public override void HandleMcpeStartGame(McpeStartGame message) { Client.EntityId = message.runtimeEntityId; Client.NetworkEntityId = message.entityIdSelf; Client.SpawnPoint = message.spawn; Client.CurrentLocation = new PlayerLocation(Client.SpawnPoint, message.rotation.X, message.rotation.X, message.rotation.Y); Client.LevelInfo.LevelName = message.levelId; Client.LevelInfo.Version = 19133; Client.LevelInfo.GameType = message.gamemode; _blockPallet = message.blockPallet; _internalStates = new HashSet <BlockRecord>(BlockFactory.BlockPallet); //ClientUtils.SaveLevel(_level); { int viewDistance = Config.GetProperty("ViewDistance", 11); var packet = McpeRequestChunkRadius.CreateObject(); Client.ChunkRadius = viewDistance; packet.chunkRadius = Client.ChunkRadius; Client.SendPacket(packet); } }
private static uint GetHashRuntimeId(BlockPallet bedrockPallet, HashSet <BlockRecord> internalBlockPallet, int runtimeId) { if (runtimeId < 0 || runtimeId >= bedrockPallet.Count) { Log.Error($"RuntimeId = {runtimeId}"); } var record = bedrockPallet[runtimeId]; if (!internalBlockPallet.TryGetValue(record, out BlockRecord internalRecord)) { Log.Error($"Did not find {record.Id}"); return(0); // air } uint hash = (uint)((internalRecord.Id << 4) | (byte)internalRecord.Data); return(hash); }
public void GenerateClassesForBlocks() { BlockPallet pallet = null; var assembly = Assembly.GetAssembly(typeof(Block)); using (var stream = assembly.GetManifestResourceStream(typeof(Block).Namespace + ".blockstates.json")) using (var reader = new StreamReader(stream)) { pallet = BlockPallet.FromJson(reader.ReadToEnd()); } List <(int, string)> blocks = new List <(int, string)>(); string fileName = Path.GetTempPath() + "MissingBlocks_" + Guid.NewGuid() + ".txt"; using (FileStream file = File.OpenWrite(fileName)) { Log.Warn($"Writing new blocks to filename:\n{fileName}"); IndentedTextWriter writer = new IndentedTextWriter(new StreamWriter(file)); writer.WriteLine($"namespace MiNET.Blocks"); writer.WriteLine($"{{"); writer.Indent++; foreach (IGrouping <string, BlockRecord> blockstate in pallet.OrderBy(r => r.Name).ThenBy(r => r.Data).GroupBy(r => r.Name)) { var enumerator = blockstate.GetEnumerator(); enumerator.MoveNext(); var value = enumerator.Current; if (value == null) { continue; } Log.Debug($"{value.RuntimeId}, {value.Name}, {value.Data}"); int id = BlockFactory.GetBlockIdByName(value.Name.Replace("minecraft:", "")); if (id == 0 && !value.Name.Contains("air")) { string blockName = CodeName(value.Name.Replace("minecraft:", ""), true); blocks.Add((value.Id, blockName)); writer.WriteLine($"public class {blockName}: Block"); writer.WriteLine($"{{"); writer.Indent++; writer.WriteLine($"public {blockName}() : base({value.Id})"); writer.WriteLine($"{{"); writer.Indent++; writer.WriteLine($"Name = \"{value.Name}\";"); do { writer.WriteLine($"// runtime id: {enumerator.Current.RuntimeId} 0x{enumerator.Current.RuntimeId:X}, data: {enumerator.Current.Data}"); } while (enumerator.MoveNext()); writer.Indent--; writer.WriteLine($"}}"); writer.Indent--; writer.WriteLine($"}}"); } } writer.Indent--; writer.WriteLine($"}}"); foreach (var block in blocks.OrderBy(tuple => tuple.Item1)) { writer.WriteLine($"else if (blockId == {block.Item1}) block = new {block.Item2}();"); } writer.Flush(); } }
public static ChunkColumn DecodeChunkColumn(int subChunkCount, byte[] buffer, BlockPallet bedrockPallet = null, HashSet <BlockRecord> 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(); for (int chunkIndex = 0; chunkIndex < subChunkCount; chunkIndex++) { int version = defStream.ReadByte(); int storageSize = defStream.ReadByte(); var section = (PaletteChunk)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}, " + $"bitsPerBlock={bitsPerBlock}, " + $"noBlocksPerWord={blocksPerWord}, " + $"wordCount={wordsPerChunk}, " + $""); long jumpPos = stream.Position; stream.Seek(wordsPerChunk * 4, SeekOrigin.Current); int paletteCount = VarInt.ReadSInt32(stream); var palette = new uint[paletteCount]; for (int j = 0; j < paletteCount; j++) { palette[j] = GetHashRuntimeId(bedrockPallet, internalBlockPallet, VarInt.ReadSInt32(stream)); } 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; uint hash = palette[state]; int bid = (int)(hash >> 4); if (BlockFactory.GetBlockById(bid).GetType() == typeof(Block)) { //Log.Error($"No block for bid={bid}"); bid = 0; } if (storageIndex == 0) { section.SetBlock(x, y, z, bid); section.SetMetadata(x, y, z, (byte)(hash & 0xf)); } else { section.SetLoggedBlock(x, y, z, bid); section.SetLoggedMetadata(x, y, z, (byte)(hash & 0xf)); } 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; 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: {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); } } }