public void ApplyBlock(BlockType b, BlockCoord coord) { int x = coord.x; int y = coord.y; int z = coord.z; switch (b) { case BlockType.BRICK_X_AXIS: this.blocks[x][y][z].type = BlockType.BRICK_X_AXIS; this.blocks[x + 1][y][z].type = BlockType.BRICK_EXT; break; case BlockType.BRICK_Y_AXIS: this.blocks[x][y][z].type = BlockType.BRICK_Y_AXIS; this.blocks[x][y + 1][z].type = BlockType.BRICK_EXT; break; case BlockType.BRICK_Z_AXIS: this.blocks[x][y][z].type = BlockType.BRICK_Z_AXIS; this.blocks[x][y][z + 1].type = BlockType.BRICK_EXT; break; case BlockType.EMPTY: this.DestroyBlock(new BlockCoord(x, y, z)); break; default: break; } }
public bool BlockIsSupported(BlockType b, BlockCoord coord) { coord = this.FindSourceCoord(coord); int x = coord.x; int y = coord.y; int z = coord.z; // On the ground if (y == 0) { return(true); } // Central block could be supported if (this.blocks[x][y - 1][z].type != BlockType.EMPTY) { return(true); } // Each special shape switch (b) { case BlockType.BRICK_X_AXIS: return(this.blocks[x + 1][y - 1][z].type != BlockType.EMPTY); case BlockType.BRICK_Z_AXIS: return(this.blocks[x][y - 1][z + 1].type != BlockType.EMPTY); default: return(false); } }
public void SpawnItemAt(ref List <BlockCoord> selectedBlockCoords) { if (DoesItemSpawn() == false) { return; } int lastBlock = selectedBlockCoords.Count - 1; BlockCoord itemBlockCoord = selectedBlockCoords[lastBlock]; Block block = hexGrid.GetBlockAt(itemBlockCoord); if (matchCount >= CircularBlockThreshold) { block.SetBlockType(BlockType.Item_Circular); } else if (matchCount >= DiagonalBlockThreshold) { block.SetBlockType(BlockType.Item_Diagonal); } else if (matchCount >= VerticalBlockThreshold) { block.SetBlockType(BlockType.Item_Vertical); } selectedBlockCoords.RemoveAt(lastBlock); }
public bool IsValidPlacement(BlockType b, BlockCoord coord) { if (new Block(b).IsValidCoord(this, coord)) { return(BlockIsSupported(b, coord)); } return(false); }
/// <summary> /// Unmarks a previously marked chunk coordinate to be ticked when this chunk is loaded. /// </summary> public void UnmarkForTickUpdate(int x, int y, int z) { var coord = new BlockCoord(x, y, z); if (blockTicks.Contains(coord)) { blockTicks.Remove(coord); } }
public bool BlockIsSupported2(BlockType b, BlockCoord coord) { coord = this.FindSourceCoord(coord); int x = coord.x; int y = coord.y; int z = coord.z; // On the ground if (y == 0) { return(true); } bool main_strong = false; bool ext_strong = false; bool main_weak = false; bool ext_weak = false; bool ext_top = false; bool main_top = false; // Central block could be supported if (this.SpaceIsFilled(x, y - 1, z)) { main_strong = true; main_top = this.SpaceIsFilled(x, y + 1, z); } // Each special shape switch (b) { case BlockType.BRICK_X_AXIS: ext_strong = this.SpaceIsFilled(x + 1, y - 1, z); ext_weak |= this.SpaceIsFilled(x + 2, y, z); main_weak |= this.SpaceIsFilled(x - 1, y, z); ext_top = this.SpaceIsFilled(x + 1, y + 1, z); break; case BlockType.BRICK_Z_AXIS: ext_strong = this.SpaceIsFilled(x, y - 1, z + 1); ext_weak |= this.SpaceIsFilled(x, y, z + 2); main_weak |= this.SpaceIsFilled(x, y, z - 1); ext_top = this.SpaceIsFilled(x, y + 1, z + 1); break; case BlockType.BRICK_Y_AXIS: main_top = true; break; default: ext_strong = false; ext_weak = false; main_weak = false; break; } return((main_strong && ext_strong) || (main_strong && ext_weak) || (ext_strong && main_weak) || (main_strong && main_top) || (ext_strong && ext_top)); }
/// <summary> /// Marks the given chunk coordinate to be ticked when this chunk is loaded. /// </summary> public void MarkForTickUpdate(int x, int y, int z) { var coord = new BlockCoord(x, y, z); if (!blockTicks.Contains(coord)) { blockTicks.Add(coord); } }
// TODO: CLEAN public void DestroyBlock(BlockCoord pos) { BlockCoord coord = this.FindSourceCoord(pos); int x = coord.x; int y = coord.y; int z = coord.z; switch (this.blocks[x][y][z].type) { case BlockType.BRICK_X_AXIS: this.blocks[x][y][z].type = BlockType.EMPTY; this.blocks[x + 1][y][z].type = BlockType.EMPTY; if (y + 1 < this.blocks[0].Length && !this.BlockIsSupported(new BlockCoord(x, y + 1, z))) { this.DestroyBlock(new BlockCoord(x, y + 1, z)); } if (y + 1 < this.blocks[0].Length && !this.BlockIsSupported(new BlockCoord(x + 1, y + 1, z))) { this.DestroyBlock(new BlockCoord(x + 1, y + 1, z)); } break; case BlockType.BRICK_Y_AXIS: this.blocks[x][y][z].type = BlockType.EMPTY; this.blocks[x][y + 1][z].type = BlockType.EMPTY; if (y + 2 < this.blocks[0].Length && !this.BlockIsSupported(new BlockCoord(x, y + 2, z))) { this.DestroyBlock(new BlockCoord(x, y + 2, z)); } break; case BlockType.BRICK_Z_AXIS: this.blocks[x][y][z].type = BlockType.EMPTY; this.blocks[x][y][z + 1].type = BlockType.EMPTY; if (y + 1 < this.blocks[0].Length && !this.BlockIsSupported(new BlockCoord(x, y + 1, z))) { this.DestroyBlock(new BlockCoord(x, y + 1, z)); } if (y + 1 < this.blocks[0].Length && !this.BlockIsSupported(new BlockCoord(x, y + 1, z + 1))) { this.DestroyBlock(new BlockCoord(x, y + 1, z + 1)); } break; default: break; } }
public void SetAffectedBlocks() { var currentBlockNeighbors = baseBehaviour.neighborGrid.Coordinates[currentBlock.Coord.X, currentBlock.Coord.Y]; BlockCoord topLeft = currentBlockNeighbors[(byte)BlockDirection.TopLeft]; BlockCoord topRight = currentBlockNeighbors[(byte)BlockDirection.TopRight]; BlockCoord bottomLeft = currentBlockNeighbors[(byte)BlockDirection.BottomLeft]; BlockCoord bottomRight = currentBlockNeighbors[(byte)BlockDirection.BottomRight]; while (topLeft.IsValid) { if (baseBehaviour.hexGrid.GetBlockAt(topLeft).IsItem() == false) { baseBehaviour.selectedBlockSet.CoordList.Add(topLeft); } topLeft = baseBehaviour.neighborGrid.Coordinates[topLeft.X, topLeft.Y][(byte)BlockDirection.TopLeft]; } while (topRight.IsValid) { if (baseBehaviour.hexGrid.GetBlockAt(topRight).IsItem() == false) { baseBehaviour.selectedBlockSet.CoordList.Add(topRight); } topRight = baseBehaviour.neighborGrid.Coordinates[topRight.X, topRight.Y][(byte)BlockDirection.TopRight]; } while (bottomLeft.IsValid) { if (baseBehaviour.hexGrid.GetBlockAt(bottomLeft).IsItem() == false) { baseBehaviour.selectedBlockSet.CoordList.Add(bottomLeft); } bottomLeft = baseBehaviour.neighborGrid.Coordinates[bottomLeft.X, bottomLeft.Y][(byte)BlockDirection.BottomLeft]; } while (bottomRight.IsValid) { if (baseBehaviour.hexGrid.GetBlockAt(bottomRight).IsItem() == false) { baseBehaviour.selectedBlockSet.CoordList.Add(bottomRight); } bottomRight = baseBehaviour.neighborGrid.Coordinates[bottomRight.X, bottomRight.Y][(byte)BlockDirection.BottomRight]; } baseBehaviour.selectedBlockSet.CoordList.Add(currentBlock.Coord); }
private bool BlockIsOpaque(int x, int y, int z) { if (x < 0 || y < 0 || z < 0 || x >= Chunk.size || y >= Chunk.size || z >= Chunk.size) { var bc = new BlockCoord(x, y, z); var c = manager.Get(chunk.coord + bc.ChunkCoord); if (c == null) { Debug.LogError("ChunkMeshGenerator is missing surrounding chunks " + x + " " + y + " " + z + " -> " + bc.ChunkCoord); } return(Block.Get(c.GetBlock(bc.LocalCoord)).isOpaque); } return(Block.Get(chunk.GetBlock(x, y, z)).isOpaque); }
public void SetRequestRegion(BlockCoord min, BlockCoord max) { lock (blockRequest) { RequestRegionMin = min; RequestRegionMax = max; blockRequest.min_x = min.x; blockRequest.min_y = min.y; blockRequest.min_z = min.z; blockRequest.max_x = max.x; blockRequest.max_y = max.y; blockRequest.max_z = max.z; } }
private void AnimateForegroundFX(BlockCoord blockCoord) { if (tweeners[blockCoord.X, blockCoord.Y] == null) { tweeners[blockCoord.X, blockCoord.Y] = DOTween.To(() => fxGrid.ForegroundFXs[blockCoord.X, blockCoord.Y].localScale, x => fxGrid.ForegroundFXs[blockCoord.X, blockCoord.Y].localScale = x, Vector3.one, .15f); } tweeners[blockCoord.X, blockCoord.Y].Restart(); selectedBlockCoords.Push(blockCoord); }
public Chunk Generate(Vector3Int coord) { //Let's start with height map based generation Chunk chunk = new Chunk(coord); // Go over X and Z for (int i = 0; i < Chunk.size; ++i) { for (int j = 0; j < Chunk.size; ++j) { var elevation = ElevationAt(coord, i, j); var localHeight = Math.Min(Chunk.size, elevation - coord.y * Chunk.size); var grassOnTop = elevation - coord.y * Chunk.size <= Chunk.size; for (int k = 0; k < localHeight; ++k) { if (Noise3d(holeNoiseScale * (i + coord.x * Chunk.size), holeNoiseScale * (k + coord.y * Chunk.size), holeNoiseScale * (j + coord.z * Chunk.size)) > holeBias) { if (grassOnTop && k + 1 == localHeight) { var bcoord = new BlockCoord(); bcoord.ChunkCoord = coord; bcoord.LocalCoord = new Vector3Int(i, k, j); var randomization = noiseGenerator.Noise3dInterpolated(i, j, k) * snowBiasRandomization; if (elevation >= snowBias + randomization) { chunk.SetBlock(i, k, j, (byte)Block.Type.Snow); } else { chunk.SetBlock(i, k, j, (byte)Block.Type.Grass); } } else if (grassOnTop && k + 3 >= localHeight) { chunk.SetBlock(i, k, j, (byte)Block.Type.Dirt); } else { chunk.SetBlock(i, k, j, (byte)Block.Type.Stone); } } } } } return(chunk); }
///<summary>Gets the tile entity for the block at the given chunk coordinate (if available).</summary> public TileEntity GetTileEntity(int x, int y, int z) { if (tileEntities == null) { return(null); } var c = new BlockCoord(x, y, z); if (tileEntities.ContainsKey(c)) { return(tileEntities[c]); } else { return(null); } }
private void DeleteRandomBlock() { for (int i = 0; i < MAX_MUTATE_SEARCH_ITERS; i++) { int x = rng.Next(0, this.blocks.Length); int y = rng.Next(0, this.blocks[0].Length); int z = rng.Next(0, this.blocks[0][0].Length); BlockCoord coord = new BlockCoord(x, y, z); coord = this.FindSourceCoord(coord); x = coord.x; y = coord.y; z = coord.z; if (this.blocks[x][y][z].type != BlockType.EMPTY) { this.DestroyBlock(coord); break; } } }
public BlockCoord FindSourceCoord(BlockCoord coord) { BlockCoord new_coord = new BlockCoord(coord); if (blocks[coord.x][coord.y][coord.z].type == BlockType.BRICK_EXT) { if (coord.x > 0 && this.blocks[coord.x - 1][coord.y][coord.z].type == BlockType.BRICK_X_AXIS) { new_coord.x--; } else if (coord.y > 0 && this.blocks[coord.x][coord.y - 1][coord.z].type == BlockType.BRICK_Y_AXIS) { new_coord.y--; } else if (coord.z > 0) { new_coord.z--; } } return(new_coord); }
// TODO: CLEAN public BlockType FindValidBlock(BlockCoord coord) { int x = coord.x; int y = coord.y; int z = coord.z; List <BlockType> possible = new List <BlockType>(); possible.Add(BlockType.EMPTY); // TODO: move this logic into the block class and iterate through all blocks if (this.blocks[x][y][z].type != BlockType.EMPTY) { return(this.blocks[x][y][z].type); } foreach (BlockType b in System.Enum.GetValues(typeof(BlockType)).Cast <BlockType>()) { if (this.IsValidPlacement(b, coord)) { possible.Add(b); } } return(possible[rng.Next(0, possible.Count)]); }
// Checks if a block is inside bounds and is not intersecting any other blocks. public bool IsValidCoord(Blueprint blueprint, BlockCoord coord) { int x = coord.x; int y = coord.y; int z = coord.z; switch (this.type) { case BlockType.EMPTY: return(true); // ------ Basic Bricks ------- case BlockType.BRICK_X_AXIS: return // Bounds check (x + 1 < blueprint.blocks.Length && // Empty space to the left blueprint.blocks[x + 1][y][z].type == BlockType.EMPTY); case BlockType.BRICK_Z_AXIS: return // Bounds check (z + 1 < blueprint.blocks[0][0].Length && // Empty space to the left blueprint.blocks[x][y][z + 1].type == BlockType.EMPTY); case BlockType.BRICK_Y_AXIS: return // Bounds check (y + 1 < blueprint.blocks[0].Length && // Empty space up blueprint.blocks[x][y + 1][z].type == BlockType.EMPTY); default: return(false); } }
// Different Private Mutation Functions private void AddRandomBlock() { for (int i = 0; i < MAX_MUTATE_SEARCH_ITERS; i++) { int x = rng.Next(0, this.blocks.Length); int y = rng.Next(0, this.blocks[0].Length); int z = rng.Next(0, this.blocks[0][0].Length); BlockCoord coord = new BlockCoord(x, y, z); coord = this.FindSourceCoord(coord); x = coord.x; y = coord.y; z = coord.z; if (this.blocks[x][y][z].type == BlockType.EMPTY) { BlockType possible = this.FindValidBlock(new BlockCoord(x, y, z)); if (possible != BlockType.EMPTY) { this.ApplyBlock(possible, new BlockCoord(x, y, z)); break; } } } }
public void SetRequestRegion(BlockCoord min, BlockCoord max) { requestRegion.Set(new BlockCoord.Range(min, max)); }
public MapDataStore(BlockCoord block) : this(block.ToDFCoord(), BLOCK_SIZE) { }
public void CopySliceTo(BlockCoord block, MapDataStore target) { CopySliceTo(block.ToDFCoord(), BLOCK_SIZE, target); }
public MapDataStore CopySlice(BlockCoord block) { return CopySlice(block.ToDFCoord(), BLOCK_SIZE); }
public MapDataStore CopySlice(BlockCoord block) { return(CopySlice(block.ToDFCoord(), BLOCK_SIZE)); }
private void DoWater(int x, int y, int z) { Queue <BlockKey> flowQueue = new Queue <BlockKey>(); BlockKey prikey = new BlockKey(x, y, z); flowQueue.Enqueue(prikey); List <BlockKey> outflow = TileOutflow(prikey); foreach (BlockKey outkey in outflow) { flowQueue.Enqueue(outkey); } while (flowQueue.Count > 0) { BlockKey key = flowQueue.Dequeue(); int curflow = 16; int inflow = TileInflow(key); BlockCoord tile = TranslateCoord(key.x, key.y, key.z); BlockInfo tileInfo = tile.chunk.GetInfo(tile.lx, tile.ly, tile.lz); if (tileInfo.ID == BlockInfo.StationaryWater.ID || tileInfo.ID == BlockInfo.Water.ID) { curflow = tile.chunk.GetData(tile.lx, tile.ly, tile.lz); } else if (tileInfo.BlocksFluid) { continue; } bool curFall = (curflow & (int)LiquidState.FALLING) != 0; bool inFall = (inflow & (int)LiquidState.FALLING) != 0; // We won't update from the following states if (curflow == 0 || curflow == inflow || curFall) { continue; } int newflow = curflow; // Update from inflow if necessary if (inFall) { newflow = inflow; } else if (inflow >= 7) { newflow = 16; } else { newflow = inflow + 1; } // If we haven't changed the flow, don't propagate if (newflow == curflow) { continue; } // Update flow, add or remove water tile as necessary if (newflow < 16 && curflow == 16) { // If we're overwriting lava, replace with appropriate stone type and abort propagation if (tileInfo.ID == BlockInfo.StationaryLava.ID || tileInfo.ID == BlockInfo.Lava.ID) { if ((newflow & (int)LiquidState.FALLING) != 0) { int odata = tile.chunk.GetData(tile.lx, tile.ly, tile.lz); if (odata == 0) { tile.chunk.SetID(tile.lx, tile.ly, tile.lz, BlockInfo.Obsidian.ID); } else { tile.chunk.SetID(tile.lx, tile.ly, tile.lz, BlockInfo.Cobblestone.ID); } tile.chunk.SetData(tile.lx, tile.ly, tile.lz, 0); continue; } } // Otherwise replace the tile with our water flow tile.chunk.SetID(tile.lx, tile.ly, tile.lz, BlockInfo.StationaryWater.ID); tile.chunk.SetData(tile.lx, tile.ly, tile.lz, newflow); } else if (newflow == 16) { tile.chunk.SetID(tile.lx, tile.ly, tile.lz, BlockInfo.Air.ID); tile.chunk.SetData(tile.lx, tile.ly, tile.lz, 0); } else { tile.chunk.SetData(tile.lx, tile.ly, tile.lz, newflow); } // Process outflows outflow = TileOutflow(key); foreach (BlockKey nkey in outflow) { flowQueue.Enqueue(nkey); } } }
private void DoLava(int x, int y, int z) { Queue <BlockKey> flowQueue = new Queue <BlockKey>(); BlockKey prikey = new BlockKey(x, y, z); flowQueue.Enqueue(prikey); List <BlockKey> outflow = TileOutflow(prikey); foreach (BlockKey outkey in outflow) { flowQueue.Enqueue(outkey); } while (flowQueue.Count > 0) { BlockKey key = flowQueue.Dequeue(); int curflow = 16; int inflow = TileInflow(key); BlockCoord tile = TranslateCoord(key.x, key.y, key.z); BlockInfo tileInfo = tile.chunk.GetInfo(tile.lx, tile.ly, tile.lz); if (tileInfo.ID == BlockType.STATIONARY_LAVA || tileInfo.ID == BlockType.LAVA) { curflow = tile.chunk.GetData(tile.lx, tile.ly, tile.lz); } else if (tileInfo.BlocksFluid) { continue; } bool curFall = (curflow & (int)LiquidState.FALLING) != 0; bool inFall = (inflow & (int)LiquidState.FALLING) != 0; // We won't update from the following states if (curflow == 0 || curflow == inflow || curFall) { continue; } int newflow = curflow; // Update from inflow if necessary if (inFall) { newflow = inflow; } else if (inflow >= 6) { newflow = 16; } else { newflow = inflow + 2; } // If we haven't changed the flow, don't propagate if (newflow == curflow) { continue; } // Update flow, add or remove lava tile as necessary if (newflow < 16 && curflow == 16) { // If we're overwriting water, replace with appropriate stone type and abort propagation if (tileInfo.ID == BlockType.STATIONARY_WATER || tileInfo.ID == BlockType.WATER) { if ((newflow & (int)LiquidState.FALLING) == 0) { tile.chunk.SetID(tile.lx, tile.ly, tile.lz, BlockType.COBBLESTONE); tile.chunk.SetData(tile.lx, tile.ly, tile.lz, 0); continue; } } tile.chunk.SetID(tile.lx, tile.ly, tile.lz, BlockType.STATIONARY_LAVA); tile.chunk.SetData(tile.lx, tile.ly, tile.lz, newflow); } else if (newflow == 16) { tile.chunk.SetID(tile.lx, tile.ly, tile.lz, BlockType.AIR); tile.chunk.SetData(tile.lx, tile.ly, tile.lz, 0); } else { tile.chunk.SetData(tile.lx, tile.ly, tile.lz, newflow); } // Process outflows outflow = TileOutflow(key); foreach (BlockKey nkey in outflow) { flowQueue.Enqueue(nkey); } } }
public bool BlockIsSupported(BlockCoord coord) { return(BlockIsSupported(this.blocks[coord.x][coord.y][coord.z].type, coord)); }
// ----- private List <BlockKey> TileOutflow(BlockKey key, int reach = 5) { Queue <BlockKey> searchQueue = new Queue <BlockKey>(); Queue <KeyValuePair <BlockKey, int> > traceQueue = new Queue <KeyValuePair <BlockKey, int> >(); Dictionary <BlockKey, int> markTable = new Dictionary <BlockKey, int>(); searchQueue.Enqueue(key); markTable.Add(key, 0); // Identify sinks while (searchQueue.Count > 0) { BlockKey branch = searchQueue.Dequeue(); int distance = markTable[branch]; // Ignore blocks out of range if (distance > reach) { continue; } // Ignore invalid blocks BlockCoord branchHigh = TranslateCoord(branch.x, branch.y, branch.z); if (branchHigh.chunk == null || branch.y == 0) { markTable.Remove(branch); continue; } // If we're not the magical source block... if (distance > 0) { // Ignore blocks that block fluid (and thus could not become a fluid) BlockInfo branchHighInfo = branchHigh.chunk.GetInfo(branchHigh.lx, branchHigh.ly, branchHigh.lz); if (branchHighInfo.BlocksFluid) { markTable.Remove(branch); continue; } } // If we found a hole, add as a sink, mark the sink distance. BlockCoord branchLow = TranslateCoord(branch.x, branch.y - 1, branch.z); BlockInfo branchLowInfo = branchLow.chunk.GetInfo(branchLow.lx, branchLow.ly, branchLow.lz); if (!branchLowInfo.BlocksFluid) { // If we are our own sink, return the only legal outflow if (key == branch) { List <BlockKey> ret = new List <BlockKey>(); ret.Add(new BlockKey(branch.x, branch.y - 1, branch.z)); return(ret); } reach = distance; traceQueue.Enqueue(new KeyValuePair <BlockKey, int>(branch, distance)); continue; } // Expand to neighbors if (distance < reach) { BlockKey[] keys = { new BlockKey(branch.x - 1, branch.y, branch.z), new BlockKey(branch.x + 1, branch.y, branch.z), new BlockKey(branch.x, branch.y, branch.z - 1), new BlockKey(branch.x, branch.y, branch.z + 1), }; for (int i = 0; i < 4; i++) { if (!markTable.ContainsKey(keys[i])) { searchQueue.Enqueue(keys[i]); markTable.Add(keys[i], distance + 1); } } } } // Candidate outflows are marked BlockKey[] neighbors = { new BlockKey(key.x - 1, key.y, key.z), new BlockKey(key.x + 1, key.y, key.z), new BlockKey(key.x, key.y, key.z - 1), new BlockKey(key.x, key.y, key.z + 1), }; List <BlockKey> outflow = new List <BlockKey>(); foreach (BlockKey n in neighbors) { if (markTable.ContainsKey(n)) { outflow.Add(n); } } // If there's no sinks, all neighbors are valid outflows if (traceQueue.Count == 0) { return(outflow); } // Trace back from each sink eliminating shortest path marks while (traceQueue.Count > 0) { KeyValuePair <BlockKey, int> tilekv = traceQueue.Dequeue(); BlockKey tile = tilekv.Key; int distance = tilekv.Value; markTable.Remove(tile); BlockKey[] keys = { new BlockKey(tile.x - 1, tile.y, tile.z), new BlockKey(tile.x + 1, tile.y, tile.z), new BlockKey(tile.x, tile.y, tile.z - 1), new BlockKey(tile.x, tile.y, tile.z + 1), }; for (int i = 0; i < 4; i++) { int nval; if (!markTable.TryGetValue(keys[i], out nval)) { continue; } if (nval < distance) { markTable.Remove(keys[i]); traceQueue.Enqueue(new KeyValuePair <BlockKey, int>(keys[i], nval)); } } } // Remove any candidates that are still marked foreach (BlockKey n in neighbors) { if (markTable.ContainsKey(n)) { outflow.Remove(n); } } return(outflow); }
public Vector3 OffsetBlockPosition(BlockCoord coord) => OffsetBlockPosition(coord.X, coord.Y);
public Block SetBlockAt(BlockCoord coord, Block block) => SetBlockAt(coord.X, coord.Y, block);
private int TileInflow(BlockKey key) { // Check if water is falling on us if (key.y < _ydim - 1) { BlockCoord up = TranslateCoord(key.x, key.y + 1, key.z); BlockInfo upInfo = up.chunk.GetInfo(up.lx, up.ly, up.lz); if (upInfo.State == BlockState.FLUID) { return(up.chunk.GetData(up.lx, up.ly, up.lz) | (int)LiquidState.FALLING); } } // Otherwise return the min inflow of our neighbors + step BlockKey[] keys = { new BlockKey(key.x - 1, key.y, key.z), new BlockKey(key.x + 1, key.y, key.z), new BlockKey(key.x, key.y, key.z - 1), new BlockKey(key.x, key.y, key.z + 1), }; int minFlow = 16; // XXX: Might have different neighboring fluids for (int i = 0; i < 4; i++) { BlockCoord neighbor = TranslateCoord(keys[i].x, keys[i].y, keys[i].z); if (neighbor.chunk == null) { continue; } BlockInfo neighborInfo = neighbor.chunk.GetInfo(neighbor.lx, neighbor.ly, neighbor.lz); if (neighborInfo.State == BlockState.FLUID) { int flow = neighbor.chunk.GetData(neighbor.lx, neighbor.ly, neighbor.lz); bool flowFall = (flow & (int)LiquidState.FALLING) != 0; if (flowFall) { if (keys[i].y == 0) { continue; } BlockCoord low = TranslateCoord(keys[i].x, keys[i].y - 1, keys[i].z); BlockInfo lowinfo = low.chunk.GetInfo(low.lx, low.ly, low.lz); if (lowinfo.BlocksFluid) { return(0); } continue; } if (flow < minFlow) { minFlow = flow; } } } return(minFlow); }