Пример #1
0
        protected override void ClientGenerateMap(long seed, BoundsUshort worldBounds, byte startHeight)
        {
            EditorStaticObjectsRemovalHelper.ClientDelete(worldBounds);

            var map = GenerateIslandMap(seed, worldBounds.Size);

            this.ClientApplyMap(worldBounds.Offset, map, startHeight);

            EditorClientActionsHistorySystem.Purge();
        }
Пример #2
0
        public void Apply(
            long seed,
            double noiseProbability,
            BoundsUshort selectionBounds,
            IProtoTile protoTileTarget,
            IProtoTile protoTileNoise)
        {
            Api.Assert(protoTileTarget is not null, "Please select target tile proto");
            Api.Assert(protoTileNoise is not null, "Please select noise tile proto");
            Api.Assert(selectionBounds.Size.LengthSquared > 0, "Please select world area");
            Api.Assert(noiseProbability >= 0 || noiseProbability <= 1,
                       "Noise probability must be in range from 0 to 1 inclusive.");

            var random = new Random((int)seed);

            var world = Client.World;

            var tilesToModify = new List <Vector2Ushort>();

            for (var x = selectionBounds.MinX; x < selectionBounds.MaxX; x++)
            {
                for (var y = selectionBounds.MinY; y < selectionBounds.MaxY; y++)
                {
                    if (random.NextDouble() > noiseProbability)
                    {
                        // do not process this tile
                        continue;
                    }

                    // check tile type
                    var tilePosition = new Vector2Ushort(x, y);
                    var tile         = world.GetTile(tilePosition);
                    if (tile.ProtoTile == protoTileTarget)
                    {
                        tilesToModify.Add(tilePosition);
                    }
                }
            }

            if (tilesToModify.Count == 0)
            {
                return;
            }

            EditorClientActionsHistorySystem.DoAction(
                "Modify terrain tiles (noise)",
                onDo: () => tilesToModify.ChunkedInvoke(
                    5000,
                    chunk => this.CallServer(_ => _.ServerRemote_PlaceAt(chunk, protoTileNoise))),
                onUndo: () => tilesToModify.ChunkedInvoke(
                    5000,
                    chunk => this.CallServer(_ => _.ServerRemote_PlaceAt(chunk, protoTileTarget))),
                canGroupWithPreviousAction: false);
        }
Пример #3
0
        private void ClientPlaceAt(List <Vector2Ushort> tilePositions, bool isRepeat)
        {
            this.ValidateCallback(tilePositions, out var tilePosition);

            var tile            = Client.World.GetTile(tilePosition);
            var previousIsSlope = tile.IsSlope;
            var newIsSlope      = !previousIsSlope;

            EditorClientActionsHistorySystem.DoAction(
                "Toggle terrain slope",
                onDo: () => this.CallServer(_ => _.ServerRemote_PlaceAt(tilePosition, newIsSlope)),
                onUndo: () => this.CallServer(_ => _.ServerRemote_PlaceAt(tilePosition, previousIsSlope)),
                canGroupWithPreviousAction: false);
        }
Пример #4
0
        public static void ClientPaste(Vector2Ushort tilePosition)
        {
            if (lastBufferEntry is null)
            {
                return;
            }

            var bufferEntry = lastBufferEntry.Value;

            if (ClientEditorAreaSelectorHelper.Instance is not null)
            {
                NotificationSystem.ClientShowNotification(
                    title: null,
                    message:
                    "You're already in object placement mode."
                    + ObjectPlacementGuide,
                    color: NotificationColor.Neutral);
                return;
            }

            NotificationSystem.ClientShowNotification(
                title: null,
                message:
                $"{bufferEntry.SpawnList.Count} objects ready for paste!"
                + ObjectPlacementGuide,
                color: NotificationColor.Good);

            var originalTileStartX = bufferEntry.TilePositions.Min(t => t.X);
            var originalTileStartY = bufferEntry.TilePositions.Min(t => t.Y);
            var originalTileEndX   = bufferEntry.TilePositions.Max(t => t.X);
            var originalTileEndY   = bufferEntry.TilePositions.Max(t => t.Y);

            var originalSize = new Vector2Ushort((ushort)(originalTileEndX - originalTileStartX + 1),
                                                 (ushort)(originalTileEndY - originalTileStartY + 1));

            // ReSharper disable once ObjectCreationAsStatement
            new ClientEditorAreaSelectorHelper(tilePosition,
                                               originalSize,
                                               selectedCallback: PlaceSelectedCallback);

            void PlaceSelectedCallback(Vector2Ushort selectedTilePosition)
            {
                var originalStartX = bufferEntry.SpawnList.Min(t => t.TilePosition.X);
                var originalStartY = bufferEntry.SpawnList.Min(t => t.TilePosition.Y);
                var offset         = selectedTilePosition.ToVector2Int() - (originalStartX, originalStartY);

                var storageEntry = new ActionStorageEntry(
                    spawnBatches: bufferEntry.SpawnList
                    .Select(t => new SpawnObjectRequest(
                                t.Prototype,
                                t.TilePosition + offset))
                    .Batch(20000)
                    .Select(b => b.ToList())
                    .ToList());

                EditorClientActionsHistorySystem.DoAction(
                    "Paste objects",
                    onDo: async() =>
                {
                    var spawnBatches = storageEntry.SpawnBatches;
                    for (var index = 0; index < spawnBatches.Count; index++)
                    {
                        var batch             = spawnBatches[index];
                        var spawnedObjectsIds =
                            await WorldObjectsEditingSystem.Instance.CallServer(
                                _ => _.ServerRemote_SpawnObjects(batch));
                        // record spawned objects IDs so they could be removed on undo
                        var undoSpawnBatch = storageEntry.UndoSpawnBatches[index];
                        undoSpawnBatch.Clear();
                        undoSpawnBatch.AddRange(spawnedObjectsIds);
                    }

                    NotificationSystem.ClientShowNotification(
                        title: null,
                        message: spawnBatches.Sum(r => r.Count) + " object(s) pasted!",
                        color: NotificationColor.Good);
                },
                    onUndo: () =>
                {
                    var countRemoved = 0;
                    foreach (var batch in storageEntry.UndoSpawnBatches)
                    {
                        countRemoved += batch.Count;
                        WorldObjectsEditingSystem.Instance.CallServer(
                            _ => _.ServerRemote_DeleteObjects(batch));
                        // the delete batch is no longer valid
                        batch.Clear();
                    }

                    NotificationSystem.ClientShowNotification(
                        title: null,
                        message: countRemoved + " objects(s) removed.",
                        color: NotificationColor.Neutral);
                },
                    canGroupWithPreviousAction: false);
            }
        }
