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