Пример #1
0
        /// <summary>
        /// Create a chunk from a decompressed NBT byte buffer.
        /// </summary>
        /// <param name="bytes"></param>
        public Chunk(byte[] bytes)
        {
            int position = 0;

            Tag      = NBTJ.Parse(bytes, ref position)[0];
            BlockMap = GetBlockMap();
            File.WriteAllText("nbtout.txt", Tag.ToString());
        }
Пример #2
0
        /// <summary>
        /// Parse the block pallete from a pallete NBTTag
        /// </summary>
        /// <param name="palleteTag">The tag to parse fom</param>
        /// <returns>A list of the blocks in the pallete as strings</returns>
        private string[] ParsePallete(NBTTag palleteTag)
        {
            List <string> pallete = new List <string>();

            foreach (NBTTag item in (List <NBTTag>)palleteTag.Payload)
            {
                NBTTag stringTag = ((List <NBTTag>)item.Payload)[0];
                pallete.Add((string)stringTag.Payload);
            }
            return(pallete.ToArray());
        }
Пример #3
0
        public static NBTTag ProcessPayload(int tagID, byte[] bytes, ref int position, string name = "")
        {
            NBTTag tag;

            switch (tagID)
            {
            case 1:     // Signed Byte
            {
                tag       = new NBTTag(name, (sbyte)bytes[position]);
                position += 1;
            }
            break;

            case 2:     // Signed Short
            {
                byte[] numBytes = bytes.Skip(position).Take(2).Reverse().ToArray();
                tag       = new NBTTag(name, BitConverter.ToInt16(numBytes, 0));
                position += 2;
            }
            break;

            case 3:     // Signed Int
            {
                byte[] numBytes = bytes.Skip(position).Take(4).Reverse().ToArray();
                tag       = new NBTTag(name, BitConverter.ToInt32(numBytes, 0));
                position += 4;
            }
            break;

            case 4:     // Signed Long
            {
                byte[] numBytes = bytes.Skip(position).Take(8).Reverse().ToArray();
                tag       = new NBTTag(name, BitConverter.ToInt64(numBytes, 0));
                position += 8;
            }
            break;

            case 5:     // Signed Float
            {
                byte[] numBytes = bytes.Skip(position).Take(4).Reverse().ToArray();
                tag       = new NBTTag(name, BitConverter.ToSingle(numBytes, 0));
                position += 4;
            }
            break;

            case 6:     // Signed Double
            {
                byte[] numBytes = bytes.Skip(position).Take(8).Reverse().ToArray();
                tag       = new NBTTag(name, BitConverter.ToDouble(numBytes, 0));
                position += 8;
            }
            break;

            case 7:     // Array of Signed Bytes
            {
                byte[] numBytes    = bytes.Skip(position).Take(4).Reverse().ToArray();
                int    arrayLength = BitConverter.ToInt32(numBytes, 0);
                position += 4;
                sbyte[] sbyteArray = bytes.Skip(position).Take(arrayLength).Select(i => (sbyte)i).ToArray();
                position += arrayLength;
                tag       = new NBTTag(name, sbyteArray);
            }
            break;

            case 8:     // String
            {
                byte[] numBytes     = bytes.Skip(position).Take(2).Reverse().ToArray();
                int    stringLength = BitConverter.ToInt16(numBytes, 0);
                position += 2;
                string str = Encoding.UTF8.GetString(bytes, position, stringLength);
                position += stringLength;
                tag       = new NBTTag(name, str);
            }
            break;

            case 9:     // Tag List -> recursively solve, same way as compound tags
            {
                byte childID = bytes[position];
                position += 1;
                byte[] numBytes     = bytes.Skip(position).Take(4).Reverse().ToArray();
                int    numberOfTags = BitConverter.ToInt32(numBytes, 0);
                position += 4;
                List <NBTTag> children = new List <NBTTag>();
                for (int i = 0; i < numberOfTags; i++)
                {
                    children.Add(ProcessPayload(childID, bytes, ref position));
                }
                tag = new NBTTag(name, children);
            }
            break;

            case 10:     // Compund Tag
            {
                List <NBTTag> children = Parse(bytes, ref position);
                tag = new NBTTag(name, children);
            }
            break;

            case 11:     // Int array
            {
                byte[] numBytes    = bytes.Skip(position).Take(4).Reverse().ToArray();
                int    arrayLength = BitConverter.ToInt32(numBytes, 0);
                position += 4;
                int[] array = new int[arrayLength];
                for (int i = 0; i < arrayLength; i++)
                {
                    numBytes  = bytes.Skip(position).Take(4).Reverse().ToArray();
                    array[i]  = BitConverter.ToInt32(numBytes, 0);
                    position += 4;
                }
                tag = new NBTTag(name, array);
            }
            break;

            case 12:    // Long Array
            {
                byte[] numBytes    = bytes.Skip(position).Take(4).Reverse().ToArray();
                int    arrayLength = BitConverter.ToInt32(numBytes, 0);
                position += 4;
                if (name == "BlockStates")
                {
                    byte[] array = bytes.Skip(position).Take(arrayLength * 8).ToArray();
                    tag       = new NBTTag(name, array);
                    position += arrayLength * 8;
                }
                else
                {
                    long[] array = new long[arrayLength];
                    for (int i = 0; i < arrayLength; i++)
                    {
                        numBytes  = bytes.Skip(position).Take(8).Reverse().ToArray();
                        array[i]  = BitConverter.ToInt64(numBytes, 0);
                        position += 8;
                    }
                    tag = new NBTTag(name, array);
                }
            }
            break;

            default:
            {
                tag = new NBTTag(string.Format("{0} - not Recognised", tagID), null);
            }
            break;
            }
            return(tag);
        }