Пример #5
0
        private void ServerRemote_ApplyWorldSizeSliceExpansion(BoundsUshort insertedArea)
        {
            EditorClientActionsHistorySystem.Purge();

            Logger.Info("Slice-expanding the world map - inserting an area: " + insertedArea);

            var oldWorldBounds = Server.World.WorldBounds;
            var oldOffset      = oldWorldBounds.Offset;
            var oldSize        = oldWorldBounds.Size;

            var oldMap = new Tile[oldSize.X, oldSize.Y];

            for (var x = 0; x < oldSize.X; x++)
            {
                for (var y = 0; y < oldSize.Y; y++)
                {
                    oldMap[x, y] = Server.World.GetTile(x + oldOffset.X,
                                                        y + oldOffset.Y);
                }
            }

            Logger.Info("Tile height data gathered");

            var oldStaticObjects = Server.World.EditorEnumerateAllStaticObjects()
                                   .Select(o => new SpawnObjectRequest(o))
                                   .ToList();

            Logger.Info("Static objects gathered");

            // gather zones
            var oldZones = (from protoZone in Api.FindProtoEntities <IProtoZone>()
                            select new { protoZone, snapshot = protoZone.ServerZoneInstance.QuadTree.SaveQuadTree() })
                           .ToList();

            // create new world
            var newWorldBounds = CalculateNewWorldBounds(insertedArea, oldWorldBounds);

            Server.World.CreateWorld(protoTile: Api.GetProtoEntity <TileWaterSea>(),
                                     newWorldBounds);

            Logger.Info("Server zones data gathered");

            // copy old map data to the new world
            for (var x = 0; x < oldSize.X; x++)
            {
                for (var y = 0; y < oldSize.Y; y++)
                {
                    var oldData = oldMap[x, y];
                    var oldX    = (ushort)(x + oldOffset.X);
                    var oldY    = (ushort)(y + oldOffset.Y);

                    var newPosition = ConvertPosition(insertedArea, oldX, oldY);
                    Server.World.SetTileData(newPosition,
                                             oldData.ProtoTile,
                                             oldData.Height,
                                             oldData.IsSlope,
                                             oldData.IsCliff);
                }
            }

            Server.World.FixMapTilesAll();

            Logger.Info("Map slice-expansion finished");

            // restore old static objects to the new world
            foreach (var request in oldStaticObjects)
            {
                var newPosition = ConvertPosition(insertedArea, request.TilePosition.X, request.TilePosition.Y);
                Server.World.CreateStaticWorldObject(
                    request.Prototype,
                    newPosition);
            }

            Logger.Info("Static objects restored after the slice-expansion");

            // restore zones
            foreach (var oldZoneSnapshot in oldZones)
            {
                var oldQuadTree = QuadTreeNodeFactory.Create(oldZoneSnapshot.snapshot);
                var newQuadTree = oldZoneSnapshot.protoZone.ServerZoneInstance.QuadTree;
                foreach (var oldPosition in oldQuadTree)
                {
                    var newPosition = ConvertPosition(insertedArea, oldPosition.X, oldPosition.Y);
                    newQuadTree.SetFilledPosition(newPosition);
                }
            }

            Logger.Info("Server zones data restored after the slice-expansion");
        }