diff --git a/Substrate/SubstrateCS/Source/Chunk.cs b/Substrate/SubstrateCS/Source/Chunk.cs index 79e2b68..6bfaa49 100644 --- a/Substrate/SubstrateCS/Source/Chunk.cs +++ b/Substrate/SubstrateCS/Source/Chunk.cs @@ -20,10 +20,10 @@ namespace Substrate new NBTArrayNode("HeightMap", 256), new NBTListNode("Entities", TagType.TAG_COMPOUND), new NBTListNode("TileEntities", TagType.TAG_COMPOUND, TileEntity.BaseSchema), - //new NBTScalerNode("LastUpdate", TagType.TAG_LONG), + new NBTScalerNode("LastUpdate", TagType.TAG_LONG, NBTOptions.CREATE_ON_MISSING), new NBTScalerNode("xPos", TagType.TAG_INT), new NBTScalerNode("zPos", TagType.TAG_INT), - new NBTScalerNode("TerrainPopulated", TagType.TAG_BYTE), + new NBTScalerNode("TerrainPopulated", TagType.TAG_BYTE, NBTOptions.CREATE_ON_MISSING), }, }; diff --git a/Substrate/SubstrateCS/Source/Level.cs b/Substrate/SubstrateCS/Source/Level.cs index 4d8f7da..f6a5fc8 100644 --- a/Substrate/SubstrateCS/Source/Level.cs +++ b/Substrate/SubstrateCS/Source/Level.cs @@ -10,9 +10,24 @@ namespace Substrate public class Level : INBTObject, ICopyable { - public static NBTCompoundNode LevelSchema; + public static NBTCompoundNode LevelSchema = new NBTCompoundNode() + { + new NBTCompoundNode("Data") + { + new NBTScalerNode("Time", TagType.TAG_LONG), + new NBTScalerNode("LastPlayed", TagType.TAG_LONG), + new NBTCompoundNode("Player", Player.PlayerSchema, NBTOptions.OPTIONAL), + new NBTScalerNode("SpawnX", TagType.TAG_INT), + new NBTScalerNode("SpawnY", TagType.TAG_INT), + new NBTScalerNode("SpawnZ", TagType.TAG_INT), + new NBTScalerNode("SizeOnDisk", TagType.TAG_LONG), + new NBTScalerNode("RandomSeed", TagType.TAG_LONG), + new NBTScalerNode("version", TagType.TAG_INT, NBTOptions.OPTIONAL), + new NBTScalerNode("LevelName", TagType.TAG_STRING, NBTOptions.OPTIONAL), + }, + }; - private World _world; + private INBTWorld _world; private long _time; private long _lastPlayed; @@ -42,7 +57,11 @@ namespace Substrate public Player Player { get { return _player; } - set { _player = value; } + set + { + _player = value; + _player.World = _name; + } } public int SpawnX @@ -82,29 +101,29 @@ namespace Substrate public string LevelName { get { return _name; } - set { _name = value; } + set + { + _name = value; + if (_player != null) { + _player.World = value; + } + } } - public Level (World world) + public Level (INBTWorld world) { _world = world; - LevelSchema = new NBTCompoundNode() - { - new NBTCompoundNode("Data") - { - new NBTScalerNode("Time", TagType.TAG_LONG), - new NBTScalerNode("LastPlayed", TagType.TAG_LONG), - new NBTCompoundNode("Player", Player.PlayerSchema, NBTOptions.OPTIONAL), - new NBTScalerNode("SpawnX", TagType.TAG_INT), - new NBTScalerNode("SpawnY", TagType.TAG_INT), - new NBTScalerNode("SpawnZ", TagType.TAG_INT), - new NBTScalerNode("SizeOnDisk", TagType.TAG_LONG), - new NBTScalerNode("RandomSeed", TagType.TAG_LONG), - new NBTScalerNode("version", TagType.TAG_INT, NBTOptions.OPTIONAL), - new NBTScalerNode("LevelName", TagType.TAG_STRING, NBTOptions.OPTIONAL), - }, - }; + // Sane defaults + _time = 0; + _lastPlayed = 0; + _spawnX = 0; + _spawnY = 64; + _spawnZ = 0; + _sizeOnDisk = 0; + _randomSeed = new Random().Next(); + _version = 19132; + _name = "Untitled"; } public Level (Level p) @@ -126,6 +145,12 @@ namespace Substrate } } + public void SetDefaultPlayer () + { + _player = new Player(); + _player.World = _name; + } + public bool Save () { if (_world == null) { diff --git a/Substrate/SubstrateCS/Source/Player.cs b/Substrate/SubstrateCS/Source/Player.cs index 08a4861..ebb8e5d 100644 --- a/Substrate/SubstrateCS/Source/Player.cs +++ b/Substrate/SubstrateCS/Source/Player.cs @@ -80,6 +80,11 @@ namespace Substrate : base() { _inventory = new ItemCollection(_CAPACITY); + + // Sane defaults + _dimension = 0; + _sleeping = 0; + _sleepTimer = 0; } public Player (Player p) diff --git a/Substrate/SubstrateCS/Source/RegionManager.cs b/Substrate/SubstrateCS/Source/RegionManager.cs index 8371c05..e84f14c 100644 --- a/Substrate/SubstrateCS/Source/RegionManager.cs +++ b/Substrate/SubstrateCS/Source/RegionManager.cs @@ -108,6 +108,16 @@ namespace Substrate return true; } + public int Save () + { + int saved = 0; + foreach (Region r in _cache.Values) { + saved += r.Save(); + } + + return saved; + } + #region IEnumerable Members diff --git a/Substrate/SubstrateCS/Source/World.cs b/Substrate/SubstrateCS/Source/World.cs index 4545972..1683c25 100644 --- a/Substrate/SubstrateCS/Source/World.cs +++ b/Substrate/SubstrateCS/Source/World.cs @@ -7,58 +7,149 @@ namespace Substrate { using NBT; - public abstract class World + public static class Dimension { - private string _worldPath; - - public string WorldPath - { - get { return _worldPath; } - } - - protected World (string path) - { - _worldPath = path; - - if (!File.Exists(Path.Combine(WorldPath, "level.dat"))) { - throw new Exception("Could not locate level.dat"); - } - } + public const int NETHER = -1; + public const int DEFAULT = 0; } - public abstract class NBTWorld : World + public interface INBTWorld { - private Level _level; - private PlayerManager _playerMan; + string WorldPath { get; } - public Level Level + IBlockManager GetBlockManager (); + IBlockManager GetBlockManager (int dim); + + IChunkManager GetChunkManager (); + IChunkManager GetChunkManager (int dim); + } + + public class AlphaWorld : INBTWorld + { + protected string _path; + protected string _levelFile = "level.dat"; + + protected Level _level; + + private Dictionary _chunkMgrs; + private Dictionary _blockMgrs; + + private AlphaWorld () { - get { return _level; } + _chunkMgrs = new Dictionary(); + _blockMgrs = new Dictionary(); } - public PlayerManager PlayerManager + public BlockManager GetBlockManager () { - get { return _playerMan; } + return GetBlockManager(Dimension.DEFAULT); } - public abstract IChunkManager ChunkManager { get; } - public abstract IBlockManager BlockManager { get; } - - protected NBTWorld (string path) - : base(path) + public BlockManager GetBlockManager (int dim) { + BlockManager rm; + if (_blockMgrs.TryGetValue(dim, out rm)) { + return rm; + } + + OpenDimension(dim); + return _blockMgrs[dim]; + } + + public ChunkFileManager GetChunkManager () + { + return GetChunkManager(Dimension.DEFAULT); + } + + public ChunkFileManager GetChunkManager (int dim) + { + ChunkFileManager rm; + if (_chunkMgrs.TryGetValue(dim, out rm)) { + return rm; + } + + OpenDimension(dim); + return _chunkMgrs[dim]; + } + + public static AlphaWorld Open (string path) + { + return new AlphaWorld().OpenWorld(path) as AlphaWorld; + } + + public static AlphaWorld Create (string path) + { + return new AlphaWorld().CreateWorld(path) as AlphaWorld; + } + + public void Save () + { + _level.Save(); + + foreach (KeyValuePair cm in _chunkMgrs) { + cm.Value.Save(); + } + } + + private void OpenDimension (int dim) + { + string path = _path; + if (dim != Dimension.DEFAULT) { + path = Path.Combine(path, "DIM" + dim); + } + + if (!Directory.Exists(path)) { + Directory.CreateDirectory(path); + } + + ChunkFileManager cm = new ChunkFileManager(path); + BlockManager bm = new BlockManager(cm); + + _chunkMgrs[dim] = cm; + _blockMgrs[dim] = bm; + } + + private AlphaWorld OpenWorld (string path) + { + if (!Directory.Exists(path)) { + if (File.Exists(path)) { + _levelFile = Path.GetFileName(path); + path = Path.GetDirectoryName(path); + } + else { + throw new DirectoryNotFoundException("Directory '" + path + "' not found"); + } + } + + _path = path; + + string ldat = Path.Combine(path, _levelFile); + if (!File.Exists(ldat)) { + throw new FileNotFoundException("Data file '" + _levelFile + "' not found in '" + path + "'", ldat); + } + if (!LoadLevel()) { - throw new Exception("Failed to load level.dat"); + throw new Exception("Failed to load '" + _levelFile + "'"); } - if (Directory.Exists(Path.Combine(path, "players"))) { - _playerMan = new PlayerManager(Path.Combine(path, "players")); - } + return this; } - protected bool LoadLevel () + private AlphaWorld CreateWorld (string path) { - NBTFile nf = new NBTFile(Path.Combine(WorldPath, "level.dat")); + if (!Directory.Exists(path)) { + throw new DirectoryNotFoundException("Directory '" + path + "' not found"); + } + + _path = path; + _level = new Level(this); + + return this; + } + + private bool LoadLevel () + { + NBTFile nf = new NBTFile(Path.Combine(_path, _levelFile)); Stream nbtstr = nf.GetDataInputStream(); if (nbtstr == null) { return false; @@ -71,100 +162,231 @@ namespace Substrate return _level != null; } + + + #region INBTWorld Members + + public string WorldPath + { + get { return _path; } + } + + IBlockManager INBTWorld.GetBlockManager () + { + return GetBlockManager(); + } + + IBlockManager INBTWorld.GetBlockManager (int dim) + { + return GetBlockManager(dim); + } + + IChunkManager INBTWorld.GetChunkManager () + { + return GetChunkManager(); + } + + IChunkManager INBTWorld.GetChunkManager (int dim) + { + return GetChunkManager(dim); + } + + #endregion } - public class AlphaWorld : NBTWorld - { - private ChunkFileManager _chunkMan; - private BlockManager _blockMan; + public class BetaWorld : INBTWorld { + private const string _REGION_DIR = "region"; + protected string _path; + protected string _levelFile = "level.dat"; - private string _dim; + protected Level _level; - public AlphaWorld (string path) - : base(path) + private Dictionary _regionMgrs; + private Dictionary _chunkMgrs; + private Dictionary _blockMgrs; + + private BetaWorld () { - _chunkMan = new ChunkFileManager(path); - _blockMan = new BlockManager(_chunkMan); + _regionMgrs = new Dictionary(); + _chunkMgrs = new Dictionary(); + _blockMgrs = new Dictionary(); } - public AlphaWorld (string path, string dim) - : base(path) + public BlockManager GetBlockManager () { - _dim = dim; - if (_dim.Length > 0) { - path = Path.Combine(path, dim); + return GetBlockManager(Dimension.DEFAULT); + } + + public BlockManager GetBlockManager (int dim) + { + BlockManager rm; + if (_blockMgrs.TryGetValue(dim, out rm)) { + return rm; } - _chunkMan = new ChunkFileManager(path); - _blockMan = new BlockManager(_chunkMan); + OpenDimension(dim); + return _blockMgrs[dim]; } - public override IChunkManager ChunkManager + public ChunkManager GetChunkManager () { - get { return _chunkMan; } + return GetChunkManager(Dimension.DEFAULT); } - public override IBlockManager BlockManager + public ChunkManager GetChunkManager (int dim) { - get { return _blockMan; } + ChunkManager rm; + if (_chunkMgrs.TryGetValue(dim, out rm)) { + return rm; + } + + OpenDimension(dim); + return _chunkMgrs[dim]; } + + public RegionManager GetRegionManager () + { + return GetRegionManager(Dimension.DEFAULT); + } + + public RegionManager GetRegionManager (int dim) + { + RegionManager rm; + if (_regionMgrs.TryGetValue(dim, out rm)) { + return rm; + } + + OpenDimension(dim); + return _regionMgrs[dim]; + } + + public static BetaWorld Open (string path) + { + return new BetaWorld().OpenWorld(path) as BetaWorld; + } + + public static BetaWorld Create (string path) + { + return new BetaWorld().CreateWorld(path) as BetaWorld; + } + + public void Save () + { + _level.Save(); + + foreach (KeyValuePair rm in _regionMgrs) { + rm.Value.Save(); + } + } + + private void OpenDimension (int dim) + { + string path = _path; + if (dim == Dimension.DEFAULT) { + path = Path.Combine(path, _REGION_DIR); + } + else { + path = Path.Combine(path, "DIM" + dim); + path = Path.Combine(path, _REGION_DIR); + } + + if (!Directory.Exists(path)) { + Directory.CreateDirectory(path); + } + + RegionManager rm = new RegionManager(path); + ChunkManager cm = new ChunkManager(rm); + BlockManager bm = new BlockManager(cm); + + _regionMgrs[dim] = rm; + _chunkMgrs[dim] = cm; + _blockMgrs[dim] = bm; + } + + private BetaWorld OpenWorld (string path) + { + if (!Directory.Exists(path)) { + if (File.Exists(path)) { + _levelFile = Path.GetFileName(path); + path = Path.GetDirectoryName(path); + } + else { + throw new DirectoryNotFoundException("Directory '" + path + "' not found"); + } + } + + _path = path; + + string ldat = Path.Combine(path, _levelFile); + if (!File.Exists(ldat)) { + throw new FileNotFoundException("Data file '" + _levelFile + "' not found in '" + path + "'", ldat); + } + + if (!LoadLevel()) { + throw new Exception("Failed to load '" + _levelFile + "'"); + } + + return this; + } + + private BetaWorld CreateWorld (string path) + { + if (!Directory.Exists(path)) { + throw new DirectoryNotFoundException("Directory '" + path + "' not found"); + } + + _path = path; + _level = new Level(this); + + return this; + } + + private bool LoadLevel () + { + NBTFile nf = new NBTFile(Path.Combine(_path, _levelFile)); + Stream nbtstr = nf.GetDataInputStream(); + if (nbtstr == null) { + return false; + } + + NBT_Tree tree = new NBT_Tree(nbtstr); + + _level = new Level(this); + _level = _level.LoadTreeSafe(tree.Root); + + return _level != null; + } + + + #region INBTWorld Members + + public string WorldPath + { + get { return _path; } + } + + IBlockManager INBTWorld.GetBlockManager () + { + return GetBlockManager(); + } + + IBlockManager INBTWorld.GetBlockManager (int dim) + { + return GetBlockManager(dim); + } + + IChunkManager INBTWorld.GetChunkManager () + { + return GetChunkManager(); + } + + IChunkManager INBTWorld.GetChunkManager (int dim) + { + return GetChunkManager(dim); + } + + #endregion } - public class BetaWorld : NBTWorld - { - private RegionManager _regionMan; - private ChunkManager _chunkMan; - private BlockManager _blockMan; - - private string _dim; - private string _regionDir; - - public RegionManager RegionManager - { - get { return _regionMan; } - } - - public BetaWorld (string path) - : this(path, "region", "") - { - } - - public BetaWorld (string path, string region) - : this(path, region, "") - { - } - - public BetaWorld (string path, string region, string dim) - : base(path) - { - _regionDir = region; - - _dim = dim; - if (_dim.Length > 0) { - path = Path.Combine(path, dim); - } - - if (!Directory.Exists(Path.Combine(path, _regionDir))) { - throw new Exception("Could not find region directory"); - } - - _regionMan = new RegionManager(Path.Combine(path, _regionDir)); - _chunkMan = new ChunkManager(_regionMan); - _blockMan = new BlockManager(_chunkMan); - } - - public override IChunkManager ChunkManager - { - get { return _chunkMan; } - } - - public override IBlockManager BlockManager - { - get { return _blockMan; } - } - - //public static BetaWorld Open (string path); - //public static BetaWorld Create (string path); - } - + public class DimensionNotFoundException : Exception { } }