예제 #1
0
        public Block GetBlock(BlockCoordinates blockCoordinates)
        {
            ChunkColumn chunk = _worldProvider.GenerateChunkColumn(new ChunkCoordinates(blockCoordinates.X >> 4, blockCoordinates.Z >> 4));

            if (chunk == null)
            {
                return new Air()
                       {
                           Coordinates = blockCoordinates, SkyLight = 15
                       }
            }
            ;

            byte bid        = chunk.GetBlock(blockCoordinates.X & 0x0f, blockCoordinates.Y & 0xff, blockCoordinates.Z & 0x0f);
            byte metadata   = chunk.GetMetadata(blockCoordinates.X & 0x0f, blockCoordinates.Y & 0xff, blockCoordinates.Z & 0x0f);
            byte blockLight = chunk.GetBlocklight(blockCoordinates.X & 0x0f, blockCoordinates.Y & 0xff, blockCoordinates.Z & 0x0f);
            byte skyLight   = chunk.GetSkylight(blockCoordinates.X & 0x0f, blockCoordinates.Y & 0xff, blockCoordinates.Z & 0x0f);

            Block block = BlockFactory.GetBlockById(bid);

            block.Coordinates = blockCoordinates;
            block.Metadata    = metadata;
            block.BlockLight  = blockLight;
            block.SkyLight    = skyLight;

            return(block);
        }
예제 #2
0
        public Block GetBlock(BlockCoordinates blockCoordinates)
        {
            ChunkColumn chunk    = _worldProvider.GenerateChunkColumn(new ChunkCoordinates(blockCoordinates.X >> 4, blockCoordinates.Z >> 4));
            byte        bid      = chunk.GetBlock(blockCoordinates.X & 0x0f, blockCoordinates.Y & 0x7f, blockCoordinates.Z & 0x0f);
            byte        metadata = chunk.GetMetadata(blockCoordinates.X & 0x0f, blockCoordinates.Y & 0x7f, blockCoordinates.Z & 0x0f);

            Block block = BlockFactory.GetBlockById(bid);

            block.Coordinates = blockCoordinates;
            block.Metadata    = metadata;

            return(block);
        }
예제 #3
0
        public static NbtFile CreateNbtFromChunkColumn(ChunkColumn chunk, int yoffset)
        {
            var nbt = new NbtFile();

            NbtCompound levelTag = new NbtCompound("Level");

            nbt.RootTag.Add(levelTag);

            levelTag.Add(new NbtInt("xPos", chunk.x));
            levelTag.Add(new NbtInt("zPos", chunk.z));
            levelTag.Add(new NbtByteArray("Biomes", chunk.biomeId));

            NbtList sectionsTag = new NbtList("Sections");

            levelTag.Add(sectionsTag);

            for (int i = 0; i < 8; i++)
            {
                NbtCompound sectionTag = new NbtCompound();
                sectionsTag.Add(sectionTag);
                sectionTag.Add(new NbtByte("Y", (byte)i));
                int sy = i * 16;

                byte[] blocks     = new byte[4096];
                byte[] data       = new byte[2048];
                byte[] blockLight = new byte[2048];
                byte[] skyLight   = new byte[2048];

                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;
                            if (yi < 0 || yi >= 256)
                            {
                                continue;                                                  // ?
                            }
                            int  anvilIndex = (y + yoffset) * 16 * 16 + z * 16 + x;
                            byte blockId    = chunk.GetBlock(x, yi, z);

                            // PE to Anvil friendly converstion
                            if (blockId == 5)
                            {
                                blockId = 125;
                            }
                            else if (blockId == 158)
                            {
                                blockId = 126;
                            }
                            else if (blockId == 50)
                            {
                                blockId = 75;
                            }
                            else if (blockId == 50)
                            {
                                blockId = 76;
                            }
                            else if (blockId == 89)
                            {
                                blockId = 123;
                            }
                            else if (blockId == 89)
                            {
                                blockId = 124;
                            }
                            else if (blockId == 73)
                            {
                                blockId = 152;
                            }

                            blocks[anvilIndex] = blockId;
                            SetNibble4(data, anvilIndex, chunk.GetMetadata(x, yi, z));
                            SetNibble4(blockLight, anvilIndex, chunk.GetBlocklight(x, yi, z));
                            SetNibble4(skyLight, anvilIndex, chunk.GetSkylight(x, yi, z));
                        }
                    }
                }

                sectionTag.Add(new NbtByteArray("Blocks", blocks));
                sectionTag.Add(new NbtByteArray("Data", data));
                sectionTag.Add(new NbtByteArray("BlockLight", blockLight));
                sectionTag.Add(new NbtByteArray("SkyLight", skyLight));
            }

            // TODO: Save entities
            NbtList entitiesTag = new NbtList("Entities", NbtTagType.Compound);

            levelTag.Add(entitiesTag);

            NbtList blockEntitiesTag = new NbtList("TileEntities", NbtTagType.Compound);

            levelTag.Add(blockEntitiesTag);
            foreach (NbtCompound blockEntityNbt in chunk.BlockEntities.Values)
            {
                NbtCompound nbtClone = (NbtCompound)blockEntityNbt.Clone();
                nbtClone.Name = null;
                blockEntitiesTag.Add(nbtClone);
            }

            levelTag.Add(new NbtList("TileTicks", NbtTagType.Compound));

            return(nbt);
        }
예제 #4
0
        private void ReadSection(int yoffset, NbtTag sectionTag, ChunkColumn chunk)
        {
            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 >= 256)
                        {
                            continue;
                        }

                        int anvilIndex = y * 16 * 16 + z * 16 + x;
                        int blockId    = blocks[anvilIndex] + (Nibble4(adddata, anvilIndex) << 8);

                        // Anvil to PE friendly converstion

                        Func <int, byte, byte> dataConverter = (i, b) => b;                        // Default no-op converter
                        if (Convert.ContainsKey(blockId))
                        {
                            dataConverter = Convert[blockId].Item2;
                            blockId       = Convert[blockId].Item1;
                        }
                        else
                        {
                            if (BlockFactory.GetBlockById((byte)blockId).GetType() == typeof(Block))
                            {
                                Log.Warn($"No block implemented for block ID={blockId}, Meta={data}");
                                //blockId = 57;
                            }
                        }

                        chunk.isAllAir = chunk.isAllAir && blockId == 0;
                        if (blockId > 255)
                        {
                            Log.Warn($"Failed mapping for block ID={blockId}, Meta={data}");
                            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));

                        //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)
                        {
                            // Dirt Course => (Grass Path)
                            chunk.SetBlock(x, yi, z, 198);
                            chunk.SetMetadata(x, yi, z, 0);
                        }
                        else if (blockId == 3 && chunk.GetMetadata(x, yi, z) == 2)
                        {
                            // Dirt Podzol => (Podzol)
                            chunk.SetBlock(x, yi, z, 243);
                            chunk.SetMetadata(x, yi, z, 0);
                        }
                        var block = BlockFactory.GetBlockById(chunk.GetBlock(x, yi, z));
                        if (block.LightLevel > 0)
                        {
                            block.Coordinates = new BlockCoordinates(x + (16 * chunk.x), yi, z + (16 * chunk.z));
                            LightSources.Enqueue(block);
                        }
                    }
                }
            }
        }
예제 #5
0
        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));
            }

            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);

                                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;
                        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);
            }
        }
예제 #6
0
        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
                };

                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

                                Func <int, byte, byte> dataConverter = (i, b) => b;                                // Default no-op converter
                                if (Convert.ContainsKey(blockId))
                                {
                                    dataConverter = Convert[blockId].Item2;
                                    blockId       = Convert[blockId].Item1;
                                }

                                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)
                                {
                                    // Dirt Course => (Grass Path)
                                    chunk.SetBlock(x, yi, z, 198);
                                    chunk.SetMetadata(x, yi, z, 0);
                                }
                                else if (blockId == 3 && chunk.GetMetadata(x, yi, z) == 2)
                                {
                                    // Dirt Podzol => (Podzol)
                                    chunk.SetBlock(x, yi, z, 243);
                                    chunk.SetMetadata(x, yi, z, 0);
                                }
                            }
                        }
                    }
                }

                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"];

                                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);
            }
        }