/// <summary> /// Sets the block data at given world coordinates, updates the chunk and its /// neighbors if the Update chunk flag is true or not set. /// </summary> /// <param name="pos">Global position of the block</param> /// <param name="blockData">The block be placed</param> /// <param name="setBlockModified">Set to true to mark chunk data as modified</param> /// <param name="onModified">Action to perform once the operation finished</param> public void Modify(ref Vector3Int pos, BlockData blockData, bool setBlockModified, Action <ModifyBlockContext> onModified = null) { Vector3Int chunkPos = Chunk.ContainingChunkPos(ref pos); Chunk chunk = world.chunks.Get(ref chunkPos); if (chunk == null) { return; } Vector3Int blockPos = new Vector3Int( Helpers.Mod(pos.x, Env.ChunkSize), Helpers.Mod(pos.y, Env.ChunkSize), Helpers.Mod(pos.z, Env.ChunkSize) ); int index = Helpers.GetChunkIndex1DFrom3D(blockPos.x, blockPos.y, blockPos.z); // Nothing for us to do if the block did not change BlockData oldBlockData = chunk.blocks.Get(index); if (oldBlockData.Type == blockData.Type) { return; } ModifyBlockContext context = null; if (onModified != null) { context = new ModifyBlockContext(onModified, world, index, index, blockData, setBlockModified); } chunk.blocks.Modify(new ModifyOpBlock(blockData, index, setBlockModified, context)); }
/// <summary> /// Queues a modification of blocks in a given range /// </summary> /// <param name="posFrom">Starting positon in local chunk coordinates</param> /// <param name="posTo">Ending position in local chunk coordinates</param> /// <param name="blockData">BlockData to place at the given location</param> /// <param name="setBlockModified">Set to true to mark chunk data as modified</param> /// <param name="onModified">Action to perform once the operation finished</param> public void ModifyRange(ref Vector3Int posFrom, ref Vector3Int posTo, BlockData blockData, bool setBlockModified, Action <ModifyBlockContext> onModified = null) { // Let's make sure that ranges are okay if (posFrom.x > posTo.x || posFrom.y > posTo.y || posFrom.z > posTo.z) { return; } Vector3Int chunkPosFrom = Chunk.ContainingChunkPos(ref posFrom); Vector3Int chunkPosTo = Chunk.ContainingChunkPos(ref posTo); ModifyBlockContext context = null; if (onModified != null) { context = new ModifyBlockContext(onModified, world, Helpers.GetChunkIndex1DFrom3D(posFrom.x, posFrom.y, posFrom.z), Helpers.GetChunkIndex1DFrom3D(posTo.x, posTo.y, posTo.z), blockData, setBlockModified); } // Update all chunks in range int minY = Helpers.Mod(posFrom.y, Env.ChunkSize); for (int cy = chunkPosFrom.y; cy <= chunkPosTo.y; cy += Env.ChunkSize, minY = 0) { int maxY = Math.Min(posTo.y - cy, Env.ChunkSize1); int minZ = Helpers.Mod(posFrom.z, Env.ChunkSize); for (int cz = chunkPosFrom.z; cz <= chunkPosTo.z; cz += Env.ChunkSize, minZ = 0) { int maxZ = Math.Min(posTo.z - cz, Env.ChunkSize1); int minX = Helpers.Mod(posFrom.x, Env.ChunkSize); for (int cx = chunkPosFrom.x; cx <= chunkPosTo.x; cx += Env.ChunkSize, minX = 0) { Vector3Int chunkPos = new Vector3Int(cx, cy, cz); Chunk chunk = world.chunks.Get(ref chunkPos); if (chunk == null) { continue; } int maxX = Math.Min(posTo.x - cx, Env.ChunkSize1); chunk.blocks.Modify( new ModifyOpCuboid( blockData, new Vector3Int(minX, minY, minZ), new Vector3Int(maxX, maxY, maxZ), setBlockModified, context) ); } } } }
public bool Set(ref Vector3Int pos, Chunk chunk) { Assert.IsTrue(Helpers.IsMainThread); Vector3Int p = Chunk.ContainingChunkPos(ref pos); // Let's keep it within allowed world bounds if (!world.IsCoordInsideWorld(ref p)) { return(false); } chunks[p] = chunk; return(true); }
/// <summary> Returns the chunk at the given position </summary> /// <param name="pos">Position of the chunk in the world coordinates</param> /// <returns>The chunk that contains the given block position or null if there is none</returns> public Chunk Get(ref Vector3Int pos) { Vector3Int p = Chunk.ContainingChunkPos(ref pos); // If we previously searched for this chunk there is no need to look it up again /*if (p == lastChunkPos && lastChunk != null) * return lastChunk; * * lastChunkPos = p;*/ Chunk containerChunk; chunks.TryGetValue(p, out containerChunk); return(containerChunk); }
/// <summary> /// Sets blocks to a given value in a given range. It does not perform any logic. It simply sets the blocks. /// Use this function only when generating the terrain or structures. /// </summary> /// <param name="posFrom">Starting position in local chunk coordinates</param> /// <param name="posTo">Ending position in local chunk coordinates</param> /// <param name="blockData">A block to be placed on a given position</param> public void SetRangeRaw(ref Vector3Int posFrom, ref Vector3Int posTo, BlockData blockData) { // Let's make sure that ranges are okay if (posFrom.x > posTo.x || posFrom.y > posTo.y || posFrom.z > posTo.z) { return; } Vector3Int chunkPosFrom = Chunk.ContainingChunkPos(ref posFrom); Vector3Int chunkPosTo = Chunk.ContainingChunkPos(ref posTo); // Update all chunks in range int minY = Helpers.Mod(posFrom.y, Env.ChunkSize); for (int cy = chunkPosFrom.y; cy <= chunkPosTo.y; cy += Env.ChunkSize, minY = 0) { int maxY = Math.Min(posTo.y - cy, Env.ChunkSize1); int minZ = Helpers.Mod(posFrom.z, Env.ChunkSize); for (int cz = chunkPosFrom.z; cz <= chunkPosTo.z; cz += Env.ChunkSize, minZ = 0) { int maxZ = Math.Min(posTo.z - cz, Env.ChunkSize1); int minX = Helpers.Mod(posFrom.x, Env.ChunkSize); for (int cx = chunkPosFrom.x; cx <= chunkPosTo.x; cx += Env.ChunkSize, minX = 0) { Vector3Int chunkPos = new Vector3Int(cx, cy, cz); Chunk chunk = world.chunks.Get(ref chunkPos); if (chunk == null) { continue; } int maxX = Math.Min(posTo.x - cx, Env.ChunkSize1); Vector3Int from = new Vector3Int(minX, minY, minZ); Vector3Int to = new Vector3Int(maxX, maxY, maxZ); chunk.blocks.SetRangeRaw(ref from, ref to, blockData); } } } }
/// <summary>Instantiates a new chunk at a given position. If the chunk already exists, it returns it</summary> /// <param name="pos">Position to create this chunk on in the world coordinates.</param> /// <param name="chunk">Chunk at a given world position</param> /// <returns>True if a new chunk was created. False otherwise</returns> public bool CreateOrGetChunk(ref Vector3Int pos, out Chunk chunk) { Assert.IsTrue(Helpers.IsMainThread); Vector3Int p = Chunk.ContainingChunkPos(ref pos); // Let's keep it within allowed world bounds if (!world.IsCoordInsideWorld(ref p)) { chunk = null; return(false); } /*// If we previously searched for this chunk there is no need to look it up again * if (pos==lastChunkPos && lastChunk!=null) * { * chunk = lastChunk; * return false; * } * * lastChunkPos = pos;*/ // Don't recreate the chunk if it already exists chunk = Get(ref p); if (chunk != null) { return(false); } // Create a new chunk chunk = Chunk.CreateChunk(world, p); lock (chunks) { chunks.Add(p, chunk); } return(true); }