diff --git a/Substrate/SubstrateCS/Source/BlockInterface.cs b/Substrate/SubstrateCS/Source/BlockInterface.cs index 67f68ab..f5adaab 100644 --- a/Substrate/SubstrateCS/Source/BlockInterface.cs +++ b/Substrate/SubstrateCS/Source/BlockInterface.cs @@ -49,4 +49,9 @@ namespace Substrate bool SetTileEntity (int lx, int ly, int lz, TileEntity te); bool ClearTileEntity (int lx, int ly, int lz); } + + public interface IBlockManager : IBlockContainer + { + + } } diff --git a/Substrate/SubstrateCS/Source/BlockManager.cs b/Substrate/SubstrateCS/Source/BlockManager.cs index 19c8154..1ec42d4 100644 --- a/Substrate/SubstrateCS/Source/BlockManager.cs +++ b/Substrate/SubstrateCS/Source/BlockManager.cs @@ -13,7 +13,7 @@ namespace Substrate bool SetBlock (int x, int y, int z, Block block); }*/ - public class BlockManager : IBlockContainer + public class BlockManager : IBlockManager { public const int MIN_X = -32000000; public const int MAX_X = 32000000; @@ -36,11 +36,11 @@ namespace Substrate public static bool EnforceDataLimits = true; - protected ChunkManager _chunkMan; + protected IChunkManager _chunkMan; protected ChunkRef _cache; - public BlockManager (ChunkManager cm) + public BlockManager (IChunkManager cm) { _chunkMan = cm; } diff --git a/Substrate/SubstrateCS/Source/ChunkFileManager.cs b/Substrate/SubstrateCS/Source/ChunkFileManager.cs index 7e9cfa4..b3184b0 100644 --- a/Substrate/SubstrateCS/Source/ChunkFileManager.cs +++ b/Substrate/SubstrateCS/Source/ChunkFileManager.cs @@ -7,7 +7,7 @@ namespace Substrate { using NBT; - public class ChunkFileManager : IChunkContainer, IChunkCache + public class ChunkFileManager : IChunkManager, IChunkCache { protected string _mapPath; @@ -29,7 +29,7 @@ namespace Substrate protected NBT_Tree GetChunkTree (int cx, int cz) { ChunkFile cf = GetChunkFile(cx, cz); - Stream nbtstr = cf.GetChunkDataInputStream(); + Stream nbtstr = cf.GetDataInputStream(); if (nbtstr == null) { return null; } @@ -40,7 +40,7 @@ namespace Substrate protected bool SaveChunkTree (int cx, int cz, NBT_Tree tree) { ChunkFile cf = GetChunkFile(cx, cz); - Stream zipstr = cf.GetChunkDataOutputStream(); + Stream zipstr = cf.GetDataOutputStream(); if (zipstr == null) { return false; } @@ -53,7 +53,7 @@ namespace Substrate protected Stream GetChunkOutStream (int cx, int cz) { - return new ChunkFile(_mapPath, cx, cz).GetChunkDataOutputStream(); + return new ChunkFile(_mapPath, cx, cz).GetDataOutputStream(); } #region IChunkContainer Members diff --git a/Substrate/SubstrateCS/Source/ChunkInterface.cs b/Substrate/SubstrateCS/Source/ChunkInterface.cs index 175b999..859144a 100644 --- a/Substrate/SubstrateCS/Source/ChunkInterface.cs +++ b/Substrate/SubstrateCS/Source/ChunkInterface.cs @@ -47,4 +47,9 @@ namespace Substrate int Save (); bool SaveChunk (Chunk chunk); } + + public interface IChunkManager : IChunkContainer + { + + } } diff --git a/Substrate/SubstrateCS/Source/ChunkManager.cs b/Substrate/SubstrateCS/Source/ChunkManager.cs index d36e64a..6b07f72 100644 --- a/Substrate/SubstrateCS/Source/ChunkManager.cs +++ b/Substrate/SubstrateCS/Source/ChunkManager.cs @@ -5,7 +5,7 @@ using System.Text; namespace Substrate { - public class ChunkManager : IChunkContainer, IChunkCache, IEnumerable + public class ChunkManager : IChunkManager, IChunkCache, IEnumerable { public const int REGION_XLEN = 32; public const int REGION_ZLEN = 32; diff --git a/Substrate/SubstrateCS/Source/Level.cs b/Substrate/SubstrateCS/Source/Level.cs new file mode 100644 index 0000000..4c58b43 --- /dev/null +++ b/Substrate/SubstrateCS/Source/Level.cs @@ -0,0 +1,232 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Substrate +{ + using NBT; + using Utility; + using System.IO; + + public class Level : INBTObject, ICopyable + { + public static NBTCompoundNode LevelSchema = new NBTCompoundNode() + { + new NBTCompoundNode("Data") + { + new NBTScalerNode("Time", NBT_Type.TAG_LONG), + new NBTScalerNode("LastPlayed", NBT_Type.TAG_LONG), + new NBTCompoundNode("Player", Player.PlayerSchema), + new NBTScalerNode("SpawnX", NBT_Type.TAG_INT), + new NBTScalerNode("SpawnY", NBT_Type.TAG_INT), + new NBTScalerNode("SpawnZ", NBT_Type.TAG_INT), + new NBTScalerNode("SizeOnDisk", NBT_Type.TAG_LONG), + new NBTScalerNode("RandomSeed", NBT_Type.TAG_LONG), + new NBTScalerNode("Version", NBT_Type.TAG_INT, NBTOptions.OPTIONAL), + new NBTScalerNode("LevelName", NBT_Type.TAG_STRING, NBTOptions.OPTIONAL), + }, + }; + + private World _world; + + private long _time; + private long _lastPlayed; + + private Player _player; + + private int _spawnX; + private int _spawnY; + private int _spawnZ; + + private long _sizeOnDisk; + private long _randomSeed; + private int? _version; + private string _name; + + public long Time + { + get { return _time; } + set { _time = value; } + } + + public long LastPlayed + { + get { return _lastPlayed; } + } + + public Player Player + { + get { return _player; } + set { _player = value; } + } + + public int SpawnX + { + get { return _spawnX; } + set { _spawnX = value; } + } + + public int SpawnY + { + get { return _spawnY; } + set { _spawnY = value; } + } + + public int SpawnZ + { + get { return _spawnZ; } + set { _spawnZ = value; } + } + + public long SizeOnDisk + { + get { return _sizeOnDisk; } + } + + public long RandomSeed + { + get { return _randomSeed; } + set { _randomSeed = value; } + } + + public int Version + { + get { return _version ?? 0; } + } + + public string LevelName + { + get { return _name; } + set { _name = value; } + } + + public Level (World world) + { + _world = world; + } + + public Level (Level p) + { + _world = p._world; + + _time = p._time; + _lastPlayed = p._lastPlayed; + _spawnX = p._spawnX; + _spawnY = p._spawnY; + _spawnZ = p._spawnZ; + _sizeOnDisk = p._sizeOnDisk; + _randomSeed = p._randomSeed; + _version = p._version; + _name = p._name; + + if (p._player != null) { + _player = p._player.Copy(); + } + } + + public bool Save () + { + if (_world == null) { + return false; + } + + NBTFile nf = new NBTFile(Path.Combine(_world.WorldPath, "level.dat")); + Stream zipstr = nf.GetDataOutputStream(); + if (zipstr == null) { + return false; + } + + new NBT_Tree(BuildTree() as NBT_Compound).WriteTo(zipstr); + zipstr.Close(); + + return true; + } + + + #region INBTObject Members + + public virtual Level LoadTree (NBT_Value tree) + { + NBT_Compound dtree = tree as NBT_Compound; + if (dtree == null) { + return null; + } + + NBT_Compound ctree = dtree["Data"].ToNBTCompound(); + + _time = ctree["Time"].ToNBTLong(); + _lastPlayed = ctree["LastPlayed"].ToNBTLong(); + + _player = new Player().LoadTree(ctree["Player"]); + + _spawnX = ctree["SpawnX"].ToNBTInt(); + _spawnY = ctree["SpawnY"].ToNBTInt(); + _spawnZ = ctree["SpawnZ"].ToNBTInt(); + + _sizeOnDisk = ctree["SizeOnDisk"].ToNBTLong(); + _randomSeed = ctree["RandomSeed"].ToNBTLong(); + + if (ctree.ContainsKey("Version")) { + _version = ctree["Version"].ToNBTInt(); + } + + if (ctree.ContainsKey("LevelName")) { + _name = ctree["LevelName"].ToNBTString(); + } + + return this; + } + + public virtual Level LoadTreeSafe (NBT_Value tree) + { + if (!ValidateTree(tree)) { + return null; + } + + return LoadTree(tree); + } + + public virtual NBT_Value BuildTree () + { + NBT_Compound data = new NBT_Compound(); + data["Time"] = new NBT_Long(_time); + data["LastPlayed"] = new NBT_Long(_lastPlayed); + data["Player"] = _player.BuildTree(); + data["SpawnX"] = new NBT_Int(_spawnX); + data["SpawnY"] = new NBT_Int(_spawnY); + data["SpawnZ"] = new NBT_Int(_spawnZ); + data["SizeOnDisk"] = new NBT_Long(_sizeOnDisk); + data["RandomSeed"] = new NBT_Long(_randomSeed); + + if (_version != null) { + data["Version"] = new NBT_Int(_version ?? 0); + } + + if (_name != null) { + data["LevelName"] = new NBT_String(_name); + } + + NBT_Compound tree = new NBT_Compound(); + tree.Add("Data", data); + + return tree; + } + + public virtual bool ValidateTree (NBT_Value tree) + { + return new NBTVerifier(tree, LevelSchema).Verify(); + } + + #endregion + + + #region ICopyable Members + + public virtual Level Copy () + { + return new Level(this); + } + + #endregion + } +} \ No newline at end of file diff --git a/Substrate/SubstrateCS/Source/NBTFile.cs b/Substrate/SubstrateCS/Source/NBTFile.cs index 3bc5a28..5a89721 100644 --- a/Substrate/SubstrateCS/Source/NBTFile.cs +++ b/Substrate/SubstrateCS/Source/NBTFile.cs @@ -28,7 +28,7 @@ namespace Substrate return true; } - public Stream GetChunkDataInputStream () + public Stream GetDataInputStream () { FileStream fstr = new FileStream(_filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); @@ -43,7 +43,7 @@ namespace Substrate return new GZipStream(new MemoryStream(data), CompressionMode.Decompress); } - public Stream GetChunkDataOutputStream () + public Stream GetDataOutputStream () { return new ZlibStream(new NBTBuffer(this), CompressionMode.Compress); } diff --git a/Substrate/SubstrateCS/Source/PlayerManager.cs b/Substrate/SubstrateCS/Source/PlayerManager.cs index 2a1d447..ef833fc 100644 --- a/Substrate/SubstrateCS/Source/PlayerManager.cs +++ b/Substrate/SubstrateCS/Source/PlayerManager.cs @@ -24,7 +24,7 @@ namespace Substrate protected NBT_Tree GetPlayerTree (string name) { PlayerFile pf = GetPlayerFile(name); - Stream nbtstr = pf.GetChunkDataInputStream(); + Stream nbtstr = pf.GetDataInputStream(); if (nbtstr == null) { return null; } @@ -35,7 +35,7 @@ namespace Substrate protected bool SavePlayerTree (string name, NBT_Tree tree) { PlayerFile pf = GetPlayerFile(name); - Stream zipstr = pf.GetChunkDataOutputStream(); + Stream zipstr = pf.GetDataOutputStream(); if (zipstr == null) { return false; } diff --git a/Substrate/SubstrateCS/Source/World.cs b/Substrate/SubstrateCS/Source/World.cs index 9cc9c81..6400d0a 100644 --- a/Substrate/SubstrateCS/Source/World.cs +++ b/Substrate/SubstrateCS/Source/World.cs @@ -5,25 +5,45 @@ using System.IO; namespace Substrate { + using NBT; + public class World { protected RegionManager _regionMan; - protected ChunkManager _chunkMan; - protected BlockManager _blockMan; + protected IChunkManager _chunkMan; + protected IBlockManager _blockMan; protected PlayerManager _playerMan; protected string _worldPath; + protected Level _level; + + public string WorldPath + { + get { return _worldPath; } + } + public World (string world) { _worldPath = world; + if (!File.Exists(Path.Combine(_worldPath, "level.dat"))) { + throw new Exception("Could not locate level.dat"); + } + + if (!LoadLevel()) { + throw new Exception("Failed to load level.dat"); + } + if (Directory.Exists(Path.Combine(world, "region"))) { _regionMan = new RegionManager(Path.Combine(world, "region")); _chunkMan = new ChunkManager(_regionMan); } else if (Directory.Exists(Path.Combine(world, "0"))) { - //_chunkMan = new ChunkFileManager(world); + _chunkMan = new ChunkFileManager(world); + } + else { + throw new Exception("Could not locate any world data"); } _blockMan = new BlockManager(_chunkMan); @@ -33,17 +53,30 @@ namespace Substrate } } + protected bool LoadLevel () + { + NBTFile nf = new NBTFile(Path.Combine(_worldPath, "level.dat")); + Stream nbtstr = nf.GetDataInputStream(); + if (nbtstr == null) { + return false; + } + + _level = new Level(this).LoadTreeSafe(new NBT_Tree(nbtstr).Root); + + return _level != null; + } + public RegionManager GetRegionManager () { return _regionMan; } - public ChunkManager GetChunkManager () + public IChunkManager GetChunkManager () { return _chunkMan; } - public BlockManager GetBlockManager () + public IBlockManager GetBlockManager () { return _blockMan; }