LoadFromStream() public method

Loads NBT data from a stream. Existing RootTag will be replaced
is null. If an unrecognized/unsupported value was given for . If is set to AutoDetect, but the stream is not seekable. If file ended earlier than expected. If file compression could not be detected, decompressing failed, or given stream does not support reading. If an error occurred while parsing data in NBT format.
public LoadFromStream ( [ stream, NbtCompression compression ) : long
stream [ Stream from which data will be loaded. If compression is set to AutoDetect, this stream must support seeking.
compression NbtCompression Compression method to use for loading/saving this file.
return long
Example #1
0
        public void Load()
        {
            if (IsCorrupt || IsExternal)
            {
                return;
            }
            var stream = Region.GetStream();

            stream.Seek(Offset + 4, SeekOrigin.Begin);
            int compression = stream.ReadByte();

            if (compression == -1)
            {
                IsCorrupt = true;
                Remove();
            }
            else
            {
                if ((compression & (1 << 7)) != 0)
                {
                    IsExternal          = true;
                    ExternalCompression = (byte)compression;
                }
                else
                {
                    var file = new fNbt.NbtFile();
                    try
                    {
                        file.LoadFromStream(stream, NbtCompression.AutoDetect);
                        Compression = file.FileCompression;
                        SetData(file.GetRootTag <NbtCompound>());
                    }
                    catch
                    {
                        IsCorrupt = true;
                        Remove();
                    }
                }
            }
            stream.Dispose();
            OnLoaded?.Invoke(this, EventArgs.Empty);
        }
Example #2
0
 /// <summary>
 /// Retrieves the requested chunk from the region, or
 /// generates it if a world generator is provided.
 /// </summary>
 /// <param name="position">The position of the requested local chunk coordinates.</param>
 public Chunk GetChunk(Vector3 position)
 {
     // TODO: This could use some refactoring
     lock (Chunks)
     {
         if (!Chunks.ContainsKey(position))
         {
             if (regionFile != null)
             {
                 // Search the stream for that region
                 lock (regionFile)
                 {
                     var chunkData = GetChunkFromTable(position);
                     if (chunkData == null)
                     {
                         if (WorldGenerator == null)
                             throw new ArgumentException("The requested chunk is not loaded.", "position");
                         GenerateChunk(position);
                         return Chunks[position];
                     }
                     regionFile.Seek(chunkData.Item1, SeekOrigin.Begin);
                     int length = new MinecraftStream(regionFile).ReadInt32(); // TODO: Avoid making new objects here, and in the WriteInt32
                     int compressionMode = regionFile.ReadByte();
                     switch (compressionMode)
                     {
                         case 1: // gzip
                             break;
                         case 2: // zlib
                             var nbt = new NbtFile();
                             nbt.LoadFromStream(regionFile, NbtCompression.ZLib, null);
                             var chunk = Chunk.FromNbt(position, nbt);
                             chunk.ParentRegion = this;
                             Chunks.Add(position, chunk);
                             break;
                         default:
                             throw new InvalidDataException("Invalid compression scheme provided by region file.");
                     }
                 }
             }
             else if (WorldGenerator == null)
                 throw new ArgumentException("The requested chunk is not loaded.", "position");
             else
                 Chunks.Add(position, WorldGenerator.GenerateChunk(position, this));
         }
         return Chunks[position];
     }
 }
Example #3
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\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;
            }
        }
