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; SubChunk subChunk = chunk.GetSubChunk(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 static byte GetSkyLight(BlockCoordinates blockCoordinates, SubChunk 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)); }
public static bool IsTransparent(BlockCoordinates blockCoordinates, SubChunk section) { if (section == null) { return(true); } int bx = blockCoordinates.X & 0x0f; int by = blockCoordinates.Y & 0xff; int bz = blockCoordinates.Z & 0x0f; int bid = section.GetBlockId(bx, by - 16 * (by >> 4), bz); return(bid == 0 || BlockFactory.TransparentBlocks[bid] == 1); }
public static int GetDiffuseLevel(BlockCoordinates blockCoordinates, SubChunk 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; int bid = section.GetBlockId(bx, by - 16 * (by >> 4), bz); return(bid == 8 || bid == 9 ? 3 : bid == 18 || bid == 161 || bid == 30 ? 2 : 1); }
public object Clone() { SubChunk cc = CreateObject(); cc._isAllAir = _isAllAir; cc.IsDirty = IsDirty; cc._runtimeIds = new List <int>(_runtimeIds); _blocks.CopyTo(cc._blocks, 0); cc._loggedRuntimeIds = new List <int>(_loggedRuntimeIds); _loggedBlocks.CopyTo(cc._loggedBlocks, 0); _blocklight.Data.CopyTo(cc._blocklight.Data, 0); _skylight.Data.CopyTo(cc._skylight.Data, 0); if (_cache != null) { cc._cache = (byte[])_cache.Clone(); } return(cc); }
private void ParseSection(SubChunk section, ReadOnlySpan <byte> data) { var reader = new SpanReader(); var version = reader.ReadByte(data); if (version != 8) { throw new Exception("Wrong chunk version"); } var storageSize = reader.ReadByte(data); for (int storage = 0; storage < storageSize; storage++) { byte paletteAndFlag = reader.ReadByte(data); bool isRuntime = (paletteAndFlag & 1) != 0; if (isRuntime) { throw new Exception("Can't use runtime for persistent storage."); } int bitsPerBlock = paletteAndFlag >> 1; int blocksPerWord = (int)Math.Floor(32d / bitsPerBlock); int wordCount = (int)Math.Ceiling(4096d / blocksPerWord); int blockIndex = reader.Position; reader.Position += wordCount * 4; int paletteSize = reader.ReadInt32(data); var palette = new Dictionary <int, (short, byte)>(); for (int j = 0; j < paletteSize; j++) { var file = new NbtFile { BigEndian = false, UseVarInt = false }; var buffer = data.Slice(reader.Position).ToArray(); int numberOfBytesRead = (int)file.LoadFromStream(new MemoryStream(buffer), NbtCompression.None); reader.Position += numberOfBytesRead; var tag = file.RootTag; string blockName = tag["name"].StringValue; Block block = BlockFactory.GetBlockByName(blockName); short blockId = 0; if (block != null) { blockId = (short)block.Id; } else { Log.Warn($"Missing block={blockName}"); } short blockMeta = tag["val"].ShortValue; palette.Add(j, (blockId, (byte)blockMeta)); } int nextStore = reader.Position; reader.Position = blockIndex; int position = 0; for (int wordIdx = 0; wordIdx < wordCount; wordIdx++) { uint word = reader.ReadUInt32(data); for (int block = 0; block < blocksPerWord; block++) { if (position >= 4096) { continue; // padding bytes } int state = (int)((word >> ((position % blocksPerWord) * bitsPerBlock)) & ((1 << bitsPerBlock) - 1)); int x = (position >> 8) & 0xF; int y = position & 0xF; int z = (position >> 4) & 0xF; if (state > palette.Count) { Log.Error($"Got wrong state={state} from word. bitsPerBlock={bitsPerBlock}, blocksPerWord={blocksPerWord}, Word={word}"); } short bid = palette[state].Item1; byte metadata = palette[state].Item2; int runtimeId = (int)BlockFactory.GetRuntimeId(bid, metadata); if (storage == 0) { section.SetBlockByRuntimeId(x, y, z, runtimeId); } else { section.SetLoggedBlockByRuntimeId(x, y, z, runtimeId); } position++; } } reader.Position = nextStore; } }
private void ParseSection(SubChunk section, ReadOnlyMemory <byte> data) { var reader = new MemoryStreamReader(data); var version = reader.ReadByte(); if (version != 8) { throw new Exception("Wrong chunk version"); } var storageSize = reader.ReadByte(); for (int storage = 0; storage < storageSize; storage++) { byte paletteAndFlag = (byte)reader.ReadByte(); bool isRuntime = (paletteAndFlag & 1) != 0; if (isRuntime) { throw new Exception("Can't use runtime for persistent storage."); } int bitsPerBlock = paletteAndFlag >> 1; int blocksPerWord = (int)Math.Floor(32d / bitsPerBlock); int wordCount = (int)Math.Ceiling(4096d / blocksPerWord); long blockIndex = reader.Position; reader.Position += wordCount * 4; int paletteSize = reader.ReadInt32(); var palette = new Dictionary <int, int>(); for (int j = 0; j < paletteSize; j++) { var file = new NbtFile { BigEndian = false, UseVarInt = false }; file.LoadFromStream(reader, NbtCompression.None); var tag = (NbtCompound)file.RootTag; Block block = BlockFactory.GetBlockByName(tag["name"].StringValue); if (block != null && block.GetType() != typeof(Block) && !(block is Air)) { List <IBlockState> blockState = ReadBlockState(tag); block.SetState(blockState); } else { block = new Air(); } palette.Add(j, block.GetRuntimeId()); } long nextStore = reader.Position; reader.Position = blockIndex; int position = 0; for (int wordIdx = 0; wordIdx < wordCount; wordIdx++) { uint word = reader.ReadUInt32(); for (int block = 0; block < blocksPerWord; block++) { if (position >= 4096) { continue; // padding bytes } int state = (int)((word >> ((position % blocksPerWord) * bitsPerBlock)) & ((1 << bitsPerBlock) - 1)); int x = (position >> 8) & 0xF; int y = position & 0xF; int z = (position >> 4) & 0xF; if (state > palette.Count) { Log.Error($"Got wrong state={state} from word. bitsPerBlock={bitsPerBlock}, blocksPerWord={blocksPerWord}, Word={word}"); } if (storage == 0) { section.SetBlockByRuntimeId(x, y, z, palette[state]); } else { section.SetLoggedBlockByRuntimeId(x, y, z, palette[state]); } position++; } } reader.Position = nextStore; } }
private byte SetLightLevel(IBlockAccess level, ChunkColumn chunk, SubChunk 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); } if (!(up || down) && (chunk.X != coordinates.X >> 4 || chunk.Z != coordinates.Z >> 4)) { chunk = level.GetChunk((ChunkCoordinates)coordinates); 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 = chunk.GetSubChunk(coordinates.Y); } 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); }