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); }
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); }
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); } }