/// <inheritdoc />
        public Structure Load(string filename)
        {
            using (var fs = File.OpenRead(filename))
                using (var bs = new BrotliStream(fs, CompressionMode.Decompress))
                    using (var s = new BinaryReader(bs))
                    {
                        var idMap   = new TranslationMap();
                        var diffMap = new DiffMap();

                        var identBytes = new byte[ScarifStructure.Magic.Length];
                        var read       = s.Read(identBytes, 0, identBytes.Length);
                        var ident      = Encoding.UTF8.GetString(identBytes);
                        if (ident != ScarifStructure.Magic || read != identBytes.Length)
                        {
                            throw new IOException("Input file not SCARIF structure");
                        }

                        var version = s.ReadInt32();
                        if (version != 1)
                        {
                            throw new IOException("Input file not SCARIF v1");
                        }
                        var numChunks       = s.ReadInt32();
                        var numIdMapEntries = s.ReadInt32();

                        for (var entryIdx = 0; entryIdx < numIdMapEntries; entryIdx++)
                        {
                            var id   = s.ReadInt16();
                            var name = ReadNullTerminatedString(s);
                            idMap.Add(id, name);
                        }

                        var lowestPos  = new BlockPos(int.MaxValue, int.MaxValue, int.MaxValue);
                        var highestPos = new BlockPos(int.MinValue, int.MinValue, int.MinValue);

                        for (var chunkIdx = 0; chunkIdx < numChunks; chunkIdx++)
                        {
                            var chunkX    = s.ReadInt32();
                            var chunkZ    = s.ReadInt32();
                            var numBlocks = s.ReadInt32();

                            var blocks = new Dictionary <BlockPos, Block>();

                            for (var blockIdx = 0; blockIdx < numBlocks; blockIdx++)
                            {
                                // Format:
                                // 0b 0000 1111
                                //    xxxx zzzz
                                var xz = s.ReadByte();

                                var x = (byte)((xz & 0xF0) >> 4);
                                var z = (byte)(xz & 0x0F);
                                var y = s.ReadByte();

                                EnforceBounds(chunkX * 16 + x, y, chunkZ * 16 + z, ref lowestPos, ref highestPos);

                                var id    = s.ReadInt16();
                                var flags = (BlockFlags)s.ReadByte();

                                byte    metadata = 0;
                                NbtTree tileTag  = null;

                                if (flags.Has(BlockFlags.Metadata))
                                {
                                    metadata = s.ReadByte();
                                }
                                if (flags.Has(BlockFlags.Nbt))
                                {
                                    var len = s.ReadInt32();
                                    if (len <= 0)
                                    {
                                        throw new IOException("Zero-length NBT present");
                                    }
                                    var bytes = s.ReadBytes(len);
                                    using (var ms = new MemoryStream(bytes))
                                    {
                                        tileTag = new NbtTree(ms);
                                    }
                                }

                                if (idMap.ContainsKey(id))
                                {
                                    blocks[new BlockPos(x, y, z)] = new Block(idMap.TranslateBlock(id), metadata, tileTag?.Root);
                                }
                                else
                                {
                                    throw new IOException($"Unknown block ID found: {id}");
                                }
                            }

                            diffMap.Add(new ChunkPosition(chunkX, chunkZ), blocks);
                        }

                        return(new ScarifStructure(idMap, diffMap, lowestPos, highestPos));
                    }
        }
Exemple #2
0
 private static string TranslateBlockId(TranslationMap map, int id)
 {
     return(map.ContainsKey((short)id) ? map[(short)id] : $"unknown:{id}");
 }