public override void FromStream(BinaryReader reader) { Stream stream = reader.BaseStream; Value = new BlockCoordinates { X = VarInt.ReadSInt32(stream), Y = VarInt.ReadSInt32(stream), Z = VarInt.ReadSInt32(stream), }; }
public static ChunkColumn DecocedChunkColumn(byte[] buffer) { lock (_chunkRead) { MemoryStream stream = new MemoryStream(buffer); { NbtBinaryReader defStream = new NbtBinaryReader(stream, true); Log.Debug("New chunk column"); int count = defStream.ReadByte(); if (count < 1) { Log.Warn("Nothing to read"); return(null); } if (count > 1) { Log.Debug($"Reading {count} sections"); } else { Log.Debug($"Reading {count} sections"); } ChunkColumn chunkColumn = new ChunkColumn(); for (int s = 0; s < count; s++) { int idx = defStream.ReadByte(); Log.Debug($"New section {s}, index={idx}"); Chunk chunk = chunkColumn.chunks[s]; int chunkSize = 16 * 16 * 16; defStream.Read(chunk.blocks, 0, chunkSize); //Log.Debug($"Blocks1:\n{Package.HexDump(chunk.blocks)}"); if (defStream.Read(chunk.metadata.Data, 0, chunkSize / 2) != chunkSize / 2) { Log.Error($"Out of data: metadata"); } //Log.Debug($"metadata:\n{Package.HexDump(chunk.metadata.Data)}"); if (defStream.Read(chunk.skylight.Data, 0, chunkSize / 2) != chunkSize / 2) { Log.Error($"Out of data: skylight"); } //Log.Debug($"skylight:\n{Package.HexDump(chunk.skylight.Data)}"); if (defStream.Read(chunk.blocklight.Data, 0, chunkSize / 2) != chunkSize / 2) { Log.Error($"Out of data: blocklight"); } //Log.Debug($"blocklight:\n{Package.HexDump(chunk.blocklight.Data)}"); //Log.Debug($"skylight.Data:\n{Package.HexDump(chunk.skylight.Data, 64)}"); //Log.Debug($"blocklight.Data:\n{Package.HexDump(chunk.blocklight.Data)}"); //byte[] ints = new byte[256*4]; //var readLen = defStream.Read(ints, 0, ints.Length); //if (readLen != ints.Length) Log.Error($"Out of data biomeColors, read lenght {readLen}"); //Log.Debug($"biomeColor (pre):\n{Package.HexDump(ints)}"); //return null; //int j = 0; //for (int i = 0; i < ints.Length; i = i + 4) //{ // chunk.biomeId[j] = ints[i]; // chunk.biomeColor[j++] = BitConverter.ToInt32(new[] {(byte) 0, ints[i + 1], ints[i + 2], ints[i + 3]}, 0); //} //Log.Debug($"biomeId (post):\n{Package.HexDump(chunk.biomeId)}"); //if (stream.Position >= stream.Length - 1) return chunk; ////return chunk; //return chunk; } //if (stream.Position >= stream.Length - 1) continue; if (defStream.Read(chunkColumn.height, 0, 256 * 2) != 256 * 2) { Log.Error($"Out of data height"); } //Log.Debug($"Heights:\n{Package.HexDump(chunk.height)}"); //if (stream.Position >= stream.Length - 1) continue; if (defStream.Read(chunkColumn.biomeId, 0, 256) != 256) { Log.Error($"Out of data biomeId"); } //Log.Debug($"biomeId:\n{Package.HexDump(chunk.biomeId)}"); //if (stream.Position >= stream.Length - 1) continue; int borderBlock = VarInt.ReadSInt32(stream); if (borderBlock != 0) { Log.Warn($"??? Got borderblock {borderBlock}"); } int extraCount = VarInt.ReadSInt32(stream); if (extraCount != 0) { //Log.Warn($"Got extradata\n{Package.HexDump(defStream.ReadBytes(extraCount*10))}"); for (int i = 0; i < extraCount; i++) { var hash = VarInt.ReadSInt32(stream); var blockData = defStream.ReadInt16(); Log.Warn($"Got extradata: hash=0x{hash:X2}, blockdata=0x{blockData:X2}"); } } if (stream.Position < stream.Length - 1) { //Log.Debug($"Got NBT data\n{Package.HexDump(defStream.ReadBytes((int) (stream.Length - stream.Position)))}"); while (stream.Position < stream.Length) { NbtFile file = new NbtFile() { BigEndian = false, UseVarInt = true }; file.LoadFromStream(stream, NbtCompression.None); Log.Debug($"Blockentity: {file.RootTag}"); } } if (stream.Position < stream.Length - 1) { Log.Warn($"Still have data to read\n{Package.HexDump(defStream.ReadBytes((int)(stream.Length - stream.Position)))}"); } } return(new ChunkColumn()); } }
public int ReadSignedVarInt() { return(VarInt.ReadSInt32(_buffer)); }
public static ChunkColumn DecocedChunkColumn(byte[] buffer) { lock (_chunkRead) { MemoryStream stream = new MemoryStream(buffer); { NbtBinaryReader defStream = new NbtBinaryReader(stream, true); Log.Debug("New chunk column"); int count = defStream.ReadByte(); if (count < 1) { Log.Warn("Nothing to read"); return(null); } Log.Debug($"Reading {count} sections"); ChunkColumn chunkColumn = new ChunkColumn(); for (int s = 0; s < count; s++) { int version = defStream.ReadByte(); int storageSize = defStream.ReadByte(); for (int i = 0; i < storageSize; i++) { int bitsPerBlock = defStream.ReadByte() >> 1; int noBlocksPerWord = (int)Math.Floor(32f / bitsPerBlock); int wordCount = (int)Math.Ceiling(4096f / noBlocksPerWord); Log.Warn($"New section {s}, " + $"version={version}, " + $"storageSize={storageSize}, " + $"bitsPerBlock={bitsPerBlock}, " + $"noBlocksPerWord={noBlocksPerWord}, " + $"wordCount={wordCount}, " + $""); defStream.ReadBytes(wordCount * 4); int paletteCount = VarInt.ReadSInt32(stream); //Log.Warn($"New section {s}, " + // $"version={version}, " + // $"storageSize={storageSize}, " + // $"bitsPerBlock={bitsPerBlock}, " + // $"noBlocksPerWord={noBlocksPerWord}, " + // $"wordCount={wordCount}, " + // $"paletteCount={paletteCount}" + // $""); for (int j = 0; j < paletteCount; j++) { VarInt.ReadSInt32(stream); } } } //if (stream.Position >= stream.Length - 1) continue; byte[] ba = new byte[512]; if (defStream.Read(ba, 0, 256 * 2) != 256 * 2) { Log.Error($"Out of data height"); } Buffer.BlockCopy(ba, 0, chunkColumn.height, 0, 512); //Log.Debug($"Heights:\n{Package.HexDump(ba)}"); //if (stream.Position >= stream.Length - 1) continue; if (defStream.Read(chunkColumn.biomeId, 0, 256) != 256) { Log.Error($"Out of data biomeId"); } //Log.Debug($"biomeId:\n{Package.HexDump(chunk.biomeId)}"); if (stream.Position >= stream.Length - 1) { return(chunkColumn); } int borderBlock = VarInt.ReadSInt32(stream); if (borderBlock != 0) { byte[] buf = new byte[borderBlock]; int len = defStream.Read(buf, 0, borderBlock); Log.Warn($"??? Got borderblock {borderBlock}. Read {len} bytes"); Log.Debug($"{Packet.HexDump(buf)}"); for (int i = 0; i < borderBlock; i++) { int x = (buf[i] & 0xf0) >> 4; int z = buf[i] & 0x0f; Log.Debug($"x={x}, z={z}"); } } if (stream.Position < stream.Length - 1) { //Log.Debug($"Got NBT data\n{Package.HexDump(defStream.ReadBytes((int) (stream.Length - stream.Position)))}"); while (stream.Position < stream.Length) { NbtFile file = new NbtFile() { BigEndian = false, UseVarInt = true }; file.LoadFromStream(stream, NbtCompression.None); Log.Debug($"Blockentity: {file.RootTag}"); } } if (stream.Position < stream.Length - 1) { Log.Warn($"Still have data to read\n{Packet.HexDump(defStream.ReadBytes((int) (stream.Length - stream.Position)))}"); } return(chunkColumn); } } }
public static ChunkColumn DecodeChunkColumn(int subChunkCount, byte[] buffer, BlockPalette bedrockPalette = null, HashSet <BlockStateContainer> internalBlockPallet = null) { lock (_chunkRead) { var stream = new MemoryStream(buffer); { var defStream = new NbtBinaryReader(stream, true); if (subChunkCount < 1) { Log.Warn("Nothing to read"); return(null); } Log.Debug($"Reading {subChunkCount} sections"); var chunkColumn = new ChunkColumn(false); for (int chunkIndex = 0; chunkIndex < subChunkCount; chunkIndex++) { int version = defStream.ReadByte(); int storageSize = defStream.ReadByte(); var subChunk = chunkColumn[chunkIndex]; for (int storageIndex = 0; storageIndex < storageSize; storageIndex++) { int bitsPerBlock = defStream.ReadByte() >> 1; int blocksPerWord = (int)Math.Floor(32f / bitsPerBlock); int wordsPerChunk = (int)Math.Ceiling(4096f / blocksPerWord); Log.Debug($"New section {chunkIndex}, " + $"version={version}, " + $"storageSize={storageSize}, " + $"storageIndex={storageIndex}, " + $"bitsPerBlock={bitsPerBlock}, " + $"noBlocksPerWord={blocksPerWord}, " + $"wordCount={wordsPerChunk}, " + $""); long jumpPos = stream.Position; stream.Seek(wordsPerChunk * 4, SeekOrigin.Current); int paletteCount = VarInt.ReadSInt32(stream); var palette = new int[paletteCount]; for (int j = 0; j < paletteCount; j++) { int runtimeId = VarInt.ReadSInt32(stream); if (bedrockPalette == null || internalBlockPallet == null) { continue; } palette[j] = GetServerRuntimeId(bedrockPalette, internalBlockPallet, runtimeId); } long afterPos = stream.Position; stream.Position = jumpPos; int position = 0; for (int w = 0; w < wordsPerChunk; w++) { uint word = defStream.ReadUInt32(); for (int block = 0; block < blocksPerWord; block++) { if (position >= 4096) { continue; } uint state = (uint)((word >> ((position % blocksPerWord) * bitsPerBlock)) & ((1 << bitsPerBlock) - 1)); int x = (position >> 8) & 0xF; int y = position & 0xF; int z = (position >> 4) & 0xF; int runtimeId = palette[state]; if (storageIndex == 0) { subChunk.SetBlockByRuntimeId(x, y, z, (int)runtimeId); } else { subChunk.SetLoggedBlockByRuntimeId(x, y, z, (int)runtimeId); } position++; } } stream.Position = afterPos; } } if (defStream.Read(chunkColumn.biomeId, 0, 256) != 256) { Log.Error($"Out of data biomeId"); } //Log.Debug($"biomeId:\n{Package.HexDump(chunk.biomeId)}"); //if (stream.Position >= stream.Length - 1) return chunkColumn; int borderBlock = VarInt.ReadSInt32(stream); if (borderBlock != 0) { byte[] buf = new byte[borderBlock]; int len = defStream.Read(buf, 0, borderBlock); Log.Warn($"??? Got borderblock {borderBlock}. Read {len} bytes"); Log.Debug($"{Packet.HexDump(buf)}"); for (int i = 0; i < borderBlock; i++) { int x = (buf[i] & 0xf0) >> 4; int z = buf[i] & 0x0f; Log.Debug($"x={x}, z={z}"); } } if (stream.Position < stream.Length - 1) { while (stream.Position < stream.Length) { NbtFile file = new NbtFile() { BigEndian = false, UseVarInt = true }; file.LoadFromStream(stream, NbtCompression.None); var blockEntityTag = file.RootTag; if (blockEntityTag.Name != "alex") { int x = blockEntityTag["x"].IntValue; int y = blockEntityTag["y"].IntValue; int z = blockEntityTag["z"].IntValue; chunkColumn.SetBlockEntity(new BlockCoordinates(x, y, z), (NbtCompound)file.RootTag); Log.Debug($"Blockentity:\n{file.RootTag}"); } } } if (stream.Position < stream.Length - 1) { Log.Warn($"Still have data to read\n{Packet.HexDump(defStream.ReadBytes((int) (stream.Length - stream.Position)))}"); } return(chunkColumn); } } }
private void HandleChunk(bool cacheEnabled, uint subChunkCount, byte[] chunkData, int cx, int cz, Action <ChunkColumn> callback) { if (cacheEnabled) { Log.Warn($"Unsupported cache enabled!"); } bool gotLight = false; try { using (MemoryStream stream = new MemoryStream(chunkData)) { NbtBinaryReader defStream = new NbtBinaryReader(stream, true); //int count = defStream.ReadByte(); if (subChunkCount < 1) { Log.Warn("Nothing to read"); return; } ChunkColumn chunkColumn = new ChunkColumn(); chunkColumn.IsDirty = true; chunkColumn.X = cx; chunkColumn.Z = cz; for (int s = 0; s < subChunkCount; s++) { var section = chunkColumn.Sections[s] as ChunkSection; int version = defStream.ReadByte(); if (version == 1 || version == 8) { int storageSize = defStream.ReadByte(); if (section == null) { section = new ChunkSection(chunkColumn, s, true, 2); } for (int storage = 0; storage < storageSize; storage++) { int paletteAndFlag = defStream.ReadByte(); bool isRuntime = (paletteAndFlag & 1) != 0; int bitsPerBlock = paletteAndFlag >> 1; int blocksPerWord = (int)Math.Floor(32f / bitsPerBlock); int wordCount = (int)Math.Ceiling(4096.0f / blocksPerWord); uint[] words = new uint[wordCount]; for (int w = 0; w < wordCount; w++) { int word = defStream.ReadInt32(); words[w] = SwapBytes((uint)word); } uint[] pallete = new uint[0]; if (isRuntime) { int palleteSize = VarInt.ReadSInt32(stream); pallete = new uint[palleteSize]; for (int pi = 0; pi < pallete.Length; pi++) { var ui = (uint)VarInt.ReadSInt32(stream); pallete[pi] = ui; } if (palleteSize == 0) { Log.Warn($"Pallete size is 0"); continue; } } int position = 0; for (int w = 0; w < wordCount; w++) { uint word = words[w]; for (int block = 0; block < blocksPerWord; block++) { if (position >= 4096) { break; // padding bytes } uint state = (uint)((word >> ((position % blocksPerWord) * bitsPerBlock)) & ((1 << bitsPerBlock) - 1)); int x = (position >> 8) & 0xF; int y = position & 0xF; int z = (position >> 4) & 0xF; if (state >= pallete.Length) { continue; } BlockState translated = GetBlockState(pallete[state]); if (translated != null) { if (translated.Block is Water) { string a = ""; } section.Set(storage, x, y, z, translated); } position++; } if (position >= 4096) { break; } } } } else { if (section == null) { section = new ChunkSection(chunkColumn, s, true, 1); } #region OldFormat byte[] blockIds = new byte[4096]; defStream.Read(blockIds, 0, blockIds.Length); NibbleArray data = new NibbleArray(4096); defStream.Read(data.Data, 0, data.Data.Length); for (int x = 0; x < 16; x++) { for (int z = 0; z < 16; z++) { for (int y = 0; y < 16; y++) { int idx = (x << 8) + (z << 4) + y; var id = blockIds[idx]; var meta = data[idx]; var ruid = BlockFactory.GetBlockStateID(id, meta); BlockState result = null; if (!_convertedStates.TryGetValue( ruid, out result)) { if (id == 124 || id == 123) { result = BlockFactory.GetBlockState("minecraft:redstone_lamp"); if (id == 124) { result = result.WithProperty("lit", "true"); } } else if (id > 0 && result == null) { var reverseMap = MiNET.Worlds.AnvilWorldProvider.Convert.FirstOrDefault( map => map.Value.Item1 == id); if (reverseMap.Value != null) { id = (byte)reverseMap.Key; } var res = BlockFactory.GetBlockStateID(id, meta); if (AnvilWorldProvider.BlockStateMapper.TryGetValue(res, out var res2)) { var t = BlockFactory.GetBlockState(res2); t = TranslateBlockState(t, id, meta); result = t; } else { Log.Info($"Did not find anvil statemap: {result.Name}"); result = TranslateBlockState( BlockFactory.GetBlockState(res), id, meta); } } if (result == null) { var results = BlockFactory.RuntimeIdTable.Where(xx => xx.Id == id) .ToArray(); if (results.Length > 0) { var first = results.FirstOrDefault(xx => xx.Data == meta); if (first == default) { first = results[0]; } result = TranslateBlockState( BlockFactory.GetBlockState((uint)first.RuntimeId), id, meta); } } if (result == null) { result = new BlockState() { Name = $"{id}:{meta.ToString()}", Model = BlockFactory.UnknownBlockModel, Block = new Block(0) { } }; Log.Info($"Unknown block: {id}:{meta}"); } if (result != null) { _convertedStates.TryAdd(ruid, result); } } if (result != null) { section.Set(x, y, z, result); } else { Log.Info($"Unknown block: {id}:{meta}"); } } } } #endregion } if (UseAlexChunks) { // Log.Info($"Alex chunk!"); var rawSky = new API.Utils.NibbleArray(4096); defStream.Read(rawSky.Data, 0, rawSky.Data.Length); var rawBlock = new API.Utils.NibbleArray(4096); defStream.Read(rawBlock.Data, 0, rawBlock.Data.Length); for (int x = 0; x < 16; x++) { for (int y = 0; y < 16; y++) { for (int z = 0; z < 16; z++) { var peIndex = (x * 256) + (z * 16) + y; var sky = rawSky[peIndex]; var block = rawBlock[peIndex]; var idx = y << 8 | z << 4 | x; section.SkyLight[idx] = sky; section.BlockLight[idx] = block; } } } gotLight = true; } section.RemoveInvalidBlocks(); section.IsDirty = true; //Make sure the section is saved. chunkColumn.Sections[s] = section; } /* byte[] ba = new byte[512]; * if (defStream.Read(ba, 0, 256 * 2) != 256 * 2) Log.Error($"Out of data height"); * * Buffer.BlockCopy(ba, 0, chunkColumn.Height, 0, 512);*/ int[] biomeIds = new int[256]; for (int i = 0; i < biomeIds.Length; i++) { biomeIds[i] = defStream.ReadByte(); } chunkColumn.BiomeId = biomeIds; if (stream.Position >= stream.Length - 1) { callback?.Invoke(chunkColumn); return; } int borderBlock = VarInt.ReadSInt32(stream); if (borderBlock > 0) { byte[] buf = new byte[borderBlock]; int len = defStream.Read(buf, 0, borderBlock); } if (stream.Position < stream.Length - 1) { int loop = 0; while (stream.Position < stream.Length - 1) { try { NbtFile file = new NbtFile() { BigEndian = false, UseVarInt = true }; file.LoadFromStream(stream, NbtCompression.None); if (file.RootTag.Name == "alex") { NbtCompound alexCompound = (NbtCompound)file.RootTag; for (int ci = 0; ci < subChunkCount; ci++) { var section = (ChunkSection)chunkColumn.Sections[ci]; var rawSky = new API.Utils.NibbleArray(4096); if (alexCompound.TryGet($"skylight-{ci}", out NbtByteArray skyData)) { rawSky.Data = skyData.Value; } //defStream.Read(rawSky.Data, 0, rawSky.Data.Length); var rawBlock = new API.Utils.NibbleArray(4096); if (alexCompound.TryGet($"blocklight-{ci}", out NbtByteArray blockData)) { rawBlock.Data = blockData.Value; } for (int x = 0; x < 16; x++) { for (int y = 0; y < 16; y++) { for (int z = 0; z < 16; z++) { var peIndex = (x * 256) + (z * 16) + y; var sky = rawSky[peIndex]; var block = rawBlock[peIndex]; var idx = y << 8 | z << 4 | x; section.SkyLight[idx] = sky; section.BlockLight[idx] = block; } } } chunkColumn.Sections[ci] = section; } gotLight = true; } if (stream.Position < stream.Length - 1) { // pre = stream.ReadByte(); } } catch (Exception ex) { // Log.Warn(ex, $"Reading chunk extra data (Loop={loop})"); } loop++; } } if (stream.Position < stream.Length - 1) { Log.Warn( $"Still have data to read\n{Packet.HexDump(defStream.ReadBytes((int) (stream.Length - stream.Position)))}"); } if (gotLight) { chunkColumn.SkyLightDirty = false; chunkColumn.BlockLightDirty = false; } chunkColumn.CalculateHeight(!gotLight && ClientSideLighting); //Done processing this chunk, send to world callback?.Invoke(chunkColumn); } } catch (Exception ex) { Log.Error($"Exception in chunk loading: {ex.ToString()}"); } finally { } }
private void HandleChunk(byte[] chunkData, int cx, int cz, Action <ChunkColumn> callback) { MeasureProfiler.StartCollectingData(); var profiler = MiniProfiler.StartNew("BEToJavaColumn"); try { using (MemoryStream stream = new MemoryStream(chunkData)) { NbtBinaryReader defStream = new NbtBinaryReader(stream, true); int count = defStream.ReadByte(); if (count < 1) { Log.Warn("Nothing to read"); return; } ChunkColumn chunkColumn = new ChunkColumn(); chunkColumn.IsDirty = true; chunkColumn.X = cx; chunkColumn.Z = cz; for (int s = 0; s < count; s++) { var section = chunkColumn.Sections[s] as ChunkSection; if (section == null) { section = new ChunkSection(s, true); } int version = defStream.ReadByte(); if (version == 1 || version == 8) { int storageSize = defStream.ReadByte(); for (int storage = 0; storage < storageSize; storage++) { int paletteAndFlag = defStream.ReadByte(); bool isRuntime = (paletteAndFlag & 1) != 0; int bitsPerBlock = paletteAndFlag >> 1; int blocksPerWord = (int)Math.Floor(32f / bitsPerBlock); int wordCount = (int)Math.Ceiling(4096.0f / blocksPerWord); uint[] words = new uint[wordCount]; for (int w = 0; w < wordCount; w++) { int word = defStream.ReadInt32(); words[w] = SwapBytes((uint)word); } uint[] pallete = new uint[0]; if (isRuntime) { int palleteSize = VarInt.ReadSInt32(stream); pallete = new uint[palleteSize]; for (int pi = 0; pi < pallete.Length; pi++) { var ui = (uint)VarInt.ReadSInt32(stream); pallete[pi] = ui; } if (palleteSize == 0) { Log.Warn($"Pallete size is 0"); continue; } } int position = 0; for (int w = 0; w < wordCount; w++) { uint word = words[w]; for (int block = 0; block < blocksPerWord; block++) { if (position >= 4096) { break; // padding bytes } uint state = (uint)((word >> ((position % blocksPerWord) * bitsPerBlock)) & ((1 << bitsPerBlock) - 1)); int x = (position >> 8) & 0xF; int y = position & 0xF; int z = (position >> 4) & 0xF; if (storage == 0) { if (state >= pallete.Length) { continue; } IBlockState translated = _convertedStates.GetOrAdd(pallete[state], u => { if (_blockStateMap.TryGetValue(pallete[state], out var bs)) { var result = BlockFactory.RuntimeIdTable.FirstOrDefault(xx => xx.Name == bs.Name); if (result != null && result.Id >= 0) { var reverseMap = MiNET.Worlds.AnvilWorldProvider.Convert.FirstOrDefault(map => map.Value.Item1 == result.Id); var id = result.Id; if (reverseMap.Value != null) { id = reverseMap.Key; } var res = BlockFactory.GetBlockStateID( (int)id, (byte)bs.Data); if (AnvilWorldProvider.BlockStateMapper.TryGetValue( res, out var res2)) { var t = BlockFactory.GetBlockState(res2); t = TranslateBlockState(t, id, bs.Data); return(t); } else { Log.Info( $"Did not find anvil statemap: {result.Name}"); return(TranslateBlockState( BlockFactory.GetBlockState(result.Name), id, bs.Data)); } } return(TranslateBlockState( BlockFactory.GetBlockState(bs.Name), -1, bs.Data)); } return(null); }); if (translated != null) { section.Set(x, y, z, translated); } } else { //TODO. } position++; } if (position >= 4096) { break; } } } } else { #region OldFormat byte[] blockIds = new byte[4096]; defStream.Read(blockIds, 0, blockIds.Length); NibbleArray data = new NibbleArray(4096); defStream.Read(data.Data, 0, data.Data.Length); for (int x = 0; x < 16; x++) { for (int z = 0; z < 16; z++) { for (int y = 0; y < 16; y++) { int idx = (x << 8) + (z << 4) + y; var id = blockIds[idx]; var meta = data[idx]; IBlockState result = null; if (id > 0 && result == null) { var res = BlockFactory.GetBlockStateID(id, meta); if (AnvilWorldProvider.BlockStateMapper.TryGetValue(res, out var res2)) { var t = BlockFactory.GetBlockState(res2); t = TranslateBlockState(t, id, meta); result = t; } else { Log.Info($"Did not find anvil statemap: {result.Name}"); result = TranslateBlockState(BlockFactory.GetBlockState(res), id, meta); } } if (result == null) { var results = BlockFactory.RuntimeIdTable.Where(xx => xx.Id == id && xx.Data == meta).ToArray(); if (results.Length > 0) { result = TranslateBlockState( BlockFactory.GetBlockState((uint)results[0].RuntimeId), id, meta); } } if (result != null) { section.Set(x, y, z, result); } } } } #endregion } if (UseAlexChunks) { // Log.Info($"Alex chunk!"); var rawSky = new Utils.NibbleArray(4096); defStream.Read(rawSky.Data, 0, rawSky.Data.Length); var rawBlock = new Utils.NibbleArray(4096); defStream.Read(rawBlock.Data, 0, rawBlock.Data.Length); for (int x = 0; x < 16; x++) { for (int y = 0; y < 16; y++) { for (int z = 0; z < 16; z++) { var peIndex = (x * 256) + (z * 16) + y; var sky = rawSky[peIndex]; var block = rawBlock[peIndex]; var idx = y << 8 | z << 4 | x; section.SkyLight[idx] = sky; section.BlockLight[idx] = block; } } } } section.RemoveInvalidBlocks(); section.IsDirty = true; //Make sure the section is saved. chunkColumn.Sections[s] = section; } byte[] ba = new byte[512]; if (defStream.Read(ba, 0, 256 * 2) != 256 * 2) { Log.Error($"Out of data height"); } Buffer.BlockCopy(ba, 0, chunkColumn.Height, 0, 512); int[] biomeIds = new int[256]; for (int i = 0; i < biomeIds.Length; i++) { biomeIds[i] = defStream.ReadByte(); } chunkColumn.BiomeId = biomeIds; if (stream.Position >= stream.Length - 1) { callback?.Invoke(chunkColumn); return; } int borderBlock = VarInt.ReadSInt32(stream); if (borderBlock > 0) { byte[] buf = new byte[borderBlock]; int len = defStream.Read(buf, 0, borderBlock); } if (stream.Position < stream.Length - 1) { while (stream.Position < stream.Length) { NbtFile file = new NbtFile() { BigEndian = false, UseVarInt = true }; file.LoadFromStream(stream, NbtCompression.None); } } if (stream.Position < stream.Length - 1) { Log.Warn( $"Still have data to read\n{Packet.HexDump(defStream.ReadBytes((int) (stream.Length - stream.Position)))}"); } //Done processing this chunk, send to world callback?.Invoke(chunkColumn); } } catch (Exception ex) { Log.Error($"Exception in chunk loading: {ex.ToString()}"); } finally { profiler?.Stop(); MeasureProfiler.SaveData(); } }
public static ChunkColumn DecodeChunkColumn(int subChunkCount, byte[] buffer, BlockPalette bedrockPalette = null, HashSet <BlockStateContainer> internalBlockPallet = null) { //lock (_chunkRead) { var stream = new MemoryStream(buffer); { var defStream = new BinaryReader(stream); if (subChunkCount < 1) { Log.Warn("Nothing to read"); return(null); } //if (Log.IsTraceEnabled()) Log.Trace($"Reading {subChunkCount} sections"); var chunkColumn = new ChunkColumn(false); for (int chunkIndex = 0; chunkIndex < subChunkCount; chunkIndex++) { int version = stream.ReadByte(); int storageSize = stream.ReadByte(); var subChunk = chunkColumn[chunkIndex]; for (int storageIndex = 0; storageIndex < storageSize; storageIndex++) { int flags = stream.ReadByte(); bool isRuntime = (flags & 1) != 0; int bitsPerBlock = flags >> 1; int blocksPerWord = (int)Math.Floor(32f / bitsPerBlock); int wordsPerChunk = (int)Math.Ceiling(4096f / blocksPerWord); if (Log.IsTraceEnabled()) { Log.Trace($"New section {chunkIndex}, " + $"version={version}, " + $"storageSize={storageSize}, " + $"storageIndex={storageIndex}, " + $"bitsPerBlock={bitsPerBlock}, " + $"isRuntime={isRuntime}, " + $"noBlocksPerWord={blocksPerWord}, " + $"wordCount={wordsPerChunk}, " + $""); } long jumpPos = stream.Position; stream.Seek(wordsPerChunk * 4, SeekOrigin.Current); int paletteCount = VarInt.ReadSInt32(stream); var palette = new int[paletteCount]; for (int j = 0; j < paletteCount; j++) { if (!isRuntime) { var file = new NbtFile { BigEndian = false, UseVarInt = true }; file.LoadFromStream(stream, 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[j] = block.GetRuntimeId(); } else { int runtimeId = VarInt.ReadSInt32(stream); if (bedrockPalette == null || internalBlockPallet == null) { continue; } palette[j] = GetServerRuntimeId(bedrockPalette, internalBlockPallet, runtimeId); } } long afterPos = stream.Position; stream.Position = jumpPos; int position = 0; for (int w = 0; w < wordsPerChunk; w++) { uint word = defStream.ReadUInt32(); for (int block = 0; block < blocksPerWord; block++) { if (position >= 4096) { continue; } uint state = (uint)((word >> ((position % blocksPerWord) * bitsPerBlock)) & ((1 << bitsPerBlock) - 1)); int x = (position >> 8) & 0xF; int y = position & 0xF; int z = (position >> 4) & 0xF; int runtimeId = palette[state]; if (storageIndex == 0) { subChunk.SetBlockByRuntimeId(x, y, z, (int)runtimeId); } else { subChunk.SetLoggedBlockByRuntimeId(x, y, z, (int)runtimeId); } position++; } } stream.Position = afterPos; } } if (stream.Read(chunkColumn.biomeId, 0, 256) != 256) { return(chunkColumn); } //Log.Debug($"biomeId:\n{Package.HexDump(chunk.biomeId)}"); if (stream.Position >= stream.Length - 1) { return(chunkColumn); } int borderBlock = VarInt.ReadSInt32(stream); if (borderBlock != 0) { Log.Warn($"??? Got borderblock with value {borderBlock}."); int len = (int)(stream.Length - stream.Position); var bytes = new byte[len]; stream.Read(bytes, 0, len); Log.Warn($"Data to read for border blocks\n{Packet.HexDump(new ReadOnlyMemory<byte>(bytes))}"); //byte[] buf = new byte[borderBlock]; //int len = stream.Read(buf, 0, borderBlock); //Log.Warn($"??? Got borderblock {borderBlock}. Read {len} bytes"); //Log.Debug($"{Packet.HexDump(buf)}"); //for (int i = 0; i < borderBlock; i++) //{ // int x = (buf[i] & 0xf0) >> 4; // int z = buf[i] & 0x0f; // Log.Debug($"x={x}, z={z}"); //} } if (stream.Position < stream.Length - 1) { while (stream.Position < stream.Length) { NbtFile file = new NbtFile() { BigEndian = false, UseVarInt = true }; file.LoadFromStream(stream, NbtCompression.None); var blockEntityTag = file.RootTag; if (blockEntityTag.Name != "alex") { int x = blockEntityTag["x"].IntValue; int y = blockEntityTag["y"].IntValue; int z = blockEntityTag["z"].IntValue; chunkColumn.SetBlockEntity(new BlockCoordinates(x, y, z), (NbtCompound)file.RootTag); if (Log.IsTraceEnabled()) { Log.Trace($"Blockentity:\n{file.RootTag}"); } } } } if (stream.Position < stream.Length - 1) { int len = (int)(stream.Length - stream.Position); var bytes = new byte[len]; stream.Read(bytes, 0, len); Log.Warn($"Still have data to read\n{Packet.HexDump(new ReadOnlyMemory<byte>(bytes))}"); } return(chunkColumn); } } }
public override void FromStream(BinaryReader reader) { Value = VarInt.ReadSInt32(reader.BaseStream); }