/// <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 ModifyBlockDataRanged(ref Vector3Int posFrom, ref Vector3Int posTo, BlockData blockData, bool setBlockModified, Action <ModifyBlockContext> onModified = null) { // Make sure the values are okay. FixValues(ref posFrom.x, ref posTo.x); FixValues(ref posFrom.y, ref posTo.y); FixValues(ref posFrom.z, ref posTo.z); Vector3Int chunkPosFrom = Helpers.ContainingChunkPos(ref posFrom); Vector3Int chunkPosTo = Helpers.ContainingChunkPos(ref posTo); ModifyBlockContext context = null; if (onModified != null) { context = new ModifyBlockContext(onModified, this, 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.CHUNK_SIZE); for (int cy = chunkPosFrom.y; cy <= chunkPosTo.y; cy += Env.CHUNK_SIZE, minY = 0) { int maxY = Math.Min(posTo.y - cy, Env.CHUNK_SIZE_1); int minZ = Helpers.Mod(posFrom.z, Env.CHUNK_SIZE); for (int cz = chunkPosFrom.z; cz <= chunkPosTo.z; cz += Env.CHUNK_SIZE, minZ = 0) { int maxZ = Math.Min(posTo.z - cz, Env.CHUNK_SIZE_1); int minX = Helpers.Mod(posFrom.x, Env.CHUNK_SIZE); for (int cx = chunkPosFrom.x; cx <= chunkPosTo.x; cx += Env.CHUNK_SIZE, minX = 0) { Vector3Int chunkPos = new Vector3Int(cx, cy, cz); Chunk chunk = GetChunk(ref chunkPos); if (chunk == null) { continue; } int maxX = Math.Min(posTo.x - cx, Env.CHUNK_SIZE_1); chunk.Modify( new ModifyOpCuboid( blockData, new Vector3Int(minX, minY, minZ), new Vector3Int(maxX, maxY, maxZ), setBlockModified, context) ); } } } }
/// <summary> /// Access internal array in a circular way /// </summary> public T this[int i] { get { int pos = Helpers.Mod(i + Offset, items.Length); return(items[pos]); } set { int pos = Helpers.Mod(i + Offset, items.Length); items[pos] = value; } }
/// <summary> /// Sets the block data at given world coordinates /// </summary> /// <param name="pos">Global position of the block</param> /// <param name="blockData">A block to be placed on a given position</param> public void SetBlockData(ref Vector3Int pos, BlockData blockData) { // Transform the position into chunk coordinates Vector3Int chunkPos = Helpers.ContainingChunkPos(ref pos); Chunk chunk = GetChunk(ref chunkPos); if (chunk == null) { return; } int xx = Helpers.Mod(pos.x, Env.CHUNK_SIZE); int yy = Helpers.Mod(pos.y, Env.CHUNK_SIZE); int zz = Helpers.Mod(pos.z, Env.CHUNK_SIZE); chunk.Blocks.SetInner(Helpers.GetChunkIndex1DFrom3D(xx, yy, zz), blockData); }
public BlockData GetBlockData(Vector3Int pos) { // Transform the position into chunk coordinates Vector3Int chunkPos = Helpers.ContainingChunkPos(ref pos); Chunk chunk = GetChunk(ref chunkPos); if (chunk == null) { // Return air if the chunk that do not exist return(BlockProvider.airBlock); } int xx = Helpers.Mod(pos.x, Env.CHUNK_SIZE); int yy = Helpers.Mod(pos.y, Env.CHUNK_SIZE); int zz = Helpers.Mod(pos.z, Env.CHUNK_SIZE); return(chunk.Blocks.Get(Helpers.GetChunkIndex1DFrom3D(xx, yy, zz))); }
/// <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 SetBlockDataRangedRaw(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; } // Transform positions into chunk coordinates Vector3Int chunkPosFrom = Helpers.ContainingChunkPos(ref posFrom); Vector3Int chunkPosTo = Helpers.ContainingChunkPos(ref posTo); // Update all chunks in range int minY = Helpers.Mod(posFrom.y, Env.CHUNK_SIZE); for (int cy = chunkPosFrom.y; cy <= chunkPosTo.y; cy += Env.CHUNK_SIZE, minY = 0) { int maxY = Math.Min(posTo.y - cy, Env.CHUNK_SIZE_1); int minZ = Helpers.Mod(posFrom.z, Env.CHUNK_SIZE); for (int cz = chunkPosFrom.z; cz <= chunkPosTo.z; cz += Env.CHUNK_SIZE, minZ = 0) { int maxZ = Math.Min(posTo.z - cz, Env.CHUNK_SIZE_1); int minX = Helpers.Mod(posFrom.x, Env.CHUNK_SIZE); for (int cx = chunkPosFrom.x; cx <= chunkPosTo.x; cx += Env.CHUNK_SIZE, minX = 0) { Vector3Int chunkPos = new Vector3Int(cx, cy, cz); Chunk chunk = GetChunk(ref chunkPos); if (chunk == null) { continue; } int maxX = Math.Min(posTo.x - cx, Env.CHUNK_SIZE_1); Vector3Int from = new Vector3Int(minX, minY, minZ); Vector3Int to = new Vector3Int(maxX, maxY, maxZ); chunk.Blocks.SetRangeRaw(ref from, ref to, blockData); } } } }
public override void GenerateStructures(Chunk chunk, int layerIndex) { //if (chunk.pos.x!=-30 || chunk.pos.y!=30 || chunk.pos.z!=0) return; int minX = chunk.Pos.x; int maxX = chunk.Pos.x + Env.CHUNK_SIZE_1; int minZ = chunk.Pos.z; int maxZ = chunk.Pos.z + Env.CHUNK_SIZE_1; int structureID = 0; for (int x = minX; x <= maxX; x++) { for (int z = minZ; z <= maxZ; z++) { Vector3Int pos = new Vector3Int(x, 0, z); float chanceAtPos = Randomization.RandomPrecise(pos.GetHashCode(), 44); if (Chance > chanceAtPos) { if (Randomization.RandomPrecise(pos.Add(1, 0, 0).GetHashCode(), 44) > chanceAtPos && Randomization.RandomPrecise(pos.Add(-1, 0, 0).GetHashCode(), 44) > chanceAtPos && Randomization.RandomPrecise(pos.Add(0, 0, 1).GetHashCode(), 44) > chanceAtPos && Randomization.RandomPrecise(pos.Add(0, 0, -1).GetHashCode(), 44) > chanceAtPos) { int xx = Helpers.Mod(x, Env.CHUNK_SIZE); int zz = Helpers.Mod(z, Env.CHUNK_SIZE); int height = Helpers.FastFloor(terrainGen.GetTerrainHeightForChunk(chunk, xx, zz)); if (chunk.Pos.y <= height && chunk.Pos.y + Env.CHUNK_SIZE_1 >= height) { Vector3Int worldPos = new Vector3Int(x, height, z); structure.Build(chunk, structureID++, ref worldPos, this); } } } } } }
/// <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 ModifyBlockData(ref Vector3Int pos, BlockData blockData, bool setBlockModified, Action <ModifyBlockContext> onModified = null) { // Transform the position into chunk coordinates Vector3Int chunkPos = Helpers.ContainingChunkPos(ref pos); Chunk chunk = GetChunk(ref chunkPos); if (chunk == null) { return; } int index = Helpers.GetChunkIndex1DFrom3D( Helpers.Mod(pos.x, Env.CHUNK_SIZE), Helpers.Mod(pos.y, Env.CHUNK_SIZE), Helpers.Mod(pos.z, Env.CHUNK_SIZE) ); // 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, this, index, index, blockData, setBlockModified); } chunk.Modify(new ModifyOpBlock(blockData, index, setBlockModified, context)); }
public override void Build(Chunk chunk, int id, ref Vector3Int worldPos, TerrainLayer layer) { World world = chunk.World; int noise = Helpers.FastFloor(NoiseUtils.GetNoise(layer.Noise.Noise, worldPos.x, worldPos.y, worldPos.z, 1f, 3, 1f)); int leavesRange = MIN_CROWN_SIZE + noise; int leavesRange1 = leavesRange - 1; int trunkHeight = MIN_TRUNK_SIZE + noise; // Make the crown an ellipsoid flattened on the y axis float a2inv = 1.0f / (leavesRange * leavesRange); float b2inv = 1.0f / (leavesRange1 * leavesRange1); int x1 = worldPos.x - leavesRange; int x2 = worldPos.x + leavesRange; int y1 = worldPos.y + 1 + trunkHeight; int y2 = y1 + 1 + 2 * leavesRange1; int z1 = worldPos.z - leavesRange; int z2 = worldPos.z + leavesRange; int cx, cy, cz; int minX, minY, minZ; int maxX, maxY, maxZ; AABBInt bounds = new AABBInt(x1, worldPos.y, z1, x2, y2, z2); Vector3Int chunkPos = chunk.Pos; StructureInfo info = null; // Generate the crown Vector3Int posFrom = new Vector3Int(x1, y1, z1); Vector3Int posTo = new Vector3Int(x2, y2, z2); Vector3Int chunkPosFrom = Helpers.ContainingChunkPos(ref posFrom); Vector3Int chunkPosTo = Helpers.ContainingChunkPos(ref posTo); minY = Helpers.Mod(posFrom.y, Env.CHUNK_SIZE); for (cy = chunkPosFrom.y; cy <= chunkPosTo.y; cy += Env.CHUNK_SIZE, minY = 0) { maxY = System.Math.Min(posTo.y - cy, Env.CHUNK_SIZE_1); minZ = Helpers.Mod(posFrom.z, Env.CHUNK_SIZE); for (cz = chunkPosFrom.z; cz <= chunkPosTo.z; cz += Env.CHUNK_SIZE, minZ = 0) { maxZ = System.Math.Min(posTo.z - cz, Env.CHUNK_SIZE_1); minX = Helpers.Mod(posFrom.x, Env.CHUNK_SIZE); for (cx = chunkPosFrom.x; cx <= chunkPosTo.x; cx += Env.CHUNK_SIZE, minX = 0) { maxX = System.Math.Min(posTo.x - cx, Env.CHUNK_SIZE_1); int xOff = cx - worldPos.x; int yOff = cy - y1 - leavesRange1; int zOff = cz - worldPos.z; if (cx != chunk.Pos.x || cy != chunk.Pos.y || cz != chunk.Pos.z) { Vector3Int pos = new Vector3Int(cx, cy, cz); Vector3Int min = new Vector3Int(minX, minY, minZ); Vector3Int max = new Vector3Int(maxX, maxY, maxZ); if (info == null) { info = new StructureInfo(id, ref chunkPos, ref bounds); } world.RegisterPendingStructure(info, new StructureContextTreeCrown(id, ref pos, ref worldPos, ref min, ref max, noise)); continue; } // Actual crown construction ChunkBlocks blocks = chunk.Blocks; int index = Helpers.GetChunkIndex1DFrom3D(minX, minY, minZ); int yOffset = Env.CHUNK_SIZE_WITH_PADDING_POW_2 - (maxZ - minZ + 1) * Env.CHUNK_SIZE_WITH_PADDING; int zOffset = Env.CHUNK_SIZE_WITH_PADDING - (maxX - minX + 1); for (int y = minY; y <= maxY; ++y, index += yOffset) { for (int z = minZ; z <= maxZ; ++z, index += zOffset) { for (int x = minX; x <= maxX; ++x, ++index) { int xx = x + xOff; int yy = y + yOff; int zz = z + zOff; float _x = xx * xx * a2inv; float _y = yy * yy * b2inv; float _z = zz * zz * a2inv; if (_x + _y + _z <= 1.0f) { blocks.SetRaw(index, leaves); } } } } } } } // Generate the trunk posFrom = new Vector3Int(worldPos.x, worldPos.y, worldPos.z); posTo = new Vector3Int(worldPos.x, worldPos.y + trunkHeight, worldPos.z); chunkPosFrom = Helpers.ContainingChunkPos(ref posFrom); chunkPosTo = Helpers.ContainingChunkPos(ref posTo); cx = Helpers.MakeChunkCoordinate(worldPos.x); cz = Helpers.MakeChunkCoordinate(worldPos.z); int tx = Helpers.Mod(worldPos.x, Env.CHUNK_SIZE); int tz = Helpers.Mod(worldPos.z, Env.CHUNK_SIZE); minY = Helpers.Mod(posFrom.y, Env.CHUNK_SIZE); for (cy = chunkPosFrom.y; cy <= chunkPosTo.y; cy += Env.CHUNK_SIZE, minY = 0) { maxY = System.Math.Min(posTo.y - cy, Env.CHUNK_SIZE_1); if (cx != chunk.Pos.x || cy != chunk.Pos.y || cz != chunk.Pos.z) { Vector3Int pos = new Vector3Int(cx, cy, cz); Vector3Int min = new Vector3Int(tx, minY, tz); Vector3Int max = new Vector3Int(tx, maxY, tz); if (info == null) { info = new StructureInfo(id, ref chunkPos, ref bounds); } world.RegisterPendingStructure(info, new StructureContextTreeTrunk(id, ref pos, ref min, ref max)); continue; } // Actual trunk construction ChunkBlocks blocks = chunk.Blocks; int index = Helpers.GetChunkIndex1DFrom3D(tx, minY, tz); for (int y = minY; y <= maxY; ++y, index += Env.CHUNK_SIZE_WITH_PADDING_POW_2) { blocks.SetRaw(index, log); } } }
public int GetThreadIDFromIndex(int index) { return(Helpers.Mod(index, pools.Length)); }