Пример #4
0
        /// <summary>
        /// Generate the blockmap - must be called aftter the Tag is set
        /// </summary>
        /// <returns>The generated blockmap</returns>
        public string[,] GetBlockMap()
        {
            if (Tag is null)
            {
                throw new NullReferenceException("The Tag of the chunk is not set!");
            }

            // get sections as a stack ordered by Y index
            Stack <NBTTag> sections = new Stack <NBTTag>(((List <NBTTag>)Tag.Search("Sections").Payload)
                                                         .OrderBy(element => element.Search("Y").Payload)
                                                         );
            // get the highest non-air section in the chunk

            // generate queue of all x,z coordinate paris in the chunk
            List <Tuple <int, int> > unresolved = new List <Tuple <int, int> >();

            for (int x = 0; x < 16; x++)
            {
                for (int z = 0; z < 16; z++)
                {
                    unresolved.Add(new Tuple <int, int>(x, z));
                }
            }
            string[,] blockMap = new string[16, 16];

            // repeat this until all blocks are resolved or run out of sections.
            do
            {
                if (sections.Count <= 0)
                {
                    break;
                }
                // shallow copy unresolved coords to coordinate queue then reset unresolved queue
                List <Tuple <int, int> > coords = new List <Tuple <int, int> >(unresolved);
                unresolved = new List <Tuple <int, int> >();

                // Get next highest non-empty section of chunk
                NBTTag topSection = sections.Pop();
                while (((List <NBTTag>)topSection.Search("Palette").Payload).Count <= 1)
                {
                    topSection = sections.Pop();
                }

                Console.WriteLine(topSection);

                // Parse the pallete
                string[] pallete = ParsePallete(topSection.Search("Palette"));

                // get bytes containing block states and calculate bits per block
                byte[] blockStateBytes = (byte[])topSection.Search("BlockStates").Payload;
                int    bitsPerBlock    = NextPowerOfTwo(pallete.Length);
                //Console.WriteLine("Bits per block: {0}, {1}", bitsPerBlock, pallete.Length);

                for (int i = 0; i < coords.Count; i++)
                {
                    // for each x,z pair, find highest block in the section that isn't air
                    int    y     = 15;
                    string block = "";
                    do
                    {
                        if (y < 0) //if all block in column are empty, add to unersolved queue
                        {
                            unresolved.Add(coords[i]);
                            break;
                        }
                        block = pallete[NumFromBytes(bitsPerBlock, y * 256 + coords[i].Item2 * 16 + coords[i].Item1, blockStateBytes)];
                        y--;
                    } while (block == "minecraft:air");

                    // write block to the 2d array. if empty, air is written to it.
                    blockMap[coords[i].Item1, coords[i].Item2] = block;
                }
                Console.WriteLine("Unresolved: {0}", unresolved.Count);
            }while (unresolved.Count > 0);
            return(blockMap);
        }