Example #4
0
        public ChunkColumn GetChunk(int X, int Z)
        {
            var width = 32;
            var depth = 32;

            var rx = X >> 5;
            var rz = Z >> 5;

            var filePath = Path.Combine(_basePath, string.Format(@"region\r.{0}.{1}.mca", rx, rz));

            if (!File.Exists(filePath)) return _backEndGenerator.GenerateChunkColumn(new Vector2(X, Z));

            using (var regionFile = File.OpenRead(filePath))
            {
                var buffer = new byte[8192];

                regionFile.Read(buffer, 0, 8192);

                var xi = (X%width);
                if (xi < 0) xi += 32;
                var zi = (Z%depth);
                if (zi < 0) zi += 32;
                var tableOffset = (xi + zi*width)*4;

                regionFile.Seek(tableOffset, SeekOrigin.Begin);

                var offsetBuffer = new byte[4];
                regionFile.Read(offsetBuffer, 0, 3);
                Array.Reverse(offsetBuffer);
                var offset = BitConverter.ToInt32(offsetBuffer, 0) << 4;

                var length = regionFile.ReadByte();

                //if (offset == 0 || length == 0) return _backEndGenerator.GenerateChunkColumn(new Vector2(X, Z));

                if (offset == 0 || length == 0)
                {
                    return _backEndGenerator.GenerateChunkColumn(new Vector2(X,Z));
                }

                regionFile.Seek(offset, SeekOrigin.Begin);
                var waste = new byte[4];
                regionFile.Read(waste, 0, 4);
                var compressionMode = regionFile.ReadByte();

                var nbt = new NbtFile();
                nbt.LoadFromStream(regionFile, NbtCompression.ZLib);

                var dataTag = nbt.RootTag["Level"];

                var sections = dataTag["Sections"] as NbtList;

                var chunk = new ChunkColumn
                {
                    X = X,
                    Z = Z,
                    BiomeId = dataTag["Biomes"].ByteArrayValue
                };

                for (var 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 (var sectionTag in sections)
                {
                    var sy = sectionTag["Y"].ByteValue*16;
                    var blocks = sectionTag["Blocks"].ByteArrayValue;
                    var data = sectionTag["Data"].ByteArrayValue;
                    var addTag = sectionTag["Add"];
                    var adddata = new byte[2048];
                    if (addTag != null) adddata = addTag.ByteArrayValue;
                    var blockLight = sectionTag["BlockLight"].ByteArrayValue;
                    var skyLight = sectionTag["SkyLight"].ByteArrayValue;

                    for (var x = 0; x < 16; x++)
                    {
                        for (var z = 0; z < 16; z++)
                        {
                            for (var y = 0; y < 16; y++)
                            {
                                var yi = sy + y - _waterOffsetY;
                                if (yi < 0 || yi >= 256) continue;

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

                                var b = BlockFactory.GetBlockById((ushort) blockId);
                                b.Metadata = Nibble4(data, anvilIndex);
                                chunk.SetBlock(x, yi, z, b);
                                chunk.SetBlocklight(x, yi, z, Nibble4(blockLight, anvilIndex));
                                chunk.SetSkylight(x, yi, z, Nibble4(skyLight, anvilIndex));
                            }
                        }
                    }
                }

                var entities = dataTag["Entities"] as NbtList;
                var tileEntities = dataTag["TileEntities"] as NbtList;

                if (tileEntities != null)
                {
                    foreach (var nbtTag in tileEntities)
                    {
                        var blockEntityTag = (NbtCompound)nbtTag;
                        string entityId = blockEntityTag["id"].StringValue;
                        int x = blockEntityTag["x"].IntValue;
                        int y = blockEntityTag["y"].IntValue - _waterOffsetY;
                        int z = blockEntityTag["z"].IntValue;
                        blockEntityTag["y"] = new NbtInt("y", y);

                        TileEntity blockEntity = TileEntityFactory.GetBlockEntityById(entityId);
                        if (blockEntity != null)
                        {
                            blockEntityTag.Name = string.Empty;
                            chunk.SetBlockEntity(new Vector3(x, y, z), blockEntityTag);
                        }
                    }
                }

                var tileTicks = dataTag["TileTicks"] as NbtList;

                chunk.IsDirty = false;
                return chunk;
            }
        }
Example #5
0
 /// <summary>
 /// Retrieves the requested chunk from the region, or
 /// generates it if a world generator is provided.
 /// </summary>
 /// <param name="position">The position of the requested local chunk coordinates.</param>
 public IChunk GetChunk(Coordinates2D position, bool generate = true)
 {
     // TODO: This could use some refactoring
     lock (Chunks)
     {
         if (!Chunks.ContainsKey(position))
         {
             if (regionFile != null)
             {
                 // Search the stream for that region
                 lock (regionFile)
                 {
                     var chunkData = GetChunkFromTable(position);
                     if (chunkData == null)
                     {
                         if (World.ChunkProvider == null)
                             throw new ArgumentException("The requested chunk is not loaded.", "position");
                         if (generate)
                             GenerateChunk(position);
                         else
                             return null;
                         return Chunks[position];
                     }
                     regionFile.Seek(chunkData.Item1, SeekOrigin.Begin);
                     /*int length = */
                     new MinecraftStream(regionFile).ReadInt32(); // TODO: Avoid making new objects here, and in the WriteInt32
                     int compressionMode = regionFile.ReadByte();
                     switch (compressionMode)
                     {
                         case 1: // gzip
                             throw new NotImplementedException("gzipped chunks are not implemented");
                         case 2: // zlib
                             var nbt = new NbtFile();
                             nbt.LoadFromStream(regionFile, NbtCompression.ZLib, null);
                             var chunk = Chunk.FromNbt(nbt);
                             Chunks.Add(position, chunk);
                             World.OnChunkLoaded(new ChunkLoadedEventArgs(chunk));
                             break;
                         default:
                             throw new InvalidDataException("Invalid compression scheme provided by region file.");
                     }
                 }
             }
             else if (World.ChunkProvider == null)
                 throw new ArgumentException("The requested chunk is not loaded.", "position");
             else
             {
                 if (generate)
                     GenerateChunk(position);
                 else
                     return null;
             }
         }
         return Chunks[position];
     }
 }
Example #6
0
        public PlayerEntity LoadPlayer(string name)
        {
            PlayerEntity entity = new PlayerEntity(Difficulty);
            if (LevelDirectory == null || !File.Exists(Path.Combine(LevelDirectory, "players", name + ".dat")))
            {
                // Return default player entity
                entity.Position = SpawnPoint;
                entity.SpawnPoint = SpawnPoint;
                entity.Position += new Vector3(0, PlayerEntity.Height, 0);
                entity.GameMode = GameMode;
                return entity;
            }
            
            var file = new NbtFile();
            using (Stream stream = File.Open(Path.Combine(LevelDirectory, "players", name + ".dat"), FileMode.Open))
                file.LoadFromStream(stream, NbtCompression.GZip, null);
            var data = file.RootTag;
            entity.OnGround = data.Get<NbtByte>("OnGround").Value == 1;
            entity.Air = data.Get<NbtShort>("Air").Value;
            entity.Health = data.Get<NbtShort>("Health").Value;
            var dimension = (Dimension)data.Get<NbtInt>("Dimension").Value; // TODO
            entity.Food = (short)data.Get<NbtInt>("foodLevel").Value;
            entity.XpLevel = data.Get<NbtInt>("XpLevel").Value;
            entity.XpTotal = data.Get<NbtInt>("XpTotal").Value;
            // TODO: Set velocity based on fall distance
            entity.FoodExhaustion = data.Get<NbtFloat>("foodExhaustionLevel").Value;
            entity.FoodSaturation = data.Get<NbtFloat>("foodSaturationLevel").Value;
            entity.XpProgress = data.Get<NbtFloat>("XpP").Value;

            var equipment = data.Get<NbtList>("Equipment");
            var inventory = data.Get<NbtList>("Inventory");
            var motion = data.Get<NbtList>("Motion");
            var pos = data.Get<NbtList>("Pos");
            var rotation = data.Get<NbtList>("Rotation");
            var abilities = data.Get<NbtCompound>("abilities");

            // Appears to be unused, is overriden by the inventory contents
            // foreach (var item in equipment.Tags)

            foreach (var item in inventory)
            {
                var slot = ItemStack.FromNbt((NbtCompound)item);
                slot.Index = DataSlotToNetworkSlot(slot.Index);
                entity.Inventory[slot.Index] = slot;
            }

            entity.Velocity = new Vector3(
                ((NbtDouble)motion[0]).Value,
                ((NbtDouble)motion[1]).Value,
                ((NbtDouble)motion[2]).Value);

            entity.Position = new Vector3(
                ((NbtDouble)pos[0]).Value,
                ((NbtDouble)pos[1]).Value,
                ((NbtDouble)pos[2]).Value);

            if (data.Get<NbtInt>("SpawnX") != null)
            {
                entity.SpawnPoint = new Vector3(
                    data.Get<NbtInt>("SpawnX").Value,
                    data.Get<NbtInt>("SpawnY").Value,
                    data.Get<NbtInt>("SpawnZ").Value);
            }

            entity.Yaw = ((NbtFloat)rotation[0]).Value;
            entity.Pitch = ((NbtFloat)rotation[1]).Value;

            // TODO: Abilities

            return entity;
        }
Example #7
0
        private void LoadFromFile(string directory)
        {
            NbtFile file = new NbtFile();
            using (var stream = File.Open(Path.Combine(LevelDirectory, "level.dat"), FileMode.Open))
                file.LoadFromStream(stream, NbtCompression.None, null);
            var data = file.RootTag.Get<NbtCompound>("Data");
            var serializer = new NbtSerializer(typeof(SavedLevel));
            SavedLevel level = (SavedLevel)serializer.Deserialize(data);
            Name = level.LevelName;
            Time = level.Time;
            GameMode = (GameMode)level.GameMode;
            MapFeatures = level.MapFeatures;
            Seed = level.Seed;
            // Find world generator
            string generatorName = level.GeneratorName;
            WorldGenerator = GetGenerator(generatorName);
            WorldGenerator.Seed = Seed;
                GeneratorOptions = level.GeneratorOptions;
            WorldGenerator.Initialize(this);

            SpawnPoint = level.SpawnPoint;

            World = new World(this, WorldGenerator, Path.Combine(directory, "region"));
        }
Example #8
0
        public void Save()
        {
            NbtFile file = new NbtFile();

            var serializer = new NbtSerializer(typeof(SavedLevel));
            var level = new SavedLevel
            {
                IsRaining = Raining,
                GeneratorVersion = 0,
                Time = Time,
                GameMode = (int)GameMode,
                MapFeatures = MapFeatures,
                GeneratorName = WorldGenerator.GeneratorName,
                Initialized = true,
                Seed = Seed,
                SpawnPoint = SpawnPoint,
                SizeOnDisk = 0,
                ThunderTime = ThunderTime,
                RainTime = RainTime,
                Version = 19133,
                Thundering = Thundering,
                LevelName = Name,
                LastPlayed = DateTime.UtcNow.Ticks
            };
            if (!string.IsNullOrEmpty(PlayerName))
            {
                if (File.Exists(Path.Combine(LevelDirectory, "players", PlayerName + ".dat")))
                {
                    var player = new NbtFile();
                    using (Stream stream = File.Open(Path.Combine(LevelDirectory, "players", PlayerName + ".dat"), FileMode.Open))
                        player.LoadFromStream(stream, NbtCompression.GZip, null);
                    level.Player = player.RootTag;
                    level.Player.Name = "Player";
                }
            }
            var data = serializer.Serialize(level);
            file.RootTag = new NbtCompound("");
            file.RootTag.Add(data);
            using (var stream = File.Create(Path.Combine(LevelDirectory, "level.dat")))
                file.SaveToStream(stream, NbtCompression.GZip);
            if (World.Directory == null)
                World.Save(Path.Combine(LevelDirectory, "region"));
            else
                World.Save();
        }