public override void HandleMcpeBlockEntityData(McpeBlockEntityData message) { BlockCoordinates coordinates = message.coordinates; Nbt nbt = message.namedtag; ChunkColumn chunk = _worldProvider.GenerateChunkColumn((ChunkCoordinates)coordinates, true); if (chunk == null) { //Log.Warn($"Got block entity for non existing chunk at {coordinates}\n{nbt.NbtFile.RootTag}"); _futureBlockEntities.TryAdd(coordinates, (NbtCompound)nbt.NbtFile.RootTag); } else { //Log.Warn($"Got block entity for existing chunk at {coordinates}\n{nbt.NbtFile.RootTag}"); chunk.SetBlockEntity(coordinates, (NbtCompound)nbt.NbtFile.RootTag); } }
public ChunkColumn GetChunk(ChunkCoordinates coordinates, bool cacheOnly = false) { if (coordinates == _coord) { return(_chunk); } if (_coord != ChunkCoordinates.None) { if (coordinates != _coord) { if (coordinates != _coord + ChunkCoordinates.Backward) { if (coordinates != _coord + ChunkCoordinates.Forward) { if (coordinates != _coord + ChunkCoordinates.Left) { if (coordinates != _coord + ChunkCoordinates.Right) { if (coordinates != _coord + ChunkCoordinates.Backward + ChunkCoordinates.Left) { if (coordinates != _coord + ChunkCoordinates.Backward + ChunkCoordinates.Right) { if (coordinates != _coord + ChunkCoordinates.Forward + ChunkCoordinates.Left) { if (coordinates != _coord + ChunkCoordinates.Forward + ChunkCoordinates.Right) { return(null); } } } } } } } } } } return(_worldProvider.GenerateChunkColumn(coordinates, true)); }
public McpeBatch GenerateChunk(ChunkCoordinates chunkPosition) { if (_worldProvider == null) { return(null); } ChunkColumn chunkColumn = _worldProvider.GenerateChunkColumn(chunkPosition); if (chunkColumn == null) { return(null); } McpeBatch chunk = chunkColumn.GetBatch(); if (chunk == null) { return(null); } return(chunk); }
public void Initialize() { //IsWorldTimeStarted = false; _worldProvider.Initialize(); SpawnPoint = SpawnPoint ?? new PlayerLocation(_worldProvider.GetSpawnPoint()); CurrentWorldTime = _worldProvider.GetTime(); if (_worldProvider.IsCaching) { Stopwatch chunkLoading = new Stopwatch(); chunkLoading.Start(); // Pre-cache chunks for spawn coordinates int i = 0; foreach (var chunk in GenerateChunks(new ChunkCoordinates(SpawnPoint), new Dictionary <Tuple <int, int>, McpeBatch>(), ViewDistance)) { if (chunk != null) { i++; } } Log.InfoFormat("World pre-cache {0} chunks completed in {1}ms", i, chunkLoading.ElapsedMilliseconds); } if (Config.GetProperty("CheckForSafeSpawn", false)) { var chunk = _worldProvider.GenerateChunkColumn(new ChunkCoordinates(SpawnPoint)); chunk.RecalcHeight(); var height = GetHeight((BlockCoordinates)SpawnPoint); if (height > SpawnPoint.Y) { SpawnPoint.Y = height + 2; } Log.Debug("Checking for safe spawn"); } StartTimeInTicks = DateTime.UtcNow.Ticks; _tickTimer = new Stopwatch(); _tickTimer.Restart(); //_levelTicker = new Timer(WorldTick, null, 50, _worldTickTime); // MC worlds tick-time //_tickerThread = new Thread(RunWorldTick); //_tickerThread.Priority = ThreadPriority.Highest; //_tickerThread.IsBackground = true; //_tickerThread.Start(); //_tickerThreadTimer.Start(); _tickerHighPrecisionTimer = new HighPrecisionTimer(50, WorldTick); //_mmTickTimer = new MultiMediaTimer(); //_mmTickTimer.Mode = TimerMode.Periodic; //_mmTickTimer.Period = 50; //_mmTickTimer.Resolution = 1; //_mmTickTimer.SynchronizingObject = null; //_mmTickTimer.Tick += WorldTick; //_mmTickTimer.Start(); }
public ChunkColumn GetChunk(ChunkCoordinates coordinates, string basePath, IWorldProvider generator, int yoffset) { int width = 32; int depth = 32; int rx = coordinates.X >> 5; int rz = coordinates.Z >> 5; string filePath = Path.Combine(basePath, string.Format(@"region{2}r.{0}.{1}.mca", rx, rz, Path.DirectorySeparatorChar)); if (!File.Exists(filePath)) { var chunkColumn = generator?.GenerateChunkColumn(coordinates); if (chunkColumn != null) { chunkColumn.NeedSave = true; } return(chunkColumn); //return new ChunkColumn //{ // x = coordinates.X, // z = coordinates.Z, //}; } using (var regionFile = File.OpenRead(filePath)) { byte[] buffer = new byte[8192]; regionFile.Read(buffer, 0, 8192); int xi = (coordinates.X % width); if (xi < 0) { xi += 32; } int zi = (coordinates.Z % depth); if (zi < 0) { zi += 32; } int tableOffset = (xi + zi * width) * 4; regionFile.Seek(tableOffset, SeekOrigin.Begin); byte[] offsetBuffer = new byte[4]; regionFile.Read(offsetBuffer, 0, 3); Array.Reverse(offsetBuffer); int offset = BitConverter.ToInt32(offsetBuffer, 0) << 4; byte[] bytes = BitConverter.GetBytes(offset >> 4); Array.Reverse(bytes); if (offset != 0 && offsetBuffer[0] != bytes[0] && offsetBuffer[1] != bytes[1] && offsetBuffer[2] != bytes[2]) { throw new Exception($"Not the same buffer\n{Package.HexDump(offsetBuffer)}\n{Package.HexDump(bytes)}"); } int length = regionFile.ReadByte(); if (offset == 0 || length == 0) { var chunkColumn = generator?.GenerateChunkColumn(coordinates); if (chunkColumn != null) { chunkColumn.NeedSave = true; } return(chunkColumn); //return new ChunkColumn //{ // x = coordinates.X, // z = coordinates.Z, //}; } regionFile.Seek(offset, SeekOrigin.Begin); byte[] waste = new byte[4]; regionFile.Read(waste, 0, 4); int compressionMode = regionFile.ReadByte(); if (compressionMode != 0x02) { throw new Exception($"CX={coordinates.X}, CZ={coordinates.Z}, NBT wrong compression. Expected 0x02, got 0x{compressionMode :X2}. " + $"Offset={offset}, length={length}\n{Package.HexDump(waste)}"); } var nbt = new NbtFile(); nbt.LoadFromStream(regionFile, NbtCompression.ZLib); NbtTag dataTag = nbt.RootTag["Level"]; NbtList sections = dataTag["Sections"] as NbtList; ChunkColumn chunk = new ChunkColumn { x = coordinates.X, z = coordinates.Z, biomeId = dataTag["Biomes"].ByteArrayValue, isAllAir = true }; if (chunk.biomeId.Length > 256) { throw new Exception(); } // This will turn into a full chunk column foreach (NbtTag sectionTag in sections) { ReadSection(yoffset, sectionTag, chunk); } NbtList entities = dataTag["Entities"] as NbtList; NbtList blockEntities = dataTag["TileEntities"] as NbtList; if (blockEntities != null) { foreach (var nbtTag in blockEntities) { var blockEntityTag = (NbtCompound)nbtTag.Clone(); string entityId = blockEntityTag["id"].StringValue; int x = blockEntityTag["x"].IntValue; int y = blockEntityTag["y"].IntValue - yoffset; int z = blockEntityTag["z"].IntValue; blockEntityTag["y"] = new NbtInt("y", y); BlockEntity blockEntity = BlockEntityFactory.GetBlockEntityById(entityId); if (blockEntity != null) { blockEntityTag.Name = string.Empty; if (blockEntity is Sign) { // Remove the JSON stuff and get the text out of extra data. // TAG_String("Text2"): "{"extra":["10c a loaf!"],"text":""}" CleanSignText(blockEntityTag, "Text1"); CleanSignText(blockEntityTag, "Text2"); CleanSignText(blockEntityTag, "Text3"); CleanSignText(blockEntityTag, "Text4"); } else if (blockEntity is ChestBlockEntity) { NbtList items = (NbtList)blockEntityTag["Items"]; if (items != null) { //for (byte i = 0; i < items.Count; i++) //{ // NbtCompound item = (NbtCompound) items[i]; // item.Add(new NbtShort("OriginalDamage", item["Damage"].ShortValue)); // byte metadata = (byte) (item["Damage"].ShortValue & 0xff); // item.Remove("Damage"); // item.Add(new NbtByte("Damage", metadata)); //} } } chunk.SetBlockEntity(new BlockCoordinates(x, y, z), blockEntityTag); } } } //NbtList tileTicks = dataTag["TileTicks"] as NbtList; chunk.isDirty = false; return(chunk); } }
public static ChunkColumn GetChunk(ChunkCoordinates coordinates, string basePath, IWorldProvider generator, int yoffset) { int width = 32; int depth = 32; int rx = coordinates.X >> 5; int rz = coordinates.Z >> 5; string filePath = Path.Combine(basePath, string.Format(@"region\r.{0}.{1}.mca", rx, rz)); if (!File.Exists(filePath)) { return(generator.GenerateChunkColumn(coordinates)); } using (var regionFile = File.OpenRead(filePath)) { byte[] buffer = new byte[8192]; regionFile.Read(buffer, 0, 8192); int xi = (coordinates.X % width); if (xi < 0) { xi += 32; } int zi = (coordinates.Z % depth); if (zi < 0) { zi += 32; } int tableOffset = (xi + zi * width) * 4; regionFile.Seek(tableOffset, SeekOrigin.Begin); byte[] offsetBuffer = new byte[4]; regionFile.Read(offsetBuffer, 0, 3); Array.Reverse(offsetBuffer); int offset = BitConverter.ToInt32(offsetBuffer, 0) << 4; int length = regionFile.ReadByte(); if (offset == 0 || length == 0) { return(generator.GenerateChunkColumn(coordinates)); } regionFile.Seek(offset, SeekOrigin.Begin); byte[] waste = new byte[4]; regionFile.Read(waste, 0, 4); int compressionMode = regionFile.ReadByte(); var nbt = new NbtFile(); nbt.LoadFromStream(regionFile, NbtCompression.ZLib); NbtTag dataTag = nbt.RootTag["Level"]; NbtList sections = dataTag["Sections"] as NbtList; ChunkColumn chunk = new ChunkColumn { x = coordinates.X, z = coordinates.Z, biomeId = dataTag["Biomes"].ByteArrayValue }; for (int i = 0; i < chunk.biomeId.Length; i++) { if (chunk.biomeId[i] > 22) { chunk.biomeId[i] = 0; } } if (chunk.biomeId.Length > 256) { throw new Exception(); } // This will turn into a full chunk column foreach (NbtTag sectionTag in sections) { int sy = sectionTag["Y"].ByteValue * 16; byte[] blocks = sectionTag["Blocks"].ByteArrayValue; byte[] data = sectionTag["Data"].ByteArrayValue; NbtTag addTag = sectionTag["Add"]; byte[] adddata = new byte[2048]; if (addTag != null) { adddata = addTag.ByteArrayValue; } byte[] blockLight = sectionTag["BlockLight"].ByteArrayValue; byte[] skyLight = sectionTag["SkyLight"].ByteArrayValue; for (int x = 0; x < 16; x++) { for (int z = 0; z < 16; z++) { for (int y = 0; y < 16; y++) { int yi = sy + y - yoffset; if (yi < 0 || yi >= 128) { continue; } int anvilIndex = y * 16 * 16 + z * 16 + x; int blockId = blocks[anvilIndex] + (Nibble4(adddata, anvilIndex) << 8); // Anvil to PE friendly converstion if (blockId == 125) { blockId = 5; } else if (blockId == 126) { blockId = 158; } else if (blockId == 75) { blockId = 50; } else if (blockId == 76) { blockId = 50; } else if (blockId == 123) { blockId = 89; } else if (blockId == 124) { blockId = 89; } else if (blockId == 152) { blockId = 73; } else if (_ignore.BinarySearch(blockId) >= 0) { blockId = 0; } else if (_gaps.BinarySearch(blockId) >= 0) { Debug.WriteLine("Missing material: " + blockId); blockId = 133; } if (blockId > 255) { blockId = 41; } if (yi == 127 && blockId != 0) { blockId = 30; } if (yi == 0 && (blockId == 8 || blockId == 9 /*|| blockId == 0*/)) { blockId = 7; } //if (blockId != 0) blockId = 41; chunk.SetBlock(x, yi, z, (byte)blockId); chunk.SetMetadata(x, yi, z, Nibble4(data, anvilIndex)); chunk.SetBlocklight(x, yi, z, Nibble4(blockLight, anvilIndex)); chunk.SetSkylight(x, yi, z, Nibble4(skyLight, anvilIndex)); } } } } NbtList entities = dataTag["Entities"] as NbtList; NbtList blockEntities = dataTag["TileEntities"] as NbtList; if (blockEntities != null) { foreach (var nbtTag in blockEntities) { var blockEntityTag = (NbtCompound)nbtTag; string entityId = blockEntityTag["id"].StringValue; int x = blockEntityTag["x"].IntValue; int y = blockEntityTag["y"].IntValue - yoffset; int z = blockEntityTag["z"].IntValue; blockEntityTag["y"] = new NbtInt("y", y); BlockEntity blockEntity = BlockEntityFactory.GetBlockEntityById(entityId); if (blockEntity != null) { blockEntityTag.Name = string.Empty; chunk.SetBlockEntity(new BlockCoordinates(x, y, z), blockEntityTag); } } } NbtList tileTicks = dataTag["TileTicks"] as NbtList; chunk.isDirty = false; return(chunk); } }
public static ChunkColumn GetChunk(ChunkCoordinates coordinates, string basePath, IWorldProvider generator, int yoffset) { int width = 32; int depth = 32; int rx = coordinates.X >> 5; int rz = coordinates.Z >> 5; string filePath = Path.Combine(basePath, string.Format(@"region{2}r.{0}.{1}.mca", rx, rz, Path.DirectorySeparatorChar)); if (!File.Exists(filePath)) { return(generator?.GenerateChunkColumn(coordinates)); //return new ChunkColumn //{ // x = coordinates.X, // z = coordinates.Z, //}; } using (var regionFile = File.OpenRead(filePath)) { byte[] buffer = new byte[8192]; regionFile.Read(buffer, 0, 8192); int xi = (coordinates.X % width); if (xi < 0) { xi += 32; } int zi = (coordinates.Z % depth); if (zi < 0) { zi += 32; } int tableOffset = (xi + zi * width) * 4; regionFile.Seek(tableOffset, SeekOrigin.Begin); byte[] offsetBuffer = new byte[4]; regionFile.Read(offsetBuffer, 0, 3); Array.Reverse(offsetBuffer); int offset = BitConverter.ToInt32(offsetBuffer, 0) << 4; int length = regionFile.ReadByte(); if (offset == 0 || length == 0) { return(generator?.GenerateChunkColumn(coordinates)); //return new ChunkColumn //{ // x = coordinates.X, // z = coordinates.Z, //}; } regionFile.Seek(offset, SeekOrigin.Begin); byte[] waste = new byte[4]; regionFile.Read(waste, 0, 4); int compressionMode = regionFile.ReadByte(); var nbt = new NbtFile(); nbt.LoadFromStream(regionFile, NbtCompression.ZLib); NbtTag dataTag = nbt.RootTag["Level"]; NbtList sections = dataTag["Sections"] as NbtList; ChunkColumn chunk = new ChunkColumn { x = coordinates.X, z = coordinates.Z, biomeId = dataTag["Biomes"].ByteArrayValue }; for (int i = 0; i < chunk.biomeId.Length; i++) { if (chunk.biomeId[i] > 22) { chunk.biomeId[i] = 0; } } if (chunk.biomeId.Length > 256) { throw new Exception(); } // This will turn into a full chunk column foreach (NbtTag sectionTag in sections) { int sy = sectionTag["Y"].ByteValue * 16; byte[] blocks = sectionTag["Blocks"].ByteArrayValue; byte[] data = sectionTag["Data"].ByteArrayValue; NbtTag addTag = sectionTag["Add"]; byte[] adddata = new byte[2048]; if (addTag != null) { adddata = addTag.ByteArrayValue; } byte[] blockLight = sectionTag["BlockLight"].ByteArrayValue; byte[] skyLight = sectionTag["SkyLight"].ByteArrayValue; for (int x = 0; x < 16; x++) { for (int z = 0; z < 16; z++) { for (int y = 0; y < 16; y++) { int yi = sy + y - yoffset; if (yi < 0 || yi >= 128) { continue; } int anvilIndex = y * 16 * 16 + z * 16 + x; int blockId = blocks[anvilIndex] + (Nibble4(adddata, anvilIndex) << 8); Func <int, byte, byte> dataConverter = (i, b) => b; // Anvil to PE friendly converstion if (Convert.ContainsKey(blockId)) { dataConverter = Convert[blockId].Item2; blockId = Convert[blockId].Item1; } else if (Ignore.BinarySearch(blockId) >= 0) { blockId = 0; } else if (Gaps.BinarySearch(blockId) >= 0) { Log.WarnFormat("Missing material on convert: {0}", blockId); blockId = 133; } if (blockId > 255) { blockId = 41; } //if (yi == 127 && blockId != 0) blockId = 30; if (yi == 0 && (blockId == 8 || blockId == 9)) { blockId = 7; } chunk.SetBlock(x, yi, z, (byte)blockId); byte metadata = Nibble4(data, anvilIndex); metadata = dataConverter(blockId, metadata); chunk.SetMetadata(x, yi, z, metadata); chunk.SetBlocklight(x, yi, z, Nibble4(blockLight, anvilIndex)); chunk.SetSkylight(x, yi, z, Nibble4(skyLight, anvilIndex)); var block = BlockFactory.GetBlockById(chunk.GetBlock(x, yi, z)); if (block is BlockStairs || block is StoneSlab || block is WoodSlab) { chunk.SetSkylight(x, yi, z, 0xff); } if (blockId == 43 && chunk.GetMetadata(x, yi, z) == 7) { chunk.SetMetadata(x, yi, z, 6); } else if (blockId == 44 && chunk.GetMetadata(x, yi, z) == 7) { chunk.SetMetadata(x, yi, z, 6); } else if (blockId == 44 && chunk.GetMetadata(x, yi, z) == 15) { chunk.SetMetadata(x, yi, z, 14); } else if (blockId == 3 && chunk.GetMetadata(x, yi, z) == 1) { chunk.SetBlock(x, yi, z, 198); chunk.SetMetadata(x, yi, z, 0); } else if (blockId == 3 && chunk.GetMetadata(x, yi, z) == 2) { chunk.SetBlock(x, yi, z, 143); //Coarse Dirt => Pat chunk.SetMetadata(x, yi, z, 0); // Podzol => (Podzol) } } } } } NbtList entities = dataTag["Entities"] as NbtList; NbtList blockEntities = dataTag["TileEntities"] as NbtList; if (blockEntities != null) { foreach (var nbtTag in blockEntities) { var blockEntityTag = (NbtCompound)nbtTag.Clone(); string entityId = blockEntityTag["id"].StringValue; int x = blockEntityTag["x"].IntValue; int y = blockEntityTag["y"].IntValue - yoffset; int z = blockEntityTag["z"].IntValue; blockEntityTag["y"] = new NbtInt("y", y); BlockEntity blockEntity = BlockEntityFactory.GetBlockEntityById(entityId); if (blockEntity != null) { blockEntityTag.Name = string.Empty; if (blockEntity is Sign) { // Remove the JSON stuff and get the text out of extra data. // TAG_String("Text2"): "{"extra":["10c a loaf!"],"text":""}" CleanSignText(blockEntityTag, "Text1"); CleanSignText(blockEntityTag, "Text2"); CleanSignText(blockEntityTag, "Text3"); CleanSignText(blockEntityTag, "Text4"); } chunk.SetBlockEntity(new BlockCoordinates(x, y, z), blockEntityTag); } } } //NbtList tileTicks = dataTag["TileTicks"] as NbtList; chunk.isDirty = false; return(chunk); } }
public IEnumerable <McpeBatch> GenerateChunks(ChunkCoordinates chunkPosition, Dictionary <Tuple <int, int>, McpeBatch> chunksUsed) { lock (chunksUsed) { Dictionary <Tuple <int, int>, double> newOrders = new Dictionary <Tuple <int, int>, double>(); // ViewDistance is actually ViewArea // A = pi r^2 // sqrt(A/pi) = r double radiusSquared = ViewDistance / Math.PI; double radius = Math.Ceiling(Math.Sqrt(radiusSquared)); int centerX = chunkPosition.X; int centerZ = chunkPosition.Z; for (double x = -radius; x <= radius; ++x) { for (double z = -radius; z <= radius; ++z) { var distance = (x * x) + (z * z); if (distance > radiusSquared) { continue; } int chunkX = (int)(x + centerX); int chunkZ = (int)(z + centerZ); Tuple <int, int> index = new Tuple <int, int>(chunkX, chunkZ); newOrders[index] = distance; } } if (newOrders.Count > ViewDistance) { foreach (var pair in newOrders.OrderByDescending(pair => pair.Value)) { if (newOrders.Count <= ViewDistance) { break; } newOrders.Remove(pair.Key); } } foreach (var chunkKey in chunksUsed.Keys.ToArray()) { if (!newOrders.ContainsKey(chunkKey)) { chunksUsed.Remove(chunkKey); } } foreach (var pair in newOrders.OrderBy(pair => pair.Value)) { if (chunksUsed.ContainsKey(pair.Key)) { continue; } if (_worldProvider == null) { continue; } ChunkColumn chunkColumn = _worldProvider.GenerateChunkColumn(new ChunkCoordinates(pair.Key.Item1, pair.Key.Item2)); if (chunkColumn == null) { continue; } McpeBatch chunk = chunkColumn.GetBatch(); if (chunk == null) { continue; } chunksUsed.Add(pair.Key, chunk); yield return(chunk); } if (chunksUsed.Count > ViewDistance) { Debug.WriteLine("Too many chunks used: {0}", chunksUsed.Count); } } }
public static ChunkColumn GetChunk(ChunkCoordinates coordinates, string basePath, IWorldProvider generator, int yoffset) { int width = 32; int depth = 32; int rx = coordinates.X >> 5; int rz = coordinates.Z >> 5; string filePath = Path.Combine(basePath, string.Format(@"region\r.{0}.{1}.mca", rx, rz)); if (!File.Exists(filePath)) return generator.GenerateChunkColumn(coordinates); using (var regionFile = File.OpenRead(filePath)) { byte[] buffer = new byte[8192]; regionFile.Read(buffer, 0, 8192); int xi = (coordinates.X%width); if (xi < 0) xi += 32; int zi = (coordinates.Z%depth); if (zi < 0) zi += 32; int tableOffset = (xi + zi*width)*4; regionFile.Seek(tableOffset, SeekOrigin.Begin); byte[] offsetBuffer = new byte[4]; regionFile.Read(offsetBuffer, 0, 3); Array.Reverse(offsetBuffer); int offset = BitConverter.ToInt32(offsetBuffer, 0) << 4; int length = regionFile.ReadByte(); if (offset == 0 || length == 0) { return generator.GenerateChunkColumn(coordinates); } regionFile.Seek(offset, SeekOrigin.Begin); byte[] waste = new byte[4]; regionFile.Read(waste, 0, 4); int compressionMode = regionFile.ReadByte(); var nbt = new NbtFile(); nbt.LoadFromStream(regionFile, NbtCompression.ZLib); NbtTag dataTag = nbt.RootTag["Level"]; NbtList sections = dataTag["Sections"] as NbtList; ChunkColumn chunk = new ChunkColumn { x = coordinates.X, z = coordinates.Z, biomeId = dataTag["Biomes"].ByteArrayValue }; for (int i = 0; i < chunk.biomeId.Length; i++) { if (chunk.biomeId[i] > 22) chunk.biomeId[i] = 0; } if (chunk.biomeId.Length > 256) throw new Exception(); // This will turn into a full chunk column foreach (NbtTag sectionTag in sections) { int sy = sectionTag["Y"].ByteValue*16; byte[] blocks = sectionTag["Blocks"].ByteArrayValue; byte[] data = sectionTag["Data"].ByteArrayValue; NbtTag addTag = sectionTag["Add"]; byte[] adddata = new byte[2048]; if (addTag != null) adddata = addTag.ByteArrayValue; byte[] blockLight = sectionTag["BlockLight"].ByteArrayValue; byte[] skyLight = sectionTag["SkyLight"].ByteArrayValue; for (int x = 0; x < 16; x++) { for (int z = 0; z < 16; z++) { for (int y = 0; y < 16; y++) { int yi = sy + y - yoffset; if (yi < 0 || yi >= 128) continue; int anvilIndex = y*16*16 + z*16 + x; int blockId = blocks[anvilIndex] + (Nibble4(adddata, anvilIndex) << 8); // Anvil to PE friendly converstion if (blockId == 125) blockId = 5; else if (blockId == 126) blockId = 158; else if (blockId == 75) blockId = 50; else if (blockId == 76) blockId = 50; else if (blockId == 123) blockId = 89; else if (blockId == 124) blockId = 89; else if (blockId == 152) blockId = 73; else if (_ignore.BinarySearch(blockId) >= 0) blockId = 0; else if (_gaps.BinarySearch(blockId) >= 0) { Debug.WriteLine("Missing material: " + blockId); blockId = 133; } if (blockId > 255) blockId = 41; if (yi == 127 && blockId != 0) blockId = 30; if (yi == 0 && (blockId == 8 || blockId == 9 /*|| blockId == 0*/)) blockId = 7; //if (blockId != 0) blockId = 41; chunk.SetBlock(x, yi, z, (byte) blockId); chunk.SetMetadata(x, yi, z, Nibble4(data, anvilIndex)); chunk.SetBlocklight(x, yi, z, Nibble4(blockLight, anvilIndex)); chunk.SetSkylight(x, yi, z, Nibble4(skyLight, anvilIndex)); } } } } NbtList entities = dataTag["Entities"] as NbtList; NbtList blockEntities = dataTag["TileEntities"] as NbtList; if (blockEntities != null) { foreach (var nbtTag in blockEntities) { var blockEntityTag = (NbtCompound) nbtTag; string entityId = blockEntityTag["id"].StringValue; int x = blockEntityTag["x"].IntValue; int y = blockEntityTag["y"].IntValue - yoffset; int z = blockEntityTag["z"].IntValue; blockEntityTag["y"] = new NbtInt("y", y); BlockEntity blockEntity = BlockEntityFactory.GetBlockEntityById(entityId); if (blockEntity != null) { blockEntityTag.Name = string.Empty; chunk.SetBlockEntity(new BlockCoordinates(x, y, z), blockEntityTag); } } } NbtList tileTicks = dataTag["TileTicks"] as NbtList; chunk.isDirty = false; return chunk; } }