// On random Update spread grass to any nearby dirt blocks on the surface public override void RandomUpdate(Chunk chunk, ref Vector3Int localPos) { ChunkBlocks blocks = chunk.blocks; // Let's stay inside bounds int minX = localPos.x <= 0 ? 0 : 1; int maxX = localPos.x >= Env.ChunkSize1 ? 0 : 1; int minY = localPos.y <= 0 ? 0 : 1; int maxY = localPos.y >= Env.ChunkSize1 ? 0 : 1; int minZ = localPos.z <= 0 ? 0 : 1; int maxZ = localPos.z >= Env.ChunkSize1 ? 0 : 1; for (int y = -minY; y <= maxY; y++) { for (int z = -minZ; z <= maxZ; z++) { for (int x = -minX; x <= maxX; x++) { // There has to be dirt above our block int grassIndex = Helpers.GetChunkIndex1DFrom3D(localPos.x + x, localPos.y + y, localPos.z + z); if (!blocks.Get(grassIndex).Equals(dirt)) { continue; } // There has to be air above the dirt int airIndex = grassIndex + Env.ChunkSizePow2; if (blocks.Get(airIndex).Equals(air)) { blocks.Modify(new ModifyOpBlock(grass, grassIndex, true)); } } } } }
/// <summary> /// Fills chunk with layer data starting at startPlaceHeight and ending at endPlaceHeight /// </summary> /// <param name="chunk">Chunk filled with data</param> /// <param name="x">Position on x axis in local coordinates</param> /// <param name="z">Position on z axis in local coordinates</param> /// <param name="startPlaceHeight">Starting position on y axis in world coordinates</param> /// <param name="endPlaceHeight">Ending position on y axis in world coordinates</param> /// <param name="blockData">Block data to set</param> protected static void SetBlocks(Chunk chunk, int x, int z, int startPlaceHeight, int endPlaceHeight, BlockData blockData) { int chunkY = chunk.pos.y; int yMax = chunkY + Env.ChunkSize; if (startPlaceHeight >= yMax || endPlaceHeight < chunkY) { return; } if (endPlaceHeight < yMax) { yMax = endPlaceHeight; } int y = startPlaceHeight; if (startPlaceHeight < chunkY) { y = chunkY; } ChunkBlocks blocks = chunk.blocks; while (y < yMax) { blocks.SetRaw(Helpers.GetChunkIndex1DFrom3D(x, y - chunkY, z), blockData); ++y; } }
protected override void OnSetBlocks(ChunkBlocks blocks) { int index = Helpers.GetChunkIndex1DFrom3D(min.x, min.y, min.z); int yOffset = Env.CHUNK_SIZE_WITH_PADDING_POW_2 - (max.z - min.z + 1) * Env.CHUNK_SIZE_WITH_PADDING; int zOffset = Env.CHUNK_SIZE_WITH_PADDING - (max.x - min.x + 1); for (int y = min.y; y <= max.y; ++y, index += yOffset) { for (int z = min.z; z <= max.z; ++z, index += zOffset) { for (int x = min.x; x <= max.x; ++x, ++index) { int xx = x + offset.x; int yy = y + offset.y; int zz = z + offset.z; float _x = xx * xx * a2inv; float _y = yy * yy * b2inv; float _z = zz * zz * a2inv; if (_x + _y + _z <= 1.0f) { blocks.ProcessSetBlock(blockData, index, setBlockModified); } } } } }
public override ChunkBlocks Generate(Vector3Int coordinate, ChunkBlocks chunk, int size) { var air = Air; var iterator = chunk.GetIterator(); foreach (var coord in iterator) { var worldY = coordinate.y * size + coord.y; if (worldY > GroundHeight) { chunk.Blocks[coord.x, coord.y, coord.z] = air; } else if (worldY == GroundHeight) { if (Random.value < Probability) { chunk.Blocks[coord.x, coord.y, coord.z] = air; } else { chunk.Blocks[coord.x, coord.y, coord.z] = Top; } } else { chunk.Blocks[coord.x, coord.y, coord.z] = Default; } } return(chunk); }
public void Apply(Chunk chunk) { ChunkBlocks blocks = chunk.Blocks; OnSetBlocks(blocks); OnPostSetBlocks(blocks); }
// On random Update spread grass to any nearby dirt blocks on the surface public override void RandomUpdate(Chunk chunk, Vector3Int localPos) { ChunkBlocks blocks = chunk.blocks; int minX = localPos.x <= 0 ? 0 : 1; int maxX = localPos.x >= Env.ChunkMask ? 0 : 1; int minY = localPos.y <= 0 ? 0 : 1; int maxY = localPos.y >= Env.ChunkMask ? 0 : 1; int minZ = localPos.z <= 0 ? 0 : 1; int maxZ = localPos.z >= Env.ChunkMask ? 0 : 1; for (int x = -minX; x <= maxX; x++) { for (int y = -minY; y <= maxY; y++) { for (int z = -minZ; z <= maxZ; z++) { Vector3Int newPos = localPos.Add(x, y, z); if (!blocks.Get(newPos).Equals(dirt)) { continue; } // Let's turn air about dirt into grass if (blocks.Get(newPos.Add(0, 1, 0)).Equals(air)) { blocks.Modify(newPos, grass, true); } } } } }
protected override void OnSetBlocksRaw(ChunkBlocks blocks, ref Vector3Int from, ref Vector3Int to) { int index = Helpers.GetChunkIndex1DFrom3D(from.x, from.y, from.z); int yOffset = Env.CHUNK_SIZE_WITH_PADDING_POW_2 - (to.z - from.z + 1) * Env.CHUNK_SIZE_WITH_PADDING; int zOffset = Env.CHUNK_SIZE_WITH_PADDING - (to.x - from.x + 1); for (int y = from.y; y <= to.y; ++y, index += yOffset) { for (int z = from.z; z <= to.z; ++z, index += zOffset) { for (int x = from.x; x <= to.x; ++x, ++index) { int xx = x + offset.x; int yy = y + offset.y; int zz = z + offset.z; float _x = xx * xx * a2inv; float _y = yy * yy * b2inv; float _z = zz * zz * a2inv; if (_x + _y + _z <= 1.0f) { blocks.SetRaw(index, blockData); } } } } }
private bool ExpandZ(ChunkBlocks blocks, ref bool[] mask, Block block, int x1, int y1, int x2, int y2, ref int z2) { int sizeWithPadding = m_sideSize + Env.ChunkPadding2; int sizeWithPaddingPow2 = sizeWithPadding * sizeWithPadding; int yOffset = sizeWithPaddingPow2 - x2 + x1; int index0 = Helpers.GetChunkIndex1DFrom3D(x1, y1, z2, m_pow); // Check the quad formed by XY axes and try to expand the Z axis int index = index0; for (int y = y1; y < y2; ++y, index += yOffset) { for (int x = x1; x < x2; ++x, ++index) { if (mask[index] || !CanCreateBox(block, blocks.GetBlock(index))) { return(false); } } } // If the box can expand, mark the position as tested and expand the X axis index = index0; for (int y = y1; y < y2; ++y, index += yOffset) { for (int x = x1; x < x2; ++x, ++index) { mask[index] = true; } } ++z2; return(true); }
// On random Update spread grass to any nearby dirt blocks on the surface public override void RandomUpdate(Chunk chunk, Vector3Int localPos, Vector3Int globalPos) { ChunkBlocks blocks = chunk.blocks; WorldBlocks blocksW = chunk.world.blocks; int minX = localPos.x <= 0 ? 0 : 1; int maxX = localPos.x >= Env.ChunkMask ? 0 : 1; int minY = localPos.y <= 0 ? 0 : 1; int maxY = localPos.y >= Env.ChunkMask ? 0 : 1; int minZ = localPos.z <= 0 ? 0 : 1; int maxZ = localPos.z >= Env.ChunkMask ? 0 : 1; for (int x = -minX; x <= maxX; x++) { for (int y = -minY; y <= maxY; y++) { for (int z = -minZ; z <= maxZ; z++) { Vector3Int newPos = localPos.Add(x, y, z); if (blocks.Get(newPos).Equals(dirt) && blocksW.Get(globalPos.Add(x, y + 1, z)).Equals(air)) { blocks.Modify(newPos, grass, true); } } } } }
public static void GenerateTrunkPart(Chunk chunk, ref Vector3Int min, ref Vector3Int max) { ChunkBlocks blocks = chunk.Blocks; blocks.chunk.Modify( new ModifyOpCuboid(log, min, max, false) ); }
public bool ConsumeChanges() { ChunkBlocks blocks = Chunk.Blocks; if (!Features.UseDifferentialSerialization) { return(true); } if (Features.UseDifferentialSerialization_ForceSaveHeaders) { if (blocks.modifiedBlocks.Count <= 0) { return(true); } } else { if (blocks.modifiedBlocks.Count <= 0) { return(false); } } Dictionary <BlockPos, BlockData> blocksDictionary = new Dictionary <BlockPos, BlockData>(); // Create a map of modified blocks and their positions // TODO: Depending on the amount of changes this could become a performance bottleneck for (int i = 0; i < blocks.modifiedBlocks.Count; i++) { var pos = blocks.modifiedBlocks[i]; // Remove any existing blocks in the dictionary. They come from the existing save and are overwritten blocksDictionary.Remove(pos); blocksDictionary.Add(pos, blocks.Get(Helpers.GetChunkIndex1DFrom3D(pos.x, pos.y, pos.z))); } int cnt = blocksDictionary.Keys.Count; if (cnt > 0) { m_blocksModified = new BlockData[cnt]; m_positionsModified = new BlockPos[cnt]; int index = 0; foreach (var pair in blocksDictionary) { m_blocksModified[index] = pair.Value; m_positionsModified[index] = pair.Key; ++index; } } return(true); }
protected override void OnPostSetBlocks(ChunkBlocks blocks) { if (parentContext != null) { parentContext.ChildActionFinished(); } int x, y, z; Helpers.GetChunkIndex3DFrom1D(index, out x, out y, out z); blocks.chunk.HandleNeighbors(blockData, new Vector3Int(x, y, z)); }
public override void BuildBlock(Chunk chunk, Vector3Int localPos) { ChunkBlocks blocks = chunk.blocks; for (int d = 0; d < 6; d++) { Direction dir = DirectionUtils.Get(d); Block adjacentBlock = blocks.GetBlock(localPos.Add(dir)); if (CanBuildFaceWith(adjacentBlock, dir)) { BuildFace(chunk, localPos, dir); } } }
public static Chunk Create(ChunkBlocks blocks, Material material, int x, int y, int z, GameObject parent, Mesh mesh) { var chunk = new Chunk { Blocks = blocks, MeshMaterial = material, Mesh = mesh, Position = Voxel.Position(x, y, z) * World.SIZE }; chunk.Initialize(); chunk.gameObject.transform.SetParent(parent.transform); return(chunk); }
public override void BuildFace(Chunk chunk, Vector3[] vertices, Color32[] palette, ref BlockFace face, bool rotated) { var d = connectedMeshConfig.dataDir[(int)face.side]; var tris = d.tris; if (tris == null) { return; } var verts = d.verts; var uvs = d.uvs; var textures = d.textures; var colors = d.colors; Rect rect; ChunkBlocks blocks = chunk.blocks; RenderGeometryBatcher batcher = chunk.GeometryHandler.Batcher; Vector3Int sidePos = face.pos.Add(face.side); if (connectedMeshConfig.connectsToSolid && blocks.Get(ref sidePos).Solid) { rect = textures.GetTexture(chunk, ref face.pos, face.side); batcher.AddMeshData(face.materialID, tris, verts, colors, uvs, ref rect, face.pos); } else if (connectedMeshConfig.connectsToTypes.Length != 0) { int neighborType = blocks.Get(ref sidePos).Type; for (int i = 0; i < connectedMeshConfig.connectsToTypes.Length; i++) { if (neighborType == connectedMeshConfig.connectsToTypes[i]) { rect = textures.GetTexture(chunk, ref face.pos, face.side); batcher.AddMeshData(face.materialID, tris, verts, colors, uvs, ref rect, face.pos); break; } } } var d2 = customMeshConfig.data; rect = d2.textures.GetTexture(chunk, ref face.pos, Direction.down); batcher.AddMeshData(face.materialID, d2.tris, d2.verts, d2.colors, d2.uvs, ref rect, face.pos); }
protected override void OnSetBlocks(ChunkBlocks blocks) { int index = Helpers.GetChunkIndex1DFrom3D(min.x, min.y, min.z); int yOffset = Env.CHUNK_SIZE_WITH_PADDING_POW_2 - (max.z - min.z + 1) * Env.CHUNK_SIZE_WITH_PADDING; int zOffset = Env.CHUNK_SIZE_WITH_PADDING - (max.x - min.x + 1); for (int y = min.y; y <= max.y; ++y, index += yOffset) { for (int z = min.z; z <= max.z; ++z, index += zOffset) { for (int x = min.x; x <= max.x; ++x, ++index) { blocks.ProcessSetBlock(blockData, index, setBlockModified); } } } }
public override ChunkBlocks Generate(Vector3Int coordinate, ChunkBlocks chunk, int size) { var iterator = chunk.GetIterator(); foreach (var coord in iterator) { var x = coordinate.x * size + coord.x; var y = coordinate.y * size + coord.y; var z = coordinate.z * size + coord.z; var sample2d = MathHelper.Perlin2DSample(x, z, size, 0, Scale); var noise = Mathf.PerlinNoise(sample2d.x, sample2d.y); var terrainHeight = Mathf.FloorToInt(Height * noise) + GroundHeight; BlockType type = Substratum; if (y == terrainHeight) { type = Surface; } else if (y < terrainHeight && y > terrainHeight - 4) { type = Subsoil; } else if (y > terrainHeight) { type = Air; } else { foreach (var biomeBlock in Blocks) { if (y > biomeBlock.minHeight && y < biomeBlock.maxHeight) { var sample3d = MathHelper.Perlin3DSample(x, y, z, biomeBlock.noiseOffset, biomeBlock.scale); if (MathHelper.Get3DPerlin(sample3d.x, sample3d.y, sample3d.z) > biomeBlock.threshold) { type = biomeBlock.Type; } } } } chunk.Blocks[coord.x, coord.y, coord.z] = type; } return(chunk); }
/// <summary> /// Fills chunk with layer data starting at startPlaceHeight and ending at endPlaceHeight /// </summary> /// <param name="chunk">Chunk filled with data</param> /// <param name="x">Position on x axis in local coordinates</param> /// <param name="z">Position on z axis in local coordinates</param> /// <param name="startPlaceHeight">Starting position on y axis in world coordinates</param> /// <param name="endPlaceHeight">Ending position on y axis in world coordinates</param> /// <param name="blockData">Block data to set</param> protected static void SetBlocks(Chunk chunk, int x, int z, int startPlaceHeight, int endPlaceHeight, BlockData blockData) { int chunkY = chunk.Pos.y; int chunkYMax = chunkY + Env.ChunkSize; int y = startPlaceHeight > chunkY ? startPlaceHeight : chunkY; int yMax = endPlaceHeight < chunkYMax ? endPlaceHeight : chunkYMax; ChunkBlocks blocks = chunk.Blocks; int index = Helpers.GetChunkIndex1DFrom3D(x, y - chunkY, z); while (y++ < yMax) { blocks.SetRaw(index, blockData); index += Env.ChunkSizeWithPaddingPow2; } }
protected override void OnSetBlocksRaw(ChunkBlocks blocks, ref Vector3Int from, ref Vector3Int to) { int index = Helpers.GetChunkIndex1DFrom3D(from.x, from.y, from.z); int yOffset = Env.CHUNK_SIZE_WITH_PADDING_POW_2 - (to.z - from.z + 1) * Env.CHUNK_SIZE_WITH_PADDING; int zOffset = Env.CHUNK_SIZE_WITH_PADDING - (to.x - from.x + 1); for (int y = from.y; y <= to.y; ++y, index += yOffset) { for (int z = from.z; z <= to.z; ++z, index += zOffset) { for (int x = from.x; x <= to.x; ++x, ++index) { blocks.SetRaw(index, blockData); } } } }
protected override void OnSetBlocks(ChunkBlocks blocks) { int index = Helpers.GetChunkIndex1DFrom3D(min.x, min.y, min.z); int yOffset = Env.ChunkSizeWithPaddingPow2 - (max.z - min.z + 1) * Env.ChunkSizeWithPadding; int zOffset = Env.ChunkSizeWithPadding - (max.x - min.x + 1); for (int y = min.y; y <= max.y; ++y, index += yOffset) { for (int z = min.z; z <= max.z; ++z, index += zOffset) { for (int x = min.x; x <= max.x; ++x, ++index) { blocks.ProcessSetBlock(blockData, index, setBlockModified); } } } }
protected override void OnSetBlocksRaw(ChunkBlocks blocks, ref Vector3Int from, ref Vector3Int to) { int index = Helpers.GetChunkIndex1DFrom3D(from.x, from.y, from.z); int yOffset = Env.ChunkSizeWithPaddingPow2 - (to.z - from.z + 1) * Env.ChunkSizeWithPadding; int zOffset = Env.ChunkSizeWithPadding - (to.x - from.x + 1); for (int y = from.y; y <= to.y; ++y, index += yOffset) { for (int z = from.z; z <= to.z; ++z, index += zOffset) { for (int x = from.x; x <= to.x; ++x, ++index) { blocks.SetRaw(index, blockData); } } } }
public void Ping(Vector3Int position) { var current = generators.Get(MathHelper.Anchor(position.x, position.y, position.z, REGION)); chunkBlocks.Ping(position, radius, v => { var coord = MathHelper.Anchor(v.x, v.y, v.z, REGION); if (!generators.TryGet(ref coord, out ChunkGenerator biome)) { biome = current.Transitions[(int)(Random.value * (current.Transitions.Length))]; generators.Set(coord, biome); } var chunk = new ChunkBlocks(v.x, v.y, v.z, SIZE); var result = biome.Generate(v, chunk, SIZE); factory.Enqueue(result); return(result); });
public Rect GetTexture(Chunk chunk, ref Vector3Int localPos, Direction direction) { if (usesConnectedTextures) { ChunkBlocks blocks = chunk.blocks; int index = Helpers.GetChunkIndex1DFrom3D(localPos.x, localPos.y, localPos.z); ushort blockType = blocks.Get(index).Type; bool nw = ConnectedTextures.IsSame(blocks, index, -1, 1, direction, blockType); bool n = ConnectedTextures.IsSame(blocks, index, 0, 1, direction, blockType); bool ne = ConnectedTextures.IsSame(blocks, index, 1, 1, direction, blockType); bool w = ConnectedTextures.IsSame(blocks, index, -1, 0, direction, blockType); bool e = ConnectedTextures.IsSame(blocks, index, 1, 0, direction, blockType); bool se = ConnectedTextures.IsSame(blocks, index, 1, -1, direction, blockType); bool s = ConnectedTextures.IsSame(blocks, index, 0, -1, direction, blockType); bool sw = ConnectedTextures.IsSame(blocks, index, -1, -1, direction, blockType); return(connectedTextures[ConnectedTextures.GetTexture(n, e, s, w, nw, ne, se, sw)]); } if (textures.Count == 1) { return(textures[0]); } if (textures.Count > 1) { int hash = localPos.GetHashCode(); if (hash < 0) { hash *= -1; } float randomNumber = (hash % 100) / 100f; randomNumber *= textures.Count; return(textures[(int)randomNumber]); } Debug.LogError("There were no textures for " + textureName); return(new Rect()); }
public static void GenerateCrownPart(Chunk chunk, ref Vector3Int worldPos, ref Vector3Int min, ref Vector3Int max, int noise) { ChunkBlocks blocks = chunk.Blocks; int leavesRange = minCrownSize + noise; int leavesRange1 = leavesRange - 1; int trunkHeight = minTrunkSize + noise; // Make the crown an ellipsoid flattened on the y axis float a2inv = 1.0f / (leavesRange * leavesRange); float b2inv = 1.0f / (leavesRange1 * leavesRange1); int y1 = worldPos.y + 1 + trunkHeight; int xOff = chunk.Pos.x - worldPos.x; int yOff = chunk.Pos.y - y1 - leavesRange1; int zOff = chunk.Pos.z - worldPos.z; blocks.chunk.Modify( new ModifyOpEllipsoid(leaves, min, max, new Vector3Int(xOff, yOff, zOff), a2inv, b2inv, false) ); }
public override void BuildBlock(Chunk chunk, Vector3Int localPos) { Rect texture; RenderGeometryBatcher batcher = chunk.GeometryHandler.Batcher; ChunkBlocks blocks = chunk.blocks; for (int d = 0; d < 6; d++) { Direction dir = DirectionUtils.Get(d); if (!connectedMeshConfig.directionalTris.ContainsKey(dir)) { continue; } if (connectedMeshConfig.connectsToSolid && blocks.GetBlock(localPos + dir).IsSolid(DirectionUtils.Opposite(dir))) { texture = connectedMeshConfig.texture.GetTexture(chunk, localPos, dir); batcher.AddMeshData(connectedMeshConfig.directionalTris[dir], connectedMeshConfig.directionalVerts[dir], texture, localPos); } else if (connectedMeshConfig.connectsToTypes.Length != 0) { int neighborType = blocks.Get(localPos.Add(dir)).Type; for (int i = 0; i < connectedMeshConfig.connectsToTypes.Length; i++) { if (neighborType == connectedMeshConfig.connectsToTypes[i]) { texture = connectedMeshConfig.texture.GetTexture(chunk, localPos, dir); batcher.AddMeshData(connectedMeshConfig.directionalTris[dir], connectedMeshConfig.directionalVerts[dir], texture, localPos); break; } } } } texture = customMeshConfig.texture.GetTexture(chunk, localPos, Direction.down); batcher.AddMeshData(customMeshConfig.tris, customMeshConfig.verts, texture, localPos); }
protected abstract void OnPostSetBlocks(ChunkBlocks blocks);
protected abstract void OnSetBlocksRaw(ChunkBlocks blocks, ref Vector3Int min, ref Vector3Int max);
protected override void OnSetBlocks(ChunkBlocks blocks) { blocks.ProcessSetBlock(blockData, index, setBlockModified); }
public void Apply(ChunkBlocks blocks) { OnSetBlocks(blocks); OnPostSetBlocks(blocks); }
protected override void OnSetBlocksRaw(ChunkBlocks blocks, ref Vector3Int min, ref Vector3Int max) { throw new Exception("ModifyOpBlock::OnSetBlocksRaw should never get called!"); }