/// <summary>
        /// Get all (already populated) areas with their objects inside the zone
        /// </summary>
        private async Task ServerFillSpawnAreasInZoneAsync(
            IServerZone zone,
            IReadOnlyDictionary <Vector2Ushort, SpawnZoneArea> areas,
            Func <Task> callbackYieldIfOutOfTime)
        {
            // this is a heavy method so we will try to yield every 100 objects to reduce the load
            const int defaultCounterToYieldValue = 100;
            var       counterToYield             = defaultCounterToYieldValue;

            // this check has a problem - it returns only objects strictly inside the zone,
            // but we also need to consider objects nearby the zone for restriction presets
            //await zone.PopulateStaticObjectsInZone(tempList, callbackYieldIfOutOfTime);

            TempListAllStaticWorldObjects.Clear();
            await Api.Server.World.GetStaticWorldObjectsAsync(TempListAllStaticWorldObjects);

            foreach (var staticObject in TempListAllStaticWorldObjects)
            {
                await YieldIfOutOfTime();

                if (staticObject.IsDestroyed)
                {
                    continue;
                }

                var position = staticObject.TilePosition;
                var area     = GetArea(position, isMobTrackingEnumeration: false);
                if (area is null)
                {
                    continue;
                }

                var protoStaticWorldObject = staticObject.ProtoStaticWorldObject;
                if (!(protoStaticWorldObject is ObjectGroundItemsContainer))
                {
                    if (protoStaticWorldObject.IsIgnoredBySpawnScripts)
                    {
                        // we don't consider padding to certain objects such as ground decals
                        // (though they still might affect spawn during the tiles check)
                        continue;
                    }

                    // create entry for regular static object
                    var preset = this.FindPreset(protoStaticWorldObject);
                    if (preset != null &&
                        preset.Density > 0 &&
                        !zone.IsContainsPosition(staticObject.TilePosition))
                    {
                        // this object is a part of the preset spawn list but it's not present in the zone
                        // don't consider this object
                        // TODO: this might cause a problem if there is a padding to this object check
                        continue;
                    }

                    area.Add(preset, position);
                    continue;
                }

                // ground container object
                var itemsContainer = ObjectGroundItemsContainer.GetPublicState(staticObject).ItemsContainer;
                foreach (var item in itemsContainer.Items)
                {
                    // create entry for each item in the ground container
                    var preset = this.FindPreset(item.ProtoItem);
                    if (preset != null &&
                        preset.Density > 0 &&
                        !zone.IsContainsPosition(staticObject.TilePosition))
                    {
                        // this object is a part of the preset spawn list but it's not present in the zone
                        // don't consider this object
                        continue;
                    }

                    area.Add(preset, position);
                }
            }

            var mobsTrackingManager = SpawnedMobsTrackingManagersStore.Get(this, zone);

            foreach (var mob in mobsTrackingManager.EnumerateAll())
            {
                await YieldIfOutOfTime();

                var position = mob.TilePosition;
                var area     = GetArea(position, isMobTrackingEnumeration: true);
                area?.Add(this.FindPreset(mob.ProtoCharacter), position);
            }

            return;

            SpawnZoneArea GetArea(Vector2Ushort tilePosition, bool isMobTrackingEnumeration)
            {
                var zoneChunkStartPosition = SpawnZoneArea.CalculateStartPosition(tilePosition);

                if (areas.TryGetValue(zoneChunkStartPosition, out var area))
                {
                    return(area);
                }

                if (isMobTrackingEnumeration)
                {
                    return(null);
                }

                return(null);
//                throw new Exception("No zone area found for " + tilePosition);

                //var newArea = new SpawnZoneArea(zoneChunkStartPosition, zoneChunk);
                //areas.Add(newArea);
                //return newArea;
            }

            Task YieldIfOutOfTime()
            {
                if (--counterToYield > 0)
                {
                    return(Task.CompletedTask);
                }

                counterToYield = defaultCounterToYieldValue;
                return(callbackYieldIfOutOfTime());
            }
        }
示例#2
0
        /// <summary>
        /// Get all (already populated) areas with their objects inside the zone
        /// </summary>
        private async Task ServerFillSpawnAreasInZoneAsync(
            IServerZone zone,
            IReadOnlyDictionary <Vector2Ushort, SpawnZoneArea> areas,
            Func <Task> callbackYieldIfOutOfTime)
        {
            // this is a heavy method so we will try to yield every 100 objects to reduce the load
            const int defaultCounterToYieldValue = 100;
            var       counterToYield             = defaultCounterToYieldValue;

            using (var tempList = Api.Shared.GetTempList <IStaticWorldObject>())
            {
                await zone.PopulateStaticObjectsInZone(tempList, callbackYieldIfOutOfTime);

                foreach (var staticObject in tempList)
                {
                    await YieldIfOutOfTime();

                    if (staticObject.IsDestroyed)
                    {
                        continue;
                    }

                    var position = staticObject.TilePosition;
                    var area     = GetArea(position, isMobTrackingEnumeration: false);
                    var protoStaticWorldObject = staticObject.ProtoStaticWorldObject;
                    if (!(protoStaticWorldObject is ObjectGroundItemsContainer))
                    {
                        if (protoStaticWorldObject.Kind == StaticObjectKind.FloorDecal)
                        {
                            // we don't consider padding to decal objects
                            // (though they still might affect spawn during tile check)
                            continue;
                        }

                        // create entry for regular static object
                        area.Add(this.FindPreset(protoStaticWorldObject), position);
                        continue;
                    }

                    // ground container object
                    var itemsContainer = ObjectGroundItemsContainer.GetPublicState(staticObject).ItemsContainer;
                    foreach (var item in itemsContainer.Items)
                    {
                        // create entry for each item in the ground container
                        area.Add(this.FindPreset(item.ProtoItem), position);
                    }
                }
            }

            var mobsTrackingManager = SpawnedMobsTrackingManagersStore.Get(this, zone);

            foreach (var mob in mobsTrackingManager.EnumerateAll())
            {
                await YieldIfOutOfTime();

                var position = mob.TilePosition;
                var area     = GetArea(position, isMobTrackingEnumeration: true);
                area?.Add(this.FindPreset(mob.ProtoCharacter), position);
            }

            return;

            SpawnZoneArea GetArea(Vector2Ushort tilePosition, bool isMobTrackingEnumeration)
            {
                var zoneChunkStartPosition = SpawnZoneArea.CalculateStartPosition(tilePosition);

                if (areas.TryGetValue(zoneChunkStartPosition, out var area))
                {
                    return(area);
                }

                if (isMobTrackingEnumeration)
                {
                    return(null);
                }

                throw new Exception("No zone area found for " + tilePosition);

                //var newArea = new SpawnZoneArea(zoneChunkStartPosition, zoneChunk);
                //areas.Add(newArea);
                //return newArea;
            }

            Task YieldIfOutOfTime()
            {
                if (--counterToYield > 0)
                {
                    return(Task.CompletedTask);
                }

                counterToYield = defaultCounterToYieldValue;
                return(callbackYieldIfOutOfTime());
            }
        }