Giter Club home page Giter Club logo

fnbt's People

Contributors

aphistic avatar ddevault avatar flori-schwa avatar mstefarov avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

fnbt's Issues

System.NullReferenceException:

Καταγραφή
This is where i get the exception.

With most schematic files it works ok. But with some other schematic files i get this error "System.NullReferenceException"

Converting NBT

How can I convert all the NBT data to a byte[]

nbtFile.RootTag.ByteArrayValue isn't allowing me to do so

Unable to create a new region

Hi, I've been trying to create a region (.mca) file from scratch, but I just can't get it to work.
I'm using "NBTExplorer" to read the file I'm creating for testing.

When I load the file in NBTExplorer, I can see the chunk that I'm creating but not any tags inside it.
So it seems that everything works fine, except the NBT part.

I'd appreciate any help with this issue.
Here's the class to create a region file:

public class RegionFile
    {
        private const int SECTOR_BYTES = 4096;
        private const int SECTOR_INTS = SECTOR_BYTES / 4;
        private const int CHUNK_HEADER_SIZE = 5;
        private const int VERSION_DEFLATE = 2;


    private static byte[] emptySector = new byte[SECTOR_BYTES];
    private static int[] offsets;
    private static int[] timestamps;

    private List<bool> sectorFree;

    private static readonly DateTime Jan1st1970 = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);

    public RegionFile(string path)
    {
        offsets = new int[SECTOR_INTS];
        timestamps = new int[SECTOR_INTS];

        try
        {
            using (BinaryWriter file = new BinaryWriter(File.Open(path, FileMode.Create)))
            {
                if (file.BaseStream.Length < SECTOR_BYTES)
                {
                    /* we need to write the chunk offset table */
                    for (int i = 0; i < SECTOR_INTS; ++i)
                    {
                        file.Write((int)0);
                    }
                    // write another sector for the timestamp info
                    for (int i = 0; i < SECTOR_INTS; ++i)
                    {
                        file.Write((int)0);
                    }
                }

                if ((file.BaseStream.Length & 0xfff) != 0)
                {
                    /* the file size is not a multiple of 4KB, grow it */
                    for (int i = 0; i < (file.BaseStream.Length & 0xfff); ++i)
                    {
                        file.Write((byte)0);
                    }
                }
            }

            using (BinaryReader file = new BinaryReader(File.Open(path, FileMode.Open)))
            {
                /* set up the available sector map */
                int nSectors = (int)file.BaseStream.Length / SECTOR_BYTES;
                sectorFree = new List<bool>(nSectors);

                for (int i = 0; i < nSectors; ++i)
                {
                    sectorFree.Add(true);
                }

                sectorFree[0] = false; // chunk offset table
                sectorFree[1] = false; // for the last modified info

                file.BaseStream.Position = 0;
                for (int i = 0; i < SECTOR_INTS; ++i)
                {
                    int offset = file.ReadInt32();
                    offsets[i] = offset;
                    if (offset != 0 && (offset >> 8) + (offset & 0xFF) <= sectorFree.Count())
                    {
                        for (int sectorNum = 0; sectorNum < (offset & 0xFF); ++sectorNum)
                        {
                            sectorFree[(offset >> 8) + sectorNum] = false;
                        }
                    }
                }
                for (int i = 0; i < SECTOR_INTS; ++i)
                {
                    int lastModValue = file.ReadInt32();
                    timestamps[i] = lastModValue;
                }
            }
        }
        catch (IOException e)
        {
            MessageBox.Show(e.ToString());
        }

        // Nbt Arrays
        byte[] biomeBytes = new byte[256];
        for (int i = 0; i < 256; ++i)
        {
            biomeBytes[i] = 0;
        }

        int[] heightMapInts = new int[256];
        for (int i = 0; i < 256; ++i)
        {
            heightMapInts[i] = 0;
        }

        byte[] blockBytes = new byte[4096];
        for (int i = 0; i < 4096; ++i)
        {
            blockBytes[i] = 56;
        }

        byte[] dataBytes = new byte[2048];
        for (int i = 0; i < 2048; ++i)
        {
            dataBytes[i] = 0;
        }

        byte[] blockLightBytes = new byte[2048];
        for (int i = 0; i < 2048; ++i)
        {
            blockLightBytes[i] = 0;
        }

        byte[] skyLightBytes = new byte[2048];
        for (int i = 0; i < 2048; ++i)
        {
            skyLightBytes[i] = 0;
        }

        NbtCompound chunk = new NbtCompound("Chunk") {
            new NbtInt("DataVersion", 176),
            new NbtCompound("Level") {
                new NbtInt("xPos", 0),
                new NbtInt("zPos", 0),
                new NbtLong("LastUpdate", 0),
                new NbtByte("LightPopulated", 0),
                new NbtByte("TerrainPopulated", 1),
                new NbtByte("V", 1),
                new NbtLong("InhabitedTime", 0),
                new NbtByteArray("Biomes", biomeBytes),
                new NbtIntArray("HeightMap", heightMapInts),

                new NbtList("Sections", NbtTagType.Compound)
                {
                    new NbtCompound()
                    {
                        new NbtByte("Y", 0),
                        new NbtByteArray("Blocks", blockBytes),
                        new NbtByteArray("Data", dataBytes),
                        new NbtByteArray("BlockLight", blockLightBytes),
                        new NbtByteArray("SkyLight", skyLightBytes)
                    },
                    new NbtCompound()
                    {
                        new NbtByte("Y", 1),
                        new NbtByteArray("Blocks", blockBytes),
                        new NbtByteArray("Data", dataBytes),
                        new NbtByteArray("BlockLight", blockLightBytes),
                        new NbtByteArray("SkyLight", skyLightBytes)
                    },
                    new NbtCompound()
                    {
                        new NbtByte("Y", 2),
                        new NbtByteArray("Blocks", blockBytes),
                        new NbtByteArray("Data", dataBytes),
                        new NbtByteArray("BlockLight", blockLightBytes),
                        new NbtByteArray("SkyLight", skyLightBytes)
                    }
                },

                new NbtList("Entities", NbtTagType.Compound) {

                },

                new NbtList("TileEntities", NbtTagType.Compound) {

                }
            }
        };

        NbtFile nbtFile = new NbtFile(chunk);
        byte[] data = nbtFile.SaveToBuffer(NbtCompression.ZLib);
        using (BinaryWriter file = new BinaryWriter(new FileStream(path, FileMode.Open)))
        {
            WriteChunk(file, 0, 0, data, data.Length);
        }
    }

    void WriteChunk(BinaryWriter file, int x, int z, byte[] data, int length)
    {
        try
        {
            int offset = getOffset(x, z);
            int sectorNumber = offset >> 8;
            int sectorsAllocated = offset & 0xFF;
            int sectorsNeeded = (length + CHUNK_HEADER_SIZE) / SECTOR_BYTES + 1;

            // Maximum chunk size is 1MB
            if (sectorsNeeded >= 256)
            {
                return;
            }

            if (sectorNumber != 0 && sectorsAllocated == sectorsNeeded)
            {
                WriteChunk(file, sectorNumber, data, length);
            }
            else
            {
                for (int i = 0; i < sectorsAllocated; ++i)
                {
                    sectorFree[sectorNumber + i] = true;
                }

                int runStart = sectorFree.IndexOf(true);
                int runLength = 0;
                if (runStart != -1)
                {
                    for (int i = runStart; i < sectorFree.Count(); ++i)
                    {
                        if (runLength != 0)
                        {
                            if (sectorFree[i])
                                runLength++;
                            else
                                runLength = 0;
                        }
                        else if (sectorFree[i])
                        {
                            runStart = i;
                            runLength = 1;
                        }
                        if (runLength >= sectorsNeeded)
                        {
                            break;
                        }
                    }
                }

                if (runLength >= sectorsNeeded)
                {
                    /* We found a free space large enough */
                    sectorNumber = runStart;
                    SetOffset(file, x, z, (sectorNumber << 8) | sectorsNeeded);
                    for (int i = 0; i < sectorsNeeded; ++i)
                    {
                        sectorFree[sectorNumber + i] = false;
                    }
                    WriteChunk(file, sectorNumber, data, length);
                }
                else {
                    // No free space large enough found; we need to grow the file

                    file.BaseStream.Position = (int)file.BaseStream.Length;
                    sectorNumber = sectorFree.Count;
                    for (int i = 0; i < sectorsNeeded; ++i)
                    {
                        file.Write(emptySector);
                        sectorFree.Add(false);
                    }

                    WriteChunk(file, sectorNumber, data, length);
                    SetOffset(file, x, z, (sectorNumber << 8) | sectorsNeeded);
                }

                SetTimestamp(file, x, z, CurrentTimeMillis());
            }
        }
        catch (IOException e)
        {
            MessageBox.Show(e.ToString());
        }
    }

    private void WriteChunk(BinaryWriter file, int sectorNumber, byte[] data, int length)
    {
        file.BaseStream.Position = sectorNumber * SECTOR_BYTES;
        file.Write(length + 1); // Chunk length
        file.Write((byte)VERSION_DEFLATE); // Chunk version number
        file.Write(data, 0, length);
    }

    int getOffset(int x, int z)
    {
        return offsets[x + z * 32];
    }

    void SetOffset(BinaryWriter file, int x, int z, int offset)
    {
        offsets[x + z * 32] = offset;
        file.BaseStream.Position = (x + z * 32) * 4;
        file.Write(offset);
    }

    void SetTimestamp(BinaryWriter file, int x, int z, int value)
    {
        timestamps[x + z * 32] = value;
        file.BaseStream.Position = SECTOR_BYTES + (x + z * 32) * 4;
        file.Write(value);
    }

    public static int CurrentTimeMillis()
    {
        return (int)(DateTime.UtcNow - Jan1st1970).TotalMilliseconds;
    }
}

