예제 #1
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);
        }
예제 #2
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);
        }
예제 #3
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);
            }
        }