/// <summary> /// Transforms regular AutoTile input data into an output format that is optimized for /// efficient reading and updating operations. /// </summary> /// <param name="autoTileIndex"></param> /// <param name="autoTileInput"></param> /// <param name="tileData"></param> /// <param name="sourceTileCount"></param> /// <returns></returns> private TilesetAutoTileInfo TransformAutoTileData(int autoTileIndex, TilesetAutoTileInput autoTileInput, RawList <TileInfo> tileData, int sourceTileCount) { int[] stateToTileMap = new int[(int)TileConnection.All + 1]; TilesetAutoTileItem[] autoTileInfo = new TilesetAutoTileItem[sourceTileCount]; int baseTile = MathF.Clamp(autoTileInput.BaseTileIndex, 0, sourceTileCount - 1); // Initialize the tile mapping for all potential connection states with the base tile for (int conIndex = 0; conIndex < stateToTileMap.Length; conIndex++) { stateToTileMap[conIndex] = baseTile; } // Use the directly applicable tile mapping as-is int autoTileSourceTileCount = MathF.Min(autoTileInput.TileInput.Count, sourceTileCount); bool[] isStateAvailable = new bool[stateToTileMap.Length + 1]; for (int tileIndex = autoTileSourceTileCount - 1; tileIndex >= 0; tileIndex--) { TilesetAutoTileItem tileInput = autoTileInput.TileInput[tileIndex]; autoTileInfo[tileIndex] = tileInput; if (tileInput.IsAutoTile) { isStateAvailable[(int)tileInput.Neighbours] = true; stateToTileMap[(int)tileInput.Neighbours] = tileIndex; autoTileInfo[tileIndex].ConnectsToAutoTile = true; // Apply base tile information to the main tile dataset tileData.Count = Math.Max(tileData.Count, tileIndex + 1); tileData.Data[tileIndex].AutoTileLayer = autoTileIndex + 1; } } // Fill up unavailable state mappings with the closest available match for (int stateIndex = 0; stateIndex < isStateAvailable.Length; stateIndex++) { if (isStateAvailable[stateIndex]) { continue; } IReadOnlyList <TileConnection> fallbacks = AutoTileFallbackMap.GetFallback((TileConnection)stateIndex); for (int i = 0; i < fallbacks.Count; i++) { int fallbackStateIndex = (int)fallbacks[i]; if (isStateAvailable[fallbackStateIndex]) { stateToTileMap[stateIndex] = stateToTileMap[fallbackStateIndex]; break; } } } // Add the complete AutoTile info / mapping to the result data return(new TilesetAutoTileInfo( baseTile, stateToTileMap, autoTileInfo)); }
/// <summary> /// Transforms the intermediate AutoTile data into an output format that is optimized for /// efficient reading and updating operations. /// /// Requires the total number of output tiles, including generated ones, to be known. /// </summary> private void TransformAutoTileData(List <TilesetAutoTileInfo> outputData) { for (int autoTileIndex = 0; autoTileIndex < this.autoTiles.Count; autoTileIndex++) { AutoTileData data = this.autoTiles[autoTileIndex]; TilesetAutoTileItem[] tileInfo = new TilesetAutoTileItem[this.outputTileCount]; data.TileInfo.CopyTo(tileInfo, 0); outputData.Add(new TilesetAutoTileInfo( data.BaseTile, data.StateToTile, tileInfo)); } }
public EditTilesetAutoTileItemAction(Tileset tileset, TilesetAutoTileInput autoTile, int tileIndex, TilesetAutoTileItem tileInput) { if (tileset == null) throw new ArgumentNullException("tileset"); if (autoTile == null) throw new ArgumentNullException("autoTile"); this.tileset = tileset; this.autoTile = autoTile; this.tileInput = new RawList<TilesetAutoTileItem>(tileIndex + 1); this.tileInput.Count = tileIndex + 1; this.tileInput.Data[tileIndex] = tileInput; this.tileInputMask = new RawList<bool>(tileIndex + 1); this.tileInputMask.Count = tileIndex + 1; this.tileInputMask.Data[tileIndex] = true; }
/// <summary> /// Creates a new <see cref="TilesetAutoTileInfo"/> based on prepared data. /// </summary> /// <param name="baseTile">The tile index of the base tile for this AutoTile.</param> /// <param name="stateToTile"> /// An array where the item at a <see cref="TileConnection"/> index represents the tile index /// of the border tile to use in this connectivity setup. This array is not copied. If you plan /// to re-use it, pass a copy as a parameter. /// </param> public TilesetAutoTileInfo(int baseTile, int[] stateToTile, TilesetAutoTileItem[] tileInfo) { if (stateToTile == null) throw new ArgumentNullException("stateToTile"); if (tileInfo == null) throw new ArgumentNullException("tileInfo"); if (stateToTile.Length != (int)TileConnection.All + 1) { throw new ArgumentException( string.Format( "Invalid number of border tile mappings. It always has to equal {0}.", (int)TileConnection.All + 1), "borderTiles"); } this.baseTile = baseTile; this.stateToTile = stateToTile; this.tileInfo = tileInfo; }
/// <summary> /// Transforms regular AutoTile input data into an output format that is optimized for /// efficient reading and updating operations. /// </summary> /// <param name="autoTileIndex"></param> /// <param name="autoTileInput"></param> /// <param name="tileData"></param> /// <param name="sourceTileCount"></param> /// <returns></returns> private TilesetAutoTileInfo TransformAutoTileData(int autoTileIndex, TilesetAutoTileInput autoTileInput, RawList<TileInfo> tileData, int sourceTileCount) { int[] stateToTileMap = new int[(int)TileConnection.All + 1]; TilesetAutoTileItem[] autoTileInfo = new TilesetAutoTileItem[sourceTileCount]; int baseTile = MathF.Clamp(autoTileInput.BaseTileIndex, 0, sourceTileCount - 1); // Initialize the tile mapping for all potential connection states with the base tile for (int conIndex = 0; conIndex < stateToTileMap.Length; conIndex++) { stateToTileMap[conIndex] = baseTile; } // Use the directly applicable tile mapping as-is int autoTileSourceTileCount = MathF.Min(autoTileInput.TileInput.Count, sourceTileCount); bool[] isStateAvailable = new bool[stateToTileMap.Length + 1]; for (int tileIndex = autoTileSourceTileCount - 1; tileIndex >= 0; tileIndex--) { TilesetAutoTileItem tileInput = autoTileInput.TileInput[tileIndex]; autoTileInfo[tileIndex] = tileInput; if (tileInput.IsAutoTile) { isStateAvailable[(int)tileInput.Neighbours] = true; stateToTileMap[(int)tileInput.Neighbours] = tileIndex; autoTileInfo[tileIndex].ConnectsToAutoTile = true; // Apply base tile information to the main tile dataset tileData.Count = Math.Max(tileData.Count, tileIndex + 1); tileData.Data[tileIndex].AutoTileLayer = autoTileIndex + 1; } } // Fill up unavailable state mappings with the closest available match for (int stateIndex = 0; stateIndex < isStateAvailable.Length; stateIndex++) { if (isStateAvailable[stateIndex]) continue; IReadOnlyList<TileConnection> fallbacks = AutoTileFallbackMap.GetFallback((TileConnection)stateIndex); for (int i = 0; i < fallbacks.Count; i++) { int fallbackStateIndex = (int)fallbacks[i]; if (isStateAvailable[fallbackStateIndex]) { stateToTileMap[stateIndex] = stateToTileMap[fallbackStateIndex]; break; } } } // Add the complete AutoTile info / mapping to the result data return new TilesetAutoTileInfo( baseTile, stateToTileMap, autoTileInfo); }
/// <summary> /// Gathers and processes AutoTile input data into an easily modifyable intermediate format, /// while also collecting information on generated tiles and connectivity state mappings. /// </summary> /// <param name="autoTileConfig"></param> private void GatherAutoTileData(IReadOnlyList <TilesetAutoTileInput> autoTileConfig) { for (int autoTileIndex = 0; autoTileIndex < autoTileConfig.Count; autoTileIndex++) { TilesetAutoTileInput autoTileInput = autoTileConfig[autoTileIndex]; AutoTileData autoTile = new AutoTileData { BaseTile = MathF.Clamp(autoTileInput.BaseTileIndex, 0, this.inputTileCount - 1), TileInfo = this.autoTileItemPool.Rent(this.inputTileCount), StateToTile = new int[(int)TileConnection.All + 1], IsStateAvailable = new bool[(int)TileConnection.All + 1] }; autoTile.TileInfo.Count = this.inputTileCount; // Initialize the tile mapping for all potential connection states with the base tile for (int conIndex = 0; conIndex < autoTile.StateToTile.Length; conIndex++) { autoTile.StateToTile[conIndex] = autoTile.BaseTile; } // Use the directly applicable tile mapping as-is int autoTileSourceTileCount = MathF.Min(autoTileInput.TileInput.Count, this.inputTileCount); for (int tileIndex = autoTileSourceTileCount - 1; tileIndex >= 0; tileIndex--) { TilesetAutoTileItem tileInput = autoTileInput.TileInput[tileIndex]; autoTile.TileInfo[tileIndex] = tileInput; if (tileInput.IsAutoTile) { autoTile.IsStateAvailable[(int)tileInput.Neighbours] = true; autoTile.StateToTile[(int)tileInput.Neighbours] = tileIndex; autoTile.TileInfo.Data[tileIndex].ConnectsToAutoTile = true; // Apply base tile information to the main tile dataset this.tiles.Data[tileIndex].AutoTileLayer = autoTileIndex + 1; } } // Attempt to construct missing tiles of the minimum required base set from existing tiles // by using their sub-tile quadrants individually. Use a buffer for availability checks, so // we don't base generated tiles on previously generated tiles. autoTile.IsStateAvailable.CopyTo(this.autoTileStateBuffer, 0); for (int i = 0; i < AutoTileFallbackMap.BaseConnectivityTiles.Count; i++) { TileConnection connectivity = AutoTileFallbackMap.BaseConnectivityTiles[i]; if (this.autoTileStateBuffer[(int)connectivity]) { continue; } TileConnection topLeft = FindGeneratedAutoTileBase(TileQuadrant.TopLeft, connectivity, this.autoTileStateBuffer); TileConnection topRight = FindGeneratedAutoTileBase(TileQuadrant.TopRight, connectivity, this.autoTileStateBuffer); TileConnection bottomRight = FindGeneratedAutoTileBase(TileQuadrant.BottomRight, connectivity, this.autoTileStateBuffer); TileConnection bottomLeft = FindGeneratedAutoTileBase(TileQuadrant.BottomLeft, connectivity, this.autoTileStateBuffer); // Skip cases where we can't construct a full tile if (topLeft == TileConnection.None) { continue; } if (topRight == TileConnection.None) { continue; } if (bottomRight == TileConnection.None) { continue; } if (bottomLeft == TileConnection.None) { continue; } int generatedIndex = this.ScheduleGenerateTile( autoTile.BaseTile, autoTile.StateToTile[(int)topLeft], autoTile.StateToTile[(int)topRight], autoTile.StateToTile[(int)bottomRight], autoTile.StateToTile[(int)bottomLeft]); autoTile.IsStateAvailable[(int)connectivity] = true; autoTile.StateToTile[(int)connectivity] = generatedIndex; autoTile.TileInfo.Count = MathF.Max(autoTile.TileInfo.Count, generatedIndex + 1); autoTile.TileInfo.Data[generatedIndex] = autoTileInput.TileInput[autoTile.BaseTile]; autoTile.TileInfo[generatedIndex] = new TilesetAutoTileItem { IsAutoTile = true, ConnectsToAutoTile = true, Neighbours = connectivity }; } // Fill up unavailable state mappings with the closest available match for (int stateIndex = 0; stateIndex < autoTile.IsStateAvailable.Length; stateIndex++) { if (autoTile.IsStateAvailable[stateIndex]) { continue; } IReadOnlyList <TileConnection> fallbacks = AutoTileFallbackMap.GetFallback((TileConnection)stateIndex); for (int i = 0; i < fallbacks.Count; i++) { int fallbackStateIndex = (int)fallbacks[i]; if (autoTile.IsStateAvailable[fallbackStateIndex]) { autoTile.StateToTile[stateIndex] = autoTile.StateToTile[fallbackStateIndex]; break; } } } // Add the gathered info to our local working data this.autoTiles.Add(autoTile); } }