NbtSerializer

Automate serialization to/from NBT for user-defined classes.

Possibility of reading too many bytes when reading NBT strings

In NbtBinaryReader.cs:

while (stringBytesRead < length) {
  int bytesReadThisTime = BaseStream.Read(stringConversionBuffer, stringBytesRead, length);
  if (bytesReadThisTime == 0) {
    throw new EndOfStreamException();
  }
  stringBytesRead += bytesReadThisTime;
}

Should be length - stringBytesRead instead of just length

MCPE changed the NBT format

MiNET rely heavily on fnbt for all things NBT. Mostly because of its exceptional speed. Now, with the release of Minecraft Pocket Edition 0.16, Mojang changed the encoding of int to use google protobuf varint instead. Can you consider adding these changes to fnbt as an option.

If for instance would make the creation of NbtBinaryWriter (and reader) through a callback (factory) method, I could implement my own stuff without having to bother you with the details of the specific changes.

Conversion from SNBT to NBT

For now, it's impossible to convert SNBT file format to NBT file using fNbt and vise versa. I would like to know if you can work on this feature ?

Add option for max length prefix size

MCPE packet 0x38 originating from the client sets a Minecraft block metadata by sending its nbt.

Clients may fool servers and cause performance issues by spamming max size length prefixes in that nbt. fNbt will allocate these massive arrays and this may cause OutOfMemoryExceptions.

