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); }
/// <summary> /// Returns true if the location is used for the player corpses. /// </summary> public static bool IsCorpseIsland(Vector2Ushort chunkPosition, BoundsUshort worldBounds) { if (Api.IsEditor) { return(false); } var chunkPositionX = chunkPosition.X - worldBounds.Offset.X; var chunkPositionY = chunkPosition.Y - worldBounds.Offset.Y; // bottom right corner is the corpse island return(chunkPositionX > worldBounds.Size.X - ScriptingConstants.WorldChunkSize * 6 && chunkPositionY < ScriptingConstants.WorldChunkSize * 6); }
private static BoundsUshort CalculateNewWorldBounds(BoundsUshort locationBounds, BoundsUshort oldWorldBounds) { var newSize = oldWorldBounds.Size.ToVector2Int() + locationBounds.Size.ToVector2Int(); var newMaxPosition = oldWorldBounds.Offset.ToVector2Int() + newSize; if (newMaxPosition.X > ushort.MaxValue || newMaxPosition.Y > ushort.MaxValue) { throw new Exception( $"Max world size exceeded: please ensure that the world size is not higher than {ushort.MaxValue}x{ushort.MaxValue} (including the world offset)"); } return(new BoundsUshort(oldWorldBounds.Offset, newSize.ToVector2Ushort())); }
public void ClientGenerate(long seed, BoundsUshort worldBounds, byte startHeight) { DialogWindow.ShowDialog( "Generate", new TextBlock() { Text = "Selected world part will be DELETED!" + Environment.NewLine + "There is NO undo for this action. Are you sure?", TextAlignment = TextAlignment.Center }, okAction: () => this.ClientGenerateMap(seed, worldBounds, startHeight), focusOnCancelButton: true, hideCancelButton: false); }
private static Vector2Ushort ConvertPosition( BoundsUshort insertedArea, ushort oldX, ushort oldY) { var newX = oldX < insertedArea.Offset.X ? oldX : (ushort)(oldX + insertedArea.Size.X); var newY = oldY <= insertedArea.Offset.Y ? oldY : (ushort)(oldY + insertedArea.Size.Y); var newPosition = new Vector2Ushort(newX, newY); return(newPosition); }
private void ClientApplyWorldSizeSliceExpansion() { var location = this.settingsViewModel.ViewModelSelectWorldSizeSliceExpansionLocation; var insertedArea = new BoundsUshort(new Vector2Ushort(location.OffsetX, location.OffsetY), new Vector2Ushort(location.SizeX, location.SizeY)); if (insertedArea.Size == Vector2Ushort.Zero) { NotificationSystem.ClientShowNotification("Please enter the size of expansion", color: NotificationColor.Bad); return; } if (insertedArea.Size.X % ScriptingConstants.WorldChunkSize != 0 || insertedArea.Size.Y % ScriptingConstants.WorldChunkSize != 0) { NotificationSystem.ClientShowNotification( $"Please ensure that the size of expansion can be divided on the world chunk size ({ScriptingConstants.WorldChunkSize}) without the remainder", color: NotificationColor.Bad); return; } this.CallServer(_ => _.ServerRemote_ApplyWorldSizeSliceExpansion(insertedArea)); }
private void ServerRemote_ApplyWorldSizeSliceExpansion(BoundsUshort insertedArea) { 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 EditorStaticObjectsRemovalHelper.RestoreObjectRequest(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"); }
protected abstract void ClientGenerateMap(long seed, BoundsUshort worldBounds, byte startHeight);
public override void Update(double deltaTime) { this.time += deltaTime; if (this.time > this.durationRocketAnimation) { this.Destroy(); return; } var progress = this.time / this.durationRocketAnimation; if (this.time < 0) { progress = 0; } // apply sine easy-in 1 - cos((x * PI) / 2) progress = ApplySineEasyIn(progress); this.lastProgress = progress; var lightProgress = Math.Min(Math.Max(this.time - LightFadeInDelay, 0) / LightFadeInDuration, 1); var rocketOffsetY = progress * RocketLaunchFinalOffsetY; this.rocketRenderer.PositionOffset = this.defaultRocketRendererPositionOffset + (0, rocketOffsetY); this.rocketRenderer.DrawOrderOffsetY = this.defaultRocketRendererDrawOrderOffsetY - rocketOffsetY; this.rocketRenderer.CustomTextureBounds = new BoundsUshort( Vector2Ushort.Zero, (RocketTextureCutSize.X, (ushort)(RocketTextureCutSize.Y + rocketOffsetY * ScriptingConstants.TileSizeRealPixels))); for (var index = 0; index < this.fireAnimators.Length; index++) { var fireOffset = RocketFireOffsets[index]; var fireRenderer = this.fireAnimators[index].SpriteRenderer; fireRenderer.PositionOffset = this.rocketRenderer.PositionOffset + fireOffset; fireRenderer.DrawOrderOffsetY = this.rocketRenderer.DrawOrderOffsetY - fireOffset.Y; var cutProgress = MathHelper.Clamp((rocketOffsetY + fireOffset.Y + FireRendererTextureCutOffset) / (FireRendererTextureCutSize.Y / 256.0), 0, 1); fireRenderer.CustomTextureBounds = new BoundsUshort( Vector2Ushort.Zero, (FireRendererTextureCutSize.X, (ushort)(FireRendererTextureCutSize.Y * cutProgress))); var lightOffset = RocketLightOffsets[index]; var lightRenderer = this.lightRenderers[index]; lightRenderer.PositionOffset = this.rocketRenderer.PositionOffset + lightOffset; lightRenderer.Opacity = lightProgress; } var mastProgress = (this.time + RocketLaunchAnimationStartDelay) / MastAnimationDuration; mastProgress = MathHelper.Clamp(mastProgress, 0, 1); mastProgress = ApplySineEasyIn(mastProgress); this.mast1Renderer.PositionOffset = this.defaultMast1RendererPositionOffset + (mastProgress * Mast1MaxWorldOffsetX, 0); this.mast2Renderer.PositionOffset = this.defaultMast2RendererPositionOffset + (mastProgress * Mast2MaxWorldOffsetX, 0); this.mast1Renderer.CustomTextureBounds = new BoundsUshort( Vector2Ushort.Zero, ((ushort)(Mast1TextureSize.X - Mast1MaxWorldOffsetX * mastProgress * ScriptingConstants.TileSizeRealPixels), Mast1TextureSize.Y)); this.mast2Renderer.CustomTextureBounds = new BoundsUshort( Vector2Ushort.Zero, ((ushort)(Mast2TextureSize.X - Mast2MaxWorldOffsetX * mastProgress * ScriptingConstants.TileSizeRealPixels), Mast2TextureSize.Y)); }
public static void ClientDelete(BoundsUshort worldBoundsToDeleteObjects) { var staticObjects = Client.World.GetStaticObjectsAtBounds(worldBoundsToDeleteObjects); instance.ClientDeleteInternal(staticObjects); }
private static ExtendMode CalculateExtendMode(ref Vector2Ushort position, BoundsUshort bounds) { var minX = bounds.MinX; var minY = bounds.MinY; // calculate max XY (inclusive margins) var maxX = (ushort)(bounds.MaxX - 1); var maxY = (ushort)(bounds.MaxY - 1); if (position.X == minX && position.Y == minY) { return(ExtendMode.LeftDown); } if (position.X == minX && position.Y == maxY) { return(ExtendMode.LeftUp); } if (position.X == maxX && position.Y == minY) { return(ExtendMode.RightDown); } if (position.X == maxX && position.Y == maxY) { return(ExtendMode.RightUp); } // detect which side is closest var distanceToLeft = position.X - minX; var distanceToRight = maxX - position.X; var distanceToDown = position.Y - minY; var distanceToUp = maxY - position.Y; var minDistance = Math.Min( distanceToLeft, Math.Min(distanceToUp, Math.Min(distanceToRight, distanceToDown))); if (minDistance >= 1) { return(ExtendMode.Move); } if (distanceToLeft == minDistance) { position = (minX, position.Y); return(ExtendMode.Left); } if (distanceToRight == minDistance) { position = (maxX, position.Y); return(ExtendMode.Right); } if (distanceToUp == minDistance) { position = (position.X, maxY); return(ExtendMode.Up); } if (distanceToDown == minDistance) { position = (position.X, minY); return(ExtendMode.Down); } throw new Exception("Impossible"); }
public static void ClientCopy(BoundsUshort worldBoundsToCopyObjects) { var staticObjects = Api.Client.World.GetStaticObjectsAtBounds(worldBoundsToCopyObjects); ClientCopyInternal(staticObjects); }
private static void ClientCopyCallback(BoundsUshort bounds) { EditorTerrainCopyPasteHelper.ClientCopy(bounds); }