예제 #1
0
        private void SpawnBot(SpawnInfo spawnInfo, MyPlanet planet, MyPlanetAnimalSpawnInfo animalSpawnInfo)
        {
            PlanetAIInfo planetInfo = null;

            if (!m_planets.TryGetValue(planet.EntityId, out planetInfo))
            {
                Debug.Assert(false, "Could not get planet info!");
                return;
            }

            if (planetInfo.BotNumber >= MAX_BOTS_PER_PLANET)
            {
                return;
            }

            Debug.Assert(animalSpawnInfo != null);
            double   spawnDistMin     = animalSpawnInfo.SpawnDistMin;
            double   spawnDistMax     = animalSpawnInfo.SpawnDistMax;
            Vector3D center           = spawnInfo.Position;
            Vector3D planetGravityVec = MyGravityProviderSystem.CalculateNaturalGravityInPoint(center);

            //GR: if gravity is zero provide a random Vector to normalize
            if (planetGravityVec == Vector3D.Zero)
            {
                planetGravityVec = Vector3D.Up;
            }
            planetGravityVec.Normalize();
            Vector3D planetTangent   = Vector3D.CalculatePerpendicularVector(planetGravityVec);
            Vector3D planetBitangent = Vector3D.Cross(planetGravityVec, planetTangent);

            planetTangent.Normalize();
            planetBitangent.Normalize();
            Vector3D spawnPos = MyUtils.GetRandomDiscPosition(ref center, spawnDistMin, spawnDistMax, ref planetTangent, ref planetBitangent);

            spawnPos = planet.GetClosestSurfacePointGlobal(ref spawnPos);
            Vector3D?spawnPosCorrected = MyEntities.FindFreePlace(spawnPos, 2.0f);

            if (spawnPosCorrected.HasValue)
            {
                spawnPos = spawnPosCorrected.Value;
            }

            planet.CorrectSpawnLocation(ref spawnPos, 2.0f);

            MyAgentDefinition botBehavior = GetAnimalDefinition(animalSpawnInfo) as MyAgentDefinition;

            if (botBehavior != null)
            {
                if (botBehavior.Id.SubtypeName == Wolf_SUBTYPE_ID && MySession.Static.EnableWolfs)
                {
                    MyAIComponent.Static.SpawnNewBot(botBehavior, spawnPos);
                }
                else if (botBehavior.Id.SubtypeName != Wolf_SUBTYPE_ID && MySession.Static.EnableSpiders)
                {
                    MyAIComponent.Static.SpawnNewBot(botBehavior, spawnPos);
                }
            }
        }
        public override void UpdateAfterSimulation()
        {
            base.UpdateAfterSimulation();

            if (!Sync.IsServer)
            {
                return;
            }

            if (MyDebugDrawSettings.ENABLE_DEBUG_DRAW && MyDebugDrawSettings.DEBUG_DRAW_FAUNA_COMPONENT)
            {
                DebugDraw();
            }

            ProfilerShort.Begin("MySpaceFaunaComponent.UpdateAfter");

            m_waitForUpdate--;
            if (m_waitForUpdate > 0)
            {
                return;
            }
            m_waitForUpdate = UPDATE_DELAY;

            var players = Sync.Players.GetOnlinePlayers();

            m_tmpPlayerPositions.Capacity = Math.Max(m_tmpPlayerPositions.Capacity, players.Count);
            m_tmpPlayerPositions.Clear();

            // Reset bot numbers
            foreach (var planet in m_planets)
            {
                planet.Value.BotNumber = 0;
            }

            // Update bot numbers and save player positions
            foreach (var player in players)
            {
                // Human player
                if (player.Id.SerialId == 0)
                {
                    if (player.Controller.ControlledEntity == null)
                    {
                        continue;
                    }
                    var pos = player.GetPosition();
                    m_tmpPlayerPositions.Add(pos);
                }
                // Bot
                else
                {
                    if (player.Controller.ControlledEntity == null)
                    {
                        continue;
                    }
                    var pos = player.GetPosition();

                    var planet = MyGamePruningStructure.GetClosestPlanet(pos);
                    if (planet != null)
                    {
                        PlanetAIInfo planetInfo;
                        if (m_planets.TryGetValue(planet.EntityId, out planetInfo))
                        {
                            planetInfo.BotNumber++;
                        }
                    }
                }
            }

            int currentTime = MySandboxGame.TotalGamePlayTimeInMilliseconds;

            // Spawn bots near players on planets, only if in survival/myfakes macro set
            if (MyFakes.SPAWN_SPACE_FAUNA_IN_CREATIVE)
            {
                foreach (var player in players)
                {
                    if (player.Controller.ControlledEntity == null)
                    {
                        continue;
                    }

                    var pos    = player.GetPosition();
                    var planet = MyGamePruningStructure.GetClosestPlanet(pos);
                    if (planet == null || !PlanetHasFauna(planet))
                    {
                        continue;
                    }

                    PlanetAIInfo planetInfo = null;
                    if (!m_planets.TryGetValue(planet.EntityId, out planetInfo))
                    {
                        continue;
                    }

                    // Human player - spawn spiders
                    if (player.Id.SerialId == 0)
                    {
                        // Distance to surface check
                        Vector3D toSurface = planet.GetClosestSurfacePointGlobal(ref pos) - pos;
                        if (toSurface.LengthSquared() >= PROXIMITY_DIST * PROXIMITY_DIST && planetInfo.BotNumber >= MAX_BOTS_PER_PLANET)
                        {
                            continue;
                        }

                        int spawnPointCount = 0;
                        var pointEnum       = m_spawnInfoGrid.GetPointsCloserThan(ref pos, SPHERE_SPAWN_DIST);
                        while (pointEnum.MoveNext())
                        {
                            var spawnPoint = pointEnum.Current;
                            spawnPointCount++;
                            if (spawnPoint.SpawnDone)
                            {
                                continue; // Don't take not-yet cleaned spawn info into consideration
                            }
                            if (spawnPoint.ShouldSpawn(currentTime))
                            {
                                spawnPoint.SpawnDone = true;
                                var  timeouts       = m_timeoutInfoGrid.GetPointsCloserThan(ref pos, TIMEOUT_DIST);
                                bool timeoutPresent = false;
                                while (timeouts.MoveNext())
                                {
                                    if (timeouts.Current.IsTimedOut(currentTime))
                                    {
                                        continue;
                                    }
                                    timeoutPresent = true;
                                    break;
                                }
                                if (timeoutPresent)
                                {
                                    continue;
                                }

                                var animalSpawnInfo = MySpaceBotFactory.GetDayOrNightAnimalSpawnInfo(planet, spawnPoint.Position);
                                if (animalSpawnInfo == null)
                                {
                                    continue;
                                }

                                int numBots = MyUtils.GetRandomInt(animalSpawnInfo.WaveCountMin, animalSpawnInfo.WaveCountMax);
                                for (int i = 0; i < numBots; ++i)
                                {
                                    SpawnBot(spawnPoint, planet, animalSpawnInfo);
                                }
                            }
                            else
                            {
                                spawnPoint.UpdateAbandoned(currentTime);
                            }
                        }

                        if (spawnPointCount == 0) // we dont have any spawn points near human players position
                        {
                            var spawnInfo = new SpawnInfo(pos, currentTime, planet);
                            m_spawnInfoGrid.AddPoint(ref pos, spawnInfo);
                            m_allSpawnInfos.Add(spawnInfo);
                        }
                    }
                    // Despawn bots that are too far from all players
                    else //if (player.Id.SteamId == Sync.MyId)
                    {
                        double closestDistSq = double.MaxValue;
                        foreach (Vector3D playerPosition in m_tmpPlayerPositions)
                        {
                            closestDistSq = Math.Min(Vector3D.DistanceSquared(pos, playerPosition), closestDistSq);
                        }

                        if (closestDistSq > DESPAWN_DIST * DESPAWN_DIST)
                        {
                            MyAIComponent.Static.RemoveBot(player.Id.SerialId, removeCharacter: true);
                        }
                    }
                }
            }
            m_tmpPlayerPositions.Clear();

            m_waitForClean -= UPDATE_DELAY;

            if (m_waitForClean <= 0)
            {
                MyAIComponent.Static.CleanUnusedIdentities();
                m_waitForClean = CLEAN_DELAY;

                for (int i = 0; i < m_allSpawnInfos.Count; ++i)
                {
                    var spawnInfo = m_allSpawnInfos[i];
                    if (spawnInfo.IsAbandoned(currentTime) || spawnInfo.SpawnDone)
                    {
                        m_allSpawnInfos.RemoveAtFast(i);
                        Vector3D point = spawnInfo.Position;
                        m_spawnInfoGrid.RemovePoint(ref point);
                        --i;
                    }
                }

                for (int i = 0; i < m_allTimeoutInfos.Count; ++i)
                {
                    var timeoutInfo = m_allTimeoutInfos[i];
                    if (timeoutInfo.IsTimedOut(currentTime))
                    {
                        m_allTimeoutInfos.RemoveAtFast(i);
                        Vector3D point = timeoutInfo.Position;
                        m_timeoutInfoGrid.RemovePoint(ref point);
                        --i;
                    }
                }
            }

            ProfilerShort.End();
        }