Affected tags:

  • Byte array
  • String
  • List
  • Int array

I suggest adding a MaxBufferSize property to NbtBinaryReader with a convenience proxy in NbtFile.

Support .NET Standard

Create a version of fNbt that works with .NET Core, by excluding some non-portable functionality via conditional compilation. Porting the whole thing to .NET core would not be practical without sacrificing performance, but offering an option would be good.

NbtConvert

Utility class for easy access to automated serialization, without the need to create temporary NbtSerializers.

Minecraft: Windows 10 Edition Compatibility issue

I just tried using fNbt to load the level.dat file for a Minecraft Windows 10 Edition save and was met with two exceptions.

The first was that it was unable to detect the compression format:

System.IO.InvalidDataException: Could not auto-detect compression format.
   at fNbt.NbtFile.DetectCompression(Stream stream)

I tried to remedy that by explicitly calling nbtFile.LoadFromFile(levelDatFile, NbtCompression.None, null). This worked, but the next error I encountered was:

fNbt.NbtFormatException: Given NBT stream does not start with a TAG_Compound
   at fNbt.NbtFile.LoadFromStreamInternal(Stream stream, TagSelector tagSelector)

So, whatever Mojang did for the Windows 10 Edition of Minecraft seems to have introduced some compatibility issues with fNbt.

Comparing

Can you add method to compare two compounds?

Support For Long Arrays?

Hello! I was trying to read .litematic file from Litematica Mod and found out that fNbt does not support long array type.

Any plan for supporting long arrays in the future?

Open region files

Is it possible to open region files (.mca) with fNbt? It fails with this message:

System.IO.InvalidDataException: 'Could not auto-detect compression format.'

(edit: nvm, rolled my own)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.