public void RegisterMonsterSpawnedElsewhere(IMonster monster, bool notifyColonyForSiegeMode = true)
        {
            ThreadManager.AssertIsMainThread();
            ModLoader.Callbacks.OnMonsterSpawned.Invoke(monster);
            MonsterTracker.Add(monster);
            Colony goalColony = monster.OriginalGoal;

            if (goalColony != null)
            {
                IColonyDifficultySetting difficulty = goalColony.DifficultySetting;
                float cooldown = difficulty.GetZombieSpawnCooldown(goalColony);
                NextZombieSpawnTimes[goalColony] = Extensions.GetValueOrDefault(NextZombieSpawnTimes, goalColony, ServerTime.SecondsSinceStart) + cooldown;

                if (notifyColonyForSiegeMode)
                {
                    goalColony.OnZombieSpawn(true);
                }
            }
        }
        public virtual void Update()
        {
            if (World.FramesSinceInitialization < 2 || isQueuedForPathing || !ChunkQueue.CompletedInitialLoad)
            {
                return;
            }

            if (--pathCacheUpdateCounter <= 0)
            {
                pathCacheUpdateCounter = VERIFY_PATHCACHE_EVERY_X_UPDATES;
                pathCache.VerifyGoals();
            }

            QueuedSpawnResult result;

            while (QueuedSpawnResults.TryDequeue(out result))
            {
                Colony colony = result.Payload.banner?.Colony;
                if (colony == null)
                {
                    continue;
                }

                switch (result.result)
                {
                case QueuedSpawnResult.EResult.BadFailSpawn:
                case QueuedSpawnResult.EResult.FailPath:
                    NextZombieSpawnTimes[colony] = NextZombieSpawnTimes[colony] - colony.DifficultySetting.GetZombieSpawnCooldown(colony);
                    colony.OnZombieSpawn(false);
                    break;

                case QueuedSpawnResult.EResult.GoodFailSpawn:
                    colony.OnZombieSpawn(true);
                    break;

                case QueuedSpawnResult.EResult.SuccessPath:
                    if (result.Payload.recycleFrequency > 1)
                    {
                        pathCache.AddCopy(result.path);
                    }
                    SpawnZombie(result.Payload.typeToSpawn, result.path, colony, true);
                    break;
                }
            }


            Data data;

            data.ColoniesRequiringZombies = coloniesRequiringZombies;
            data.NextZombieSpawnTimes     = NextZombieSpawnTimes;
            ServerManager.BlockEntityTracker.BannerTracker.Foreach(ForeachBanner, ref data);

            for (int i = 0; i < coloniesRequiringZombies.Count; i++)
            {
                Colony colony = coloniesRequiringZombies[i];
                IColonyDifficultySetting difficulty = colony.DifficultySetting;
                float cooldown = difficulty.GetZombieSpawnCooldown(colony);

                double nextZombieSpawn = Extensions.GetValueOrDefault(NextZombieSpawnTimes, colony, ServerTime.SecondsSinceStart);

                while (true)
                {
                    QueueSpawnZombie(colony, difficulty, cooldown);
                    nextZombieSpawn += cooldown;
                    if (nextZombieSpawn > ServerTime.SecondsSinceStart || colony.InSiegeMode)
                    {
                        break;
                    }
                }

                NextZombieSpawnTimes[colony] = nextZombieSpawn;
            }

            coloniesRequiringZombies.Clear();

            if (QueuedSpawns.Count > 0)
            {
                isQueuedForPathing = true;
                ServerManager.PathingManager.QueueAction(this);
            }
        }
 public void QueueSpawnZombie(Colony colony, IColonyDifficultySetting difficulty)
 {
     QueueSpawnZombie(colony, difficulty, difficulty.GetZombieSpawnCooldown(colony));
 }