private void ClientPlaceAt(List <Vector2Ushort> tilePositions, IProtoTile selectedProtoTile, bool isRepeat) { var terrainHeightMode = this.settings.SelectedHeightMode.Value; var isAllowTileKindChange = this.settings.IsAllowTileKindChange; var isAllowTileProtoChangeOnlyOnTheSameHeight = this.settings.IsAllowTileProtoChangeOnlyOnTheSameHeight; var isApplyOnlyOnTheSameTileProto = this.settings.IsApplyOnlyOnTheSameTileProto; if (this.settings.IsFillMode) { if (isRepeat) { // fill doesn't support repeat return; } tilePositions = EditorTileHelper.GatherAllTilePositionsOfTheSameProtoTile( tilePositions[0], onlyOnTheSameHeight: isAllowTileProtoChangeOnlyOnTheSameHeight, ignoreCliffsAndSlopes: false); // don't change the tile heights in the fill mode terrainHeightMode = TerrainHeightMode.Keep; } var worldService = Client.World; byte targetHeight = 0; IProtoTile targetProto = null; if (isRepeat) { // use target height from previous iteration targetHeight = this.lastTargetHeight; targetProto = this.lastTargetProto; } else { if (isApplyOnlyOnTheSameTileProto) { targetProto = EditorTileHelper.CalculateMostFrequentTileProto(tilePositions); } switch (terrainHeightMode) { case TerrainHeightMode.Keep: case TerrainHeightMode.Flatten: // calculate average height for all the tiles targetHeight = EditorTileHelper.CalculateAverageHeight(tilePositions); break; case TerrainHeightMode.Increase: targetHeight = byte.MaxValue; goto case TerrainHeightMode.Decrease; case TerrainHeightMode.Decrease: // calculate target height foreach (var tilePosition in tilePositions) { var tile = worldService.GetTile(tilePosition); var calculatedNewTileHeight = this.CalculateNewTileHeight(tile, terrainHeightMode); if (terrainHeightMode == TerrainHeightMode.Increase && calculatedNewTileHeight < targetHeight || terrainHeightMode == TerrainHeightMode.Decrease && calculatedNewTileHeight > targetHeight) { targetHeight = calculatedNewTileHeight; } } break; } } this.lastTargetHeight = targetHeight; this.lastTargetProto = targetProto; var tilesToModify = new List <TerrainEditingSystem.TileModifyRequest>(); foreach (var tilePosition in tilePositions) { var tile = worldService.GetTile(tilePosition); var previousProtoTile = tile.ProtoTile; var previousTileHeight = tile.Height; var previousIsSlope = tile.IsSlope; var newProtoTile = selectedProtoTile ?? previousProtoTile; var newIsSlope = tile.IsSlope; if (isApplyOnlyOnTheSameTileProto && previousProtoTile != targetProto) { continue; } if (isAllowTileProtoChangeOnlyOnTheSameHeight && this.lastTargetHeight != previousTileHeight) { continue; } if (!isAllowTileKindChange && previousProtoTile.Kind != newProtoTile.Kind && previousProtoTile.Kind != TileKind.Placeholder) { continue; } var newTileHeight = previousTileHeight; if (terrainHeightMode == TerrainHeightMode.Flatten) { if (IsValidHeightFotTile(tile, targetHeight)) { // can set tile height to target height newTileHeight = targetHeight; } } else if (terrainHeightMode == TerrainHeightMode.Increase || terrainHeightMode == TerrainHeightMode.Decrease) { newTileHeight = this.CalculateNewTileHeight(tile, terrainHeightMode); if (newTileHeight != targetHeight) { // cannot change tile height newTileHeight = previousTileHeight; } } if (previousProtoTile == newProtoTile && newTileHeight == previousTileHeight && newIsSlope == previousIsSlope) { // nothing to change - the tile is already as desired continue; } tilesToModify.Add(new TerrainEditingSystem.TileModifyRequest( tilePosition, newProtoTile.SessionIndex, newTileHeight, newIsSlope)); } TerrainEditingSystem.ClientModifyTerrain(tilesToModify); }
private void ClientPlaceAt(List <Vector2Ushort> tilePositions, IProtoTile selectedProtoTile, bool isRepeat) { var terrainHeightMode = this.settings.SelectedHeightMode.Value; var isAllowTileKindChange = this.settings.IsAllowTileKindChange; var isAllowTileProtoChangeOnlyOnTheSameHeight = this.settings.IsAllowTileProtoChangeOnlyOnTheSameHeight; var isApplyOnlyOnTheSameTileProto = this.settings.IsApplyOnlyOnTheSameTileProto; if (this.settings.IsFillMode) { if (isRepeat) { // fill doesn't support repeat return; } tilePositions = EditorTileHelper.GatherAllTilePositionsOfTheSameProtoTile( tilePositions[0], onlyOnTheSameHeight: isAllowTileProtoChangeOnlyOnTheSameHeight, ignoreCliffsAndSlopes: false); // don't change the tile heights in the fill mode terrainHeightMode = TerrainHeightMode.Keep; } var worldService = Client.World; byte targetHeight = 0; IProtoTile targetProto = null; if (isRepeat) { // use target height from previous iteration targetHeight = this.lastTargetHeight; targetProto = this.lastTargetProto; } else { if (isApplyOnlyOnTheSameTileProto) { targetProto = EditorTileHelper.CalculateMostFrequentTileProto(tilePositions); } switch (terrainHeightMode) { case TerrainHeightMode.Keep: case TerrainHeightMode.Flatten: // calculate average height for all the tiles targetHeight = EditorTileHelper.CalculateAverageHeight(tilePositions); break; case TerrainHeightMode.Increase: targetHeight = byte.MaxValue; goto case TerrainHeightMode.Decrease; case TerrainHeightMode.Decrease: // calculate target height foreach (var tilePosition in tilePositions) { var tile = worldService.GetTile(tilePosition); var calculatedNewTileHeight = this.CalculateNewTileHeight(tile, terrainHeightMode); if (terrainHeightMode == TerrainHeightMode.Increase && calculatedNewTileHeight < targetHeight || terrainHeightMode == TerrainHeightMode.Decrease && calculatedNewTileHeight > targetHeight) { targetHeight = calculatedNewTileHeight; } } break; } } this.lastTargetHeight = targetHeight; this.lastTargetProto = targetProto; var tilesToModify = new List <List <TileModifyRequest> >(); var tilesToRevert = new List <List <TileModifyRequest> >(); // separate on groups of world chunk size var worldChunkSize = 10 * ScriptingConstants.WorldChunkSize; var groups = tilePositions .GroupBy(g => new Vector2Ushort((ushort)(g.X / worldChunkSize), (ushort)(g.Y / worldChunkSize))) .ToList(); // gather tile modifications for each group foreach (var group in groups) { var groupTilesToModify = new List <TileModifyRequest>(); var groupTilesToRevert = new List <TileModifyRequest>(); foreach (var tilePosition in group) { var tile = worldService.GetTile(tilePosition); var previousProtoTile = tile.ProtoTile; var previousTileHeight = tile.Height; var previousIsSlope = tile.IsSlope; var newProtoTile = selectedProtoTile ?? previousProtoTile; var newIsSlope = tile.IsSlope; if (isApplyOnlyOnTheSameTileProto && previousProtoTile != targetProto) { continue; } if (isAllowTileProtoChangeOnlyOnTheSameHeight && this.lastTargetHeight != previousTileHeight) { continue; } if (!isAllowTileKindChange && previousProtoTile.Kind != newProtoTile.Kind && previousProtoTile.Kind != TileKind.Placeholder) { continue; } var newTileHeight = previousTileHeight; if (terrainHeightMode == TerrainHeightMode.Flatten) { if (IsValidHeightFotTile(tile, targetHeight)) { // can set tile height to target height newTileHeight = targetHeight; } } else if (terrainHeightMode == TerrainHeightMode.Increase || terrainHeightMode == TerrainHeightMode.Decrease) { newTileHeight = this.CalculateNewTileHeight(tile, terrainHeightMode); if (newTileHeight != targetHeight) { // cannot change tile height newTileHeight = previousTileHeight; } } if (previousProtoTile == newProtoTile && newTileHeight == previousTileHeight && newIsSlope == previousIsSlope) { // nothing to change - the tile is already as desired continue; } groupTilesToModify.Add(new TileModifyRequest(tilePosition, newProtoTile.SessionIndex, newTileHeight, newIsSlope)); groupTilesToRevert.Add(new TileModifyRequest(tilePosition, previousProtoTile.SessionIndex, previousTileHeight, previousIsSlope)); } if (groupTilesToModify.Count == 0) { // nothing to modify in this group continue; } tilesToModify.Add(groupTilesToModify); tilesToRevert.Add(groupTilesToRevert); } if (tilesToModify.Count == 0) { // nothing to modify return; } EditorClientSystem.DoAction( "Modify terrain tiles", onDo: () => tilesToModify.ForEach( chunk => this.CallServer(_ => _.ServerRemote_PlaceAt(chunk))), onUndo: () => tilesToRevert.ForEach( chunk => this.CallServer(_ => _.ServerRemote_PlaceAt(chunk)))); }
private void ClientOnPaintZone(List <Vector2Ushort> tilePositions, bool isRepeat) { var selectedZoneForBrush = this.settings.SelectedZoneForBrush; if (selectedZoneForBrush is null || !selectedZoneForBrush.IsRendered) { // no zone selected for brush or zone is not visible return; } var protoZone = selectedZoneForBrush.Zone; var zoneProvider = ClientZoneProvider.Get(protoZone); if (!zoneProvider.IsDataReceived) { return; } var world = Client.World; var onlyOnTheSameHeight = this.settings.IsAllowZoneChangeOnlyOnTheSameHeight; if (this.settings.IsFillZoneMode) { if (isRepeat) { // fill doesn't support repeat return; } tilePositions = EditorTileHelper.GatherAllTilePositionsOfTheSameProtoTile( tilePositions[0], onlyOnTheSameHeight, ignoreCliffsAndSlopes: true); } this.lastUsedZoneProvider = zoneProvider; if (onlyOnTheSameHeight && !isRepeat) { // capture height when starting painting the zone this.capturedHeight = this.settings.IsFillZoneMode ? world.GetTile(tilePositions[0]).Height : EditorTileHelper.CalculateAverageHeight(tilePositions); } var onlyOnTheSameTileProto = this.settings.IsAllowZoneChangeOnlyOnTheSameTileProto; if (onlyOnTheSameTileProto && !isRepeat) { // capture tile proto when starting painting the zone this.capturedTileProto = this.settings.IsFillZoneMode ? world.GetTile(tilePositions[0]).ProtoTile : EditorTileHelper.CalculateMostFrequentTileProto(tilePositions); } // determine the mode - adding points to zone or removing them var isAddMode = ClientInputManager.IsButtonHeld(GameButton.ActionUseCurrentItem, evenIfHandled: true) || ClientInputManager.IsButtonUp(GameButton.ActionUseCurrentItem, evenIfHandled: true); if (isAddMode) { // remove points which are already added to the zone tilePositions.RemoveAll(tilePosition => zoneProvider.IsFilledPosition(tilePosition)); } else { // remove points which are not presented in the zone tilePositions.RemoveAll(tilePosition => !zoneProvider.IsFilledPosition(tilePosition)); } if (tilePositions.Count == 0) { // nothing to add/remove return; } if (onlyOnTheSameHeight) { // remove tiles with different height tilePositions.RemoveAll( tilePosition => { var tile = world.GetTile(tilePosition); return(tile.Height != this.capturedHeight // also do not allow painting on cliffs and slopes || tile.IsCliff || tile.IsSlope); }); if (tilePositions.Count == 0) { // nothing to add/remove return; } } if (onlyOnTheSameTileProto) { // remove tiles with different proto var worldService = Client.World; tilePositions.RemoveAll( tilePosition => worldService.GetTile(tilePosition).ProtoTile != this.capturedTileProto); if (tilePositions.Count == 0) { // nothing to add/remove return; } } foreach (var tilePosition in tilePositions) { if (isAddMode) { // add point to the zone zoneProvider.SetFilledPosition(tilePosition); } else { // remove point from the zone zoneProvider.ResetFilledPosition(tilePosition); } } this.lastUsedZoneProvider.ApplyClientChanges(forcePushChangesImmediately: tilePositions.Count > 10000); }