public BlockState this[Int3 location] { get { Int3 chunkSectionKey = location.GetChunk(); Int2 chunkKey = new Int2(chunkSectionKey.X, chunkSectionKey.Z); if (Chunks.ContainsKey(chunkKey)) { ChunkColumn chunk = Chunks[chunkKey]; ChunkSection section = chunk[chunkSectionKey.Y]; if (section == null) { return(new BlockState()); } else { Int3 bp = location.InChunkBlock(); BlockId id = section.GetBlock(bp.X, bp.Y, bp.Z); return(GlobalPalette.GetState(id.StateId)); } } else { return(new BlockState()); } } }
public void SetBlock(int x, int y, int z, Block block) { x = NumericsHelper.Modulo(x, 16); z = NumericsHelper.Modulo(z, 16); var sectionIndex = y >> 4; var success = Sections[sectionIndex].SetBlock(x, y & 15, z, block); // Palette dynamic sizing if (!success) { var oldSection = Sections[sectionIndex]; var bpb = oldSection.BitsPerBlock; bpb += 1; var newSection = new ChunkSection(bpb, sectionIndex); for (int sx = 0; sx < 16; sx++) { for (int sy = 0; sy < 16; sy++) { for (int sz = 0; sz < 16; sz++) { // Seems to be the safest way to do this. A bit expensive, though... newSection.SetBlock(sx, sy, sz, oldSection.GetBlock(sx, sy, sz)); } } } Sections[sectionIndex] = newSection; SetBlock(x, y, z, block); } }
private static void ChunkRecieve(Packet packet) { Vector3Int pos = new Vector3Int(packet.ReadInt(), packet.ReadInt(), packet.ReadInt()); bool encoded = packet.ReadBool(); int count = packet.ReadInt(); byte[] data = packet.ReadBytes(count); Vector2Int parentPos = new Vector2Int(pos.x, pos.z); if (!loadingChunks.ContainsKey(parentPos)) { loadingChunks[parentPos] = new Chunk(parentPos); } Chunk parent = loadingChunks[parentPos]; parent.sections[pos.y] = ChunkSection.Decode(parent, pos, data, encoded); foreach (ChunkSection section in parent.sections) { if (section == null) { return; } } loadingChunks.Remove(parentPos); ChunkManager.Get.AddChunk(parent); }
protected override void GenerateChunk(ChunkSection chunk, int x, int z) { var localPos = new Coord3(x, 0, z); var pos = localPos.BlockToWorld(chunk.worldPosition); var height = baseHeight + GetNoise(pos.x, 0, pos.z, noiseFreq, noiseHeight); for (int y = 0; y < ChunkSection.Size; y++) { localPos.y = y; pos = localPos.BlockToWorld(chunk.worldPosition); if (chanceNoise) { if (noise3d || pos.y == 0) { var chance = GetChance(pos.x, pos.y, pos.z, freq, dens); if (chance) { SetBlock(chunk, localPos, dirt); SetBlock(chunk, new Coord3(localPos.x, localPos.y + 1, localPos.z), stone); } } } } }
public void Enqueue(ChunkSection c) { lock (toLoad) { c.Meshed = true; // TODO Leave here? toLoad.Enqueue(c.Copy()); // TODO Copy maybe? to not have to worry about threading access } }
public void ReadError() { ChunkSection chunkSection = new ChunkSection(); var data = Convert.FromBase64String(ResourseReader.Read("ChunkSectionError1.txt")); chunkSection.Parse(ref data); }
private void ProcessNode(IBlockAccess level, ChunkColumn chunk, BlockCoordinates coordinates, Queue <BlockCoordinates> lightBfsQueue, HashSet <BlockCoordinates> lightBfSet) { //if (section.IsAllAir()) byte currentSkyLight = GetSkyLight(coordinates, chunk); int sectionIdx = coordinates.Y >> 4; ChunkSection subChunk = (ChunkSection)chunk.GetSection(coordinates.Y); byte maxSkyLight = currentSkyLight; if (coordinates.Y < 255) { var up = coordinates.BlockUp(); maxSkyLight = Math.Max(maxSkyLight, SetLightLevel(level, chunk, subChunk, sectionIdx, lightBfsQueue, lightBfSet, up, currentSkyLight, up: true)); } if (coordinates.Y > 0) { var down = coordinates.BlockDown(); maxSkyLight = Math.Max(maxSkyLight, SetLightLevel(level, chunk, subChunk, sectionIdx, lightBfsQueue, lightBfSet, down, currentSkyLight, down: true)); } var west = coordinates.BlockWest(); maxSkyLight = Math.Max(maxSkyLight, SetLightLevel(level, chunk, subChunk, sectionIdx, lightBfsQueue, lightBfSet, west, currentSkyLight)); var east = coordinates.BlockEast(); maxSkyLight = Math.Max(maxSkyLight, SetLightLevel(level, chunk, subChunk, sectionIdx, lightBfsQueue, lightBfSet, east, currentSkyLight)); var south = coordinates.BlockSouth(); maxSkyLight = Math.Max(maxSkyLight, SetLightLevel(level, chunk, subChunk, sectionIdx, lightBfsQueue, lightBfSet, south, currentSkyLight)); var north = coordinates.BlockNorth(); maxSkyLight = Math.Max(maxSkyLight, SetLightLevel(level, chunk, subChunk, sectionIdx, lightBfsQueue, lightBfSet, north, currentSkyLight)); if (IsTransparent(coordinates, subChunk) && currentSkyLight != 15) { int diffuseLevel = GetDiffuseLevel(coordinates, subChunk); maxSkyLight = (byte)Math.Max(currentSkyLight, maxSkyLight - diffuseLevel); if (maxSkyLight > currentSkyLight) { level.SetSkyLight(coordinates, maxSkyLight); if (!lightBfSet.Contains(coordinates)) { lightBfsQueue.Enqueue(coordinates); lightBfSet.Add(coordinates); } } } }
public ChunkMeshBuilder(ChunkSection _c) { c = _c; lightPos = new List <Vector3>(); WorldMeshBuilder = new MeshBuilder(); FluidMeshBuilder = new MeshBuilder(); FoliageMeshBuilder = new MeshBuilder(); }
protected virtual void GenerateChunk(ChunkSection chunk, int x, int z) { var stone = ResourceStore.Blocks["stone"]; for (int y = 0; y < ChunkSection.Size; y++) { var pos = new Coord3(x, y, z); SetBlock(chunk, pos, stone); } }
protected Block SetBlock(ChunkSection chunk, Coord3 localPos, BlockData data, bool replace = false) { var b = chunk.blocks.GetBlock(localPos); if (replace || b == null) { Block outb; chunk.blocks.PlaceBlock(localPos, data, out outb, false); return(outb); } return(null); }
public ChunkSection GetSection(int y) { var section = Sections[y >> 4]; if (section == null) { var storage = new ChunkSection(this, y, true, 2); Sections[y >> 4] = storage; return(storage); } return((ChunkSection)section); }
public static byte GetSkyLight(BlockCoordinates blockCoordinates, ChunkSection chunk) { if (chunk == null) { return(15); } int bx = blockCoordinates.X & 0x0f; int by = blockCoordinates.Y & 0xff; int bz = blockCoordinates.Z & 0x0f; return(chunk.GetSkylight(bx, by - 16 * (by >> 4), bz)); }
private ChunkSection GetSection(int y) { var section = Sections[y >> 4]; if (section == null) { var storage = new ChunkSection(y, true); Sections[y >> 4] = storage; return(storage); } return((ChunkSection)section); }
public void SetTile(int x, int y, int z, Tile tile) { try { var section = Sections[y >> 4] ?? (Sections[y >> 4] = new ChunkSection()); section.Tiles[x & 15, y & 15, z & 15] = tile; } catch (Exception e) { Debug.LogError(e); } }
protected override void GenerateChunk(ChunkSection chunk, int x, int z) { var localPos = new Coord3(x, 0, z); void Set(BlockData block) { SetBlock(chunk, localPos, block); } for (localPos.y = 0; localPos.y < ChunkSection.Size; localPos.y++) { var pos = localPos.BlockToWorld(chunk.worldPosition); bool isCave = GetChance(pos.x, pos.y, pos.z, caveFrequency, caveDensity) || GetChance(pos.y, pos.z, pos.x, caveFrequency + 0.02f, caveDensity + 4) || GetChance(-pos.x, -pos.y, -pos.z, caveFrequency - 0.02f, caveDensity - 4); if (pos.y <= stoneHeight && !isCave) { for (int i = 0; i < ores.Length; i++) { if (GetChance(pos.x, pos.y, pos.z, ores[i].spawnFrequency, ores[i].spawnDensity)) { Set(ores[i]); } else { Set(stone); } } } else if (pos.y < stoneHeight + dirtHeight && !isCave) { Set(dirt); } else if (pos.y == stoneHeight + dirtHeight && !isCave) { if (GetChance(pos.x, 0, pos.z, treeFrequency, treeDensity)) { GenerateStructure(chunk, localPos.x, localPos.y + 1, localPos.z, "tree"); } else if (GetChance(pos.x, 0, pos.z, grassFrequency, grassDensity)) { SetBlock(chunk, new Coord3(localPos.x, localPos.y + 1, localPos.z), grass_decal); } Set(grass); } } }
internal IEnumerable <BlockFace> CheckNeighbors(ChunkSection section, int y, IWorld world) { List <BlockFace> faces = new List <BlockFace>(); var sectionUp = (ChunkSection)Sections[y + 1]; if (sectionUp != null && sectionUp.IsFaceSolid(BlockFace.Down)) { faces.Add(BlockFace.Up); } var sectionDown = (ChunkSection)Sections[y - 1]; if (sectionDown != null && sectionDown.IsFaceSolid(BlockFace.Up)) { faces.Add(BlockFace.Down); } var eastChunk = world.GetChunkColumn(X + 1, Z); if (eastChunk != null && eastChunk.IsWallSectionSolid(3, y)) { faces.Add(BlockFace.East); } var westChunk = world.GetChunkColumn(X - 1, Z); if (westChunk != null && westChunk.IsWallSectionSolid(2, y)) { faces.Add(BlockFace.West); } var northChunk = world.GetChunkColumn(X, Z + 1); if (northChunk != null && northChunk.IsWallSectionSolid(5, y)) { faces.Add(BlockFace.North); } var southChunk = world.GetChunkColumn(X, Z - 1); if (southChunk != null && southChunk.IsWallSectionSolid(4, y)) { faces.Add(BlockFace.South); } return(faces); }
protected void FillWithAir(ChunkSection chunk) { var air = ResourceStore.Blocks["air"]; for (int x = 0; x < ChunkSection.Size; x++) { for (int y = 0; y < ChunkSection.Size; y++) { for (int z = 0; z < ChunkSection.Size; z++) { var pos = new Coord3(x, y, z); SetBlock(chunk, pos, air); } } } }
public Chunk(int x, int z) { X = x; Z = z; Heightmaps = new(); Heightmaps.Add(HeightmapType.MotionBlocking, new Heightmap(HeightmapType.MotionBlocking, this)); Heightmaps.Add(HeightmapType.OceanFloor, new Heightmap(HeightmapType.OceanFloor, this)); Heightmaps.Add(HeightmapType.WorldSurface, new Heightmap(HeightmapType.WorldSurface, this)); Sections = new ChunkSection[24]; for (int i = 0; i < Sections.Length; i++) { Sections[i] = new ChunkSection(4, yBase: i - 4); } }
private static bool IsTransparent(BlockCoordinates blockCoordinates, ChunkSection section) { if (section == null) { return(true); } int bx = blockCoordinates.X & 0x0f; int by = blockCoordinates.Y & 0xff; int bz = blockCoordinates.Z & 0x0f; var state = section.Get(bx, by - 16 * (by >> 4), bz); return(state.Block is Air || state.Block.Transparent); // return bid == 0 || BlockFactory.TransparentBlocks[bid] == 1; }
public void SetBlockId(Int3 location, BlockId state) { Int3 chunkSectionKey = location.GetChunk(); Int2 chunkKey = new Int2(chunkSectionKey.X, chunkSectionKey.Z); if (Chunks.ContainsKey(chunkKey)) { ChunkColumn chunk = Chunks[chunkKey]; ChunkSection section = chunk[chunkSectionKey.Y]; if (section != null) { Int3 bp = location.InChunkBlock(); section.SetState(bp.X, bp.Y, bp.Z, state); } } }
public static int GetDiffuseLevel(BlockCoordinates blockCoordinates, ChunkSection section) { //TODO: Figure out if this is really correct. Perhaps should be zero. if (section == null) { return(15); } int bx = blockCoordinates.X & 0x0f; int by = blockCoordinates.Y & 0xff; int bz = blockCoordinates.Z & 0x0f; var state = section.Get(bx, by - 16 * (by >> 4), bz); return(state.Block.LightOpacity); //return bid == 8 || bid == 9 ? 3 : bid == 18 || bid == 161 || bid == 30 ? 2 : 1; }
protected void GenerateStructure(ChunkSection chunk, int x, int y, int z, string id) { var s = ResourceStore.Structures[id]; for (int l = 0; l < s.height; l++) { for (int xi = 0; xi < s.size.x; xi++) { for (int zi = 0; zi < s.size.y; zi++) { var val = s[l][zi * s.size.y + xi]; var block = s.blocks[val]; var pos = new Coord3(x + xi, y + l, z + zi) - (Coord3)s.origin + Coord3.one; SetBlock(chunk, pos, block, s.cutout); } } } }
public Chunk Clone(int x, int z) { var sections = new ChunkSection[Sections.Length]; for (int i = 0; i < sections.Length; i++) { sections[i] = Sections[i].Clone(); } var heightmaps = new Dictionary <HeightmapType, Heightmap>(); var chunk = new Chunk(x, z, sections, heightmaps, isGenerated); foreach (var(type, heightmap) in Heightmaps) { heightmaps.Add(type, heightmap.Clone(chunk)); } return(chunk); }
protected override void GenerateChunk(ChunkSection chunk, int x, int z) { if (chunk.position != Coord3.zero) { return; } for (int y = 0; y < 4; y++) { if (x >= 0 && x <= 3 && z >= 0 && z <= 3) { var pos = new Coord3(8 * x, 8 * y, 8 * z); var block = SetBlock(chunk, pos, proto); chunk.blocks.GetCustomBlock <RotatedBlock>(block, b => b.SetRotation(new Coord3(x, y, z))); var block_obj = SetBlock(chunk, new Coord3(8 * x, 8 * y + 2, 8 * z), proto_obj); chunk.blocks.GetCustomBlock <StandaloneBlock>(block_obj, b => b.gameObject.transform.localEulerAngles = new Vector3(x * 90, y * 90, z * 90)); } } }
public void OnBlockChangePacket(IPacket packet) { var bcp = packet as BlockChangePacket; if (bcp != null) { int x = bcp.Location.x; int y = bcp.Location.y; int z = bcp.Location.z; if (y < 0 || y >= ChunkManager.H) { return; } int cx = x >> 4; int cz = z >> 4; ChunkManager chunk = CurrentWorld.GetChunk(cx, cz, false); if ((object)chunk == null) { return; } int cy = y >> 4; ChunkSection section = chunk.Sections[cy]; if ((object)section == null) { return; } int bx = x & 0x000F; int by = y & 0x000F; int bz = z & 0x000F; section.DecodeLongs(); section.Data[bx, by, bz] = (short)bcp.BlockId; section.Rend(); } }
public static int GetChunkSectionDataLength(ChunkSection section) { if (section == null) { throw new ArgumentNullException(nameof(section)); } IBlockPalette palette = section.BlockPalette; int length = 0; length += sizeof(short); length += sizeof(byte); length += palette.GetEncodedSize(); int longCount = GetUnderlyingDataLength(UnderlyingDataSize, palette.BitsPerBlock); length += VarInt.GetEncodedSize(longCount); length += longCount * sizeof(ulong); return(length); }
public bool IsEmptyBetween(int startY, int endY) { if (startY < 0) { startY = 0; } if (endY >= 256) { endY = 255; } for (var i = startY; i <= endY; i += 16) { if (!ChunkSection.IsEmpty(Sections[i >> 4])) { return(false); } } return(true); }
public ChunkColumn GenerateChunkAt(Vector3 ChunkPos) { ChunkSection[] sections = new ChunkSection[Constants.SECTION_PER_COLUMN]; for (int SectionY = 0; SectionY < Constants.SECTION_PER_COLUMN; SectionY++) { Dictionary <Vector3, Block> blocks = new Dictionary <Vector3, Block>(); for (int y = 0; y < Constants.SECTION_HEIGHT; y++) { for (int z = 0; z < Constants.SECTION_WIDTH; z++) { for (int x = 0; x < Constants.SECTION_WIDTH; x++) { var ActualPos = y * SectionY; Block state; if (DefaultBlocks.TryGetValue((int)TypeUtils.ChunkToWorldSpace(y, SectionY), out Block block)) ///AAAAAAH Performance { state = block; } else { state = Block.Air; } //state = new BlockState(1, 0); blocks.Add(new Vector3(x, y, z), state); } } } sections[SectionY] = new ChunkSection(blocks) { ChunkX = ChunkPos.X, ChunkY = SectionY, ChunkZ = ChunkPos.Z }; } return(new ChunkColumn(sections, ChunkPos)); }
private void WriteChunkSection(ChunkSection section, ref MemoryStream stream) { #region Section byte bitsPerBlock = FULL_SIZE_BITS_PER_BLOCK; MinecraftPacket.WriteToStream(stream, bitsPerBlock); //0: disabled? //MinecraftPacket.WriteToStream(stream, (VarInt)0); //up to 4: Blocks are encoded as 4 bits. The palette is used and sent. //5 to 8: Blocks are encoded with the given number of bits.The palette is used and sent. //9 and above: The palette is not sent. Blocks are encoded by their whole ID in the global palette, with bits per block being set as the base 2 logarithm of the number of block states, rounded up. For the current vanilla release, this is 14 bits per block. // A bitmask that contains bitsPerBlock set bits uint individualValueMask = (uint)((1 << bitsPerBlock) - 1); int dataLength = (Constants.SECTION_HEIGHT * Constants.SECTION_WIDTH * Constants.SECTION_DEPTH) * bitsPerBlock / 64; UInt64[] DataArray = new UInt64[dataLength]; for (int y = 0; y < Constants.SECTION_HEIGHT; y++) { for (int z = 0; z < Constants.SECTION_WIDTH; z++) { for (int x = 0; x < Constants.SECTION_WIDTH; x++) { var blockPos = new Vector3(x, y, z); int blockNumber = ((((int)blockPos.Y * Constants.SECTION_HEIGHT) + (int)blockPos.Z) * Constants.SECTION_WIDTH) + (int)blockPos.X; int startLong = (blockNumber * bitsPerBlock) / 64; int startOffset = (blockNumber * bitsPerBlock) % 64; int endLong = ((blockNumber + 1) * bitsPerBlock - 1) / 64; Block state = section.blocks[blockPos]; //C# Still limits the Byte Size to uint if this is a uint, //even after byteshifting into a ulong ulong value = (ulong)state.GetGlobalPaletteIDFromState(); value &= individualValueMask; DataArray[startLong] |= (value << startOffset); if (startLong != endLong) { DataArray[endLong] = (value >> (64 - startOffset)); } } } } Console.WriteLine($"Data Array was {DataArray.Length} long"); MinecraftPacket.WriteToStream(stream, (VarInt)dataLength); MinecraftPacket.WriteArrayToStream(stream, DataArray); List <byte> BlockLightData = new List <byte>(); for (int y = 0; y < Constants.SECTION_HEIGHT; y++) { for (int z = 0; z < Constants.SECTION_WIDTH; z++) { for (int x = 0; x < Constants.SECTION_WIDTH; x += 2) { // Note: x += 2 above; we read 2 values along x each time byte blocklight1 = (byte)(section.blocks[new Vector3(x, y, z)].BlockLight); //this only works because 16 is even byte blocklight2 = (byte)(section.blocks[new Vector3(x + 1, y, z)].BlockLight << 4); byte value = (byte)(blocklight1 | blocklight2); BlockLightData.Add(value); } } } Console.WriteLine($"BlockLight was {BlockLightData.Count} Long"); MinecraftPacket.WriteArrayToStream(stream, BlockLightData.ToArray()); List <byte> SkyLightData = new List <byte>(); if (section.HasSkylight) { // => current dimension is overworld / 0 for (int y = 0; y < Constants.SECTION_HEIGHT; y++) { for (int z = 0; z < Constants.SECTION_WIDTH; z++) { for (int x = 0; x < Constants.SECTION_WIDTH; x += 2) { // Note: x += 2 above; we read 2 values along x each time byte blocklight1 = (byte)(section.blocks[new Vector3(x, y, z)].SkyLight); //this only works because 16 is even byte blocklight2 = (byte)(section.blocks[new Vector3(x + 1, y, z)].SkyLight << 4); byte value = (byte)(blocklight1 | blocklight2); SkyLightData.Add(value); } } } } Console.WriteLine($"SkyLight was {SkyLightData.Count} Long"); MinecraftPacket.WriteArrayToStream(stream, SkyLightData.ToArray()); #endregion }
private byte SetLightLevel(IBlockAccess level, ChunkColumn chunk, ChunkSection subChunk, int sectionIdx, Queue <BlockCoordinates> lightBfsQueue, HashSet <BlockCoordinates> lightBfSet, BlockCoordinates coordinates, byte lightLevel, bool down = false, bool up = false) { //Interlocked.Add(ref visits, 1); if (TrackResults) { MakeVisit(coordinates); } var chunkCoords = (ChunkCoordinates)coordinates; if (!(up || down) && (chunk.X != coordinates.X >> 4 || chunk.Z != coordinates.Z >> 4)) { chunk = (ChunkColumn)level.GetChunk(chunkCoords); subChunk = null; } else { if ((up || down) && coordinates.Y >> 4 != sectionIdx) { subChunk = null; } } if (chunk == null /* || chunk.chunks == null*/) { return(lightLevel); } if (!down && !up && coordinates.Y >= GetHeight(coordinates, chunk)) { if (GetSkyLight(coordinates, subChunk) != 15) { SetSkyLight(coordinates, 15, chunk); if (!lightBfSet.Contains(coordinates)) { lightBfsQueue.Enqueue(coordinates); lightBfSet.Add(coordinates); } } return(15); } if (subChunk == null) { subChunk = (ChunkSection)chunk.Sections[coordinates.Y >> 4]; } bool isTransparent = IsTransparent(coordinates, subChunk); byte skyLight = GetSkyLight(coordinates, subChunk); if (down && isTransparent && lightLevel == 15) { if (IsNotBlockingSkylight(coordinates, chunk)) { if (skyLight != 15) { SetSkyLight(coordinates, 15, chunk); } if (!lightBfSet.Contains(coordinates)) { lightBfsQueue.Enqueue(coordinates); lightBfSet.Add(coordinates); } return(15); } } if (isTransparent) { int diffuseLevel = GetDiffuseLevel(coordinates, subChunk); if (skyLight + 1 + diffuseLevel <= lightLevel) { byte newLevel = (byte)(lightLevel - diffuseLevel); SetSkyLight(coordinates, newLevel, chunk); if (!lightBfSet.Contains(coordinates)) { lightBfsQueue.Enqueue(coordinates); lightBfSet.Add(coordinates); } return(newLevel); } } return(skyLight); }