/// <summary>
        /// For PvE servers, the structures inside the decayed land claim areas are removed completely.
        /// </summary>
        private static async Task <int> ServerDeleteAllStructuresAsync(
            HashSet <IStaticWorldObject> staticWorldObjects,
            Func <Task> yieldIfOutOfTime)
        {
            var world = Api.Server.World;
            var objectsDeletedCount = 0;

            var tempDestroyList = new List <IStaticWorldObject>();

            foreach (var worldObject in staticWorldObjects)
            {
                await yieldIfOutOfTime();

                var protoStaticWorldObject = worldObject.ProtoStaticWorldObject;
                if (!(protoStaticWorldObject is IProtoObjectStructure) ||
                    LandClaimSystem.SharedIsObjectInsideAnyArea(worldObject))
                {
                    continue;
                }

                world.DestroyObject(worldObject);
                objectsDeletedCount++;

                // destroy any ground containers that appeared in the released space
                foreach (var occupiedTilePosition in worldObject.OccupiedTilePositions)
                {
                    var tile = world.GetTile(occupiedTilePosition);
                    foreach (var staticObjectInPlace in tile.StaticObjects)
                    {
                        if (staticObjectInPlace.ProtoGameObject is ObjectGroundItemsContainer)
                        {
                            tempDestroyList.Add(staticObjectInPlace);
                        }
                    }
                }

                if (tempDestroyList.Count > 0)
                {
                    foreach (var staticObjectInPlace in tempDestroyList)
                    {
                        world.DestroyObject(staticObjectInPlace);
                    }

                    tempDestroyList.Clear();
                }
            }

            return(objectsDeletedCount);
        }
        private static void ServerDeleteAllStructures(
            HashSet <IStaticWorldObject> staticWorldObjects,
            out int objectsDeletedCount)
        {
            var world = Api.Server.World;

            objectsDeletedCount = 0;

            foreach (var worldObject in staticWorldObjects)
            {
                var protoStaticWorldObject = worldObject.ProtoStaticWorldObject;
                if (!(protoStaticWorldObject is IProtoObjectStructure) ||
                    LandClaimSystem.SharedIsObjectInsideAnyArea(worldObject))
                {
                    continue;
                }

                world.DestroyObject(worldObject);
                objectsDeletedCount++;
            }
        }
        /// <summary>
        /// This method will purge the land in the decayed land claim area.
        /// Please note: there is a small chance that the savegame is made right in the middle of the deletion.
        /// This way when the savegame is loaded the deletion will not resume.
        /// </summary>
        private static async void ServerPurgeStructuresInDestroyedLandClaimArea(
            IStaticWorldObject landClaimStructure,
            RectangleInt areaBounds)
        {
            await Api.Server.Core.AwaitEndOfFrame;

            var logger      = Api.Logger;
            var stopwatch   = Stopwatch.StartNew();
            var tempObjects = new HashSet <IStaticWorldObject>();
            var serverWorld = Api.Server.World;
            var serverItems = Api.Server.Items;

            var yieldIfOutOfTime = (Func <Task>)Api.Server.Core.YieldIfOutOfTime;

            for (var x = areaBounds.X; x < areaBounds.X + areaBounds.Width; x++)
            {
                for (var y = areaBounds.Y; y < areaBounds.Y + areaBounds.Height; y++)
                {
                    if (x < 0 ||
                        y < 0 ||
                        x >= ushort.MaxValue ||
                        y >= ushort.MaxValue)
                    {
                        continue;
                    }

                    var staticObjects = serverWorld.GetStaticObjects(new Vector2Ushort((ushort)x, (ushort)y));
                    foreach (var worldObject in staticObjects)
                    {
                        tempObjects.Add(worldObject);
                    }

                    await yieldIfOutOfTime();
                }
            }

            var objectsDeletedCount   = 0;
            var purgedContainersCount = 0;

            foreach (var worldObject in tempObjects)
            {
                await yieldIfOutOfTime();

                var protoStaticWorldObject = worldObject.ProtoStaticWorldObject;
                if (!(protoStaticWorldObject is IProtoObjectStructure) ||
                    LandClaimSystem.SharedIsObjectInsideAnyArea(worldObject))
                {
                    continue;
                }

                switch (protoStaticWorldObject)
                {
                case IProtoObjectCrate _:
                {
                    var privateState = worldObject.GetPrivateState <ObjectCratePrivateState>();
                    PurgeContainer(privateState.ItemsContainer);
                    break;
                }

                case IProtoObjectTradingStation _:
                {
                    var privateState = worldObject.GetPrivateState <ObjectTradingStationPrivateState>();
                    PurgeContainer(privateState.StockItemsContainer);
                    break;
                }

                case IProtoObjectBarrel _:
                {
                    var privateState = worldObject.GetPrivateState <ProtoBarrelPrivateState>();
                    privateState.LiquidAmount = 0;
                    privateState.LiquidType   = null;
                    PurgeManufacturerContainers(privateState);
                    break;
                }

                case IProtoObjectManufacturer _:
                {
                    var privateState = worldObject.GetPrivateState <ObjectManufacturerPrivateState>();
                    PurgeManufacturerContainers(privateState);
                    break;
                }
                }
            }

            if (PveSystem.ServerIsPvE)
            {
                // on PvE server, delete all the structures within the decayed land claim area
                objectsDeletedCount = await ServerDeleteAllStructuresAsync(tempObjects, yieldIfOutOfTime);
            }

            stopwatch.Stop();
            logger.Important(
                $"Land claim destroyed: {landClaimStructure}. Objects deleted: {objectsDeletedCount}. Item containers purged: {purgedContainersCount}. Time spent: {stopwatch.Elapsed.TotalMilliseconds}ms (spread across multiple frames)");

            void PurgeContainer(IItemsContainer container)
            {
                if (container is null ||
                    container.OccupiedSlotsCount == 0)
                {
                    return;
                }

                logger.Important("Purging items container in the destroyed land claim area: " + container);
                using var items = Api.Shared.WrapInTempList(container.Items);
                foreach (var item in items.AsList())
                {
                    serverItems.DestroyItem(item);
                }

                purgedContainersCount++;
            }

            void PurgeManufacturerContainers(ObjectManufacturerPrivateState privateState)
            {
                PurgeContainer(privateState.ManufacturingState?.ContainerInput);
                PurgeContainer(privateState.ManufacturingState?.ContainerOutput);
                PurgeContainer(privateState.FuelBurningState?.ContainerFuel);
            }
        }