World interfaces refactored; breaks existing code.

This commit is contained in:
Justin Aquadro 2011-04-13 05:04:32 +00:00
parent 245e792541
commit 44ba6eac4e
5 changed files with 396 additions and 134 deletions

View file

@ -20,10 +20,10 @@ namespace Substrate
new NBTArrayNode("HeightMap", 256), new NBTArrayNode("HeightMap", 256),
new NBTListNode("Entities", TagType.TAG_COMPOUND), new NBTListNode("Entities", TagType.TAG_COMPOUND),
new NBTListNode("TileEntities", TagType.TAG_COMPOUND, TileEntity.BaseSchema), 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("xPos", TagType.TAG_INT),
new NBTScalerNode("zPos", 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),
}, },
}; };

View file

@ -10,9 +10,24 @@ namespace Substrate
public class Level : INBTObject<Level>, ICopyable<Level> public class Level : INBTObject<Level>, ICopyable<Level>
{ {
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 _time;
private long _lastPlayed; private long _lastPlayed;
@ -42,7 +57,11 @@ namespace Substrate
public Player Player public Player Player
{ {
get { return _player; } get { return _player; }
set { _player = value; } set
{
_player = value;
_player.World = _name;
}
} }
public int SpawnX public int SpawnX
@ -82,29 +101,29 @@ namespace Substrate
public string LevelName public string LevelName
{ {
get { return _name; } 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; _world = world;
LevelSchema = new NBTCompoundNode() // Sane defaults
{ _time = 0;
new NBTCompoundNode("Data") _lastPlayed = 0;
{ _spawnX = 0;
new NBTScalerNode("Time", TagType.TAG_LONG), _spawnY = 64;
new NBTScalerNode("LastPlayed", TagType.TAG_LONG), _spawnZ = 0;
new NBTCompoundNode("Player", Player.PlayerSchema, NBTOptions.OPTIONAL), _sizeOnDisk = 0;
new NBTScalerNode("SpawnX", TagType.TAG_INT), _randomSeed = new Random().Next();
new NBTScalerNode("SpawnY", TagType.TAG_INT), _version = 19132;
new NBTScalerNode("SpawnZ", TagType.TAG_INT), _name = "Untitled";
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),
},
};
} }
public Level (Level p) public Level (Level p)
@ -126,6 +145,12 @@ namespace Substrate
} }
} }
public void SetDefaultPlayer ()
{
_player = new Player();
_player.World = _name;
}
public bool Save () public bool Save ()
{ {
if (_world == null) { if (_world == null) {

View file

@ -80,6 +80,11 @@ namespace Substrate
: base() : base()
{ {
_inventory = new ItemCollection(_CAPACITY); _inventory = new ItemCollection(_CAPACITY);
// Sane defaults
_dimension = 0;
_sleeping = 0;
_sleepTimer = 0;
} }
public Player (Player p) public Player (Player p)

View file

@ -108,6 +108,16 @@ namespace Substrate
return true; return true;
} }
public int Save ()
{
int saved = 0;
foreach (Region r in _cache.Values) {
saved += r.Save();
}
return saved;
}
#region IEnumerable<Region> Members #region IEnumerable<Region> Members

View file

@ -7,58 +7,149 @@ namespace Substrate
{ {
using NBT; using NBT;
public abstract class World public static class Dimension
{ {
private string _worldPath; public const int NETHER = -1;
public const int DEFAULT = 0;
public string WorldPath
{
get { return _worldPath; }
} }
protected World (string path) public interface INBTWorld
{ {
_worldPath = path; string WorldPath { get; }
if (!File.Exists(Path.Combine(WorldPath, "level.dat"))) { IBlockManager GetBlockManager ();
throw new Exception("Could not locate level.dat"); IBlockManager GetBlockManager (int dim);
}
} IChunkManager GetChunkManager ();
IChunkManager GetChunkManager (int dim);
} }
public abstract class NBTWorld : World public class AlphaWorld : INBTWorld
{ {
private Level _level; protected string _path;
private PlayerManager _playerMan; protected string _levelFile = "level.dat";
public Level Level protected Level _level;
private Dictionary<int, ChunkFileManager> _chunkMgrs;
private Dictionary<int, BlockManager> _blockMgrs;
private AlphaWorld ()
{ {
get { return _level; } _chunkMgrs = new Dictionary<int, ChunkFileManager>();
_blockMgrs = new Dictionary<int, BlockManager>();
} }
public PlayerManager PlayerManager public BlockManager GetBlockManager ()
{ {
get { return _playerMan; } return GetBlockManager(Dimension.DEFAULT);
} }
public abstract IChunkManager ChunkManager { get; } public BlockManager GetBlockManager (int dim)
public abstract IBlockManager BlockManager { get; }
protected NBTWorld (string path)
: base(path)
{ {
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<int, ChunkFileManager> 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()) { if (!LoadLevel()) {
throw new Exception("Failed to load level.dat"); throw new Exception("Failed to load '" + _levelFile + "'");
} }
if (Directory.Exists(Path.Combine(path, "players"))) { return this;
_playerMan = new PlayerManager(Path.Combine(path, "players"));
}
} }
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(); Stream nbtstr = nf.GetDataInputStream();
if (nbtstr == null) { if (nbtstr == null) {
return false; return false;
@ -71,100 +162,231 @@ namespace Substrate
return _level != null; return _level != null;
} }
}
public class AlphaWorld : NBTWorld
#region INBTWorld Members
public string WorldPath
{ {
private ChunkFileManager _chunkMan; get { return _path; }
private BlockManager _blockMan; }
private string _dim; IBlockManager INBTWorld.GetBlockManager ()
public AlphaWorld (string path)
: base(path)
{ {
_chunkMan = new ChunkFileManager(path); return GetBlockManager();
_blockMan = new BlockManager(_chunkMan);
} }
public AlphaWorld (string path, string dim) IBlockManager INBTWorld.GetBlockManager (int dim)
: base(path)
{ {
_dim = dim; return GetBlockManager(dim);
if (_dim.Length > 0) {
path = Path.Combine(path, dim);
} }
_chunkMan = new ChunkFileManager(path); IChunkManager INBTWorld.GetChunkManager ()
_blockMan = new BlockManager(_chunkMan);
}
public override IChunkManager ChunkManager
{ {
get { return _chunkMan; } return GetChunkManager();
} }
public override IBlockManager BlockManager IChunkManager INBTWorld.GetChunkManager (int dim)
{ {
get { return _blockMan; } return GetChunkManager(dim);
}
} }
public class BetaWorld : NBTWorld #endregion
}
public class BetaWorld : INBTWorld {
private const string _REGION_DIR = "region";
protected string _path;
protected string _levelFile = "level.dat";
protected Level _level;
private Dictionary<int, RegionManager> _regionMgrs;
private Dictionary<int, ChunkManager> _chunkMgrs;
private Dictionary<int, BlockManager> _blockMgrs;
private BetaWorld ()
{ {
private RegionManager _regionMan; _regionMgrs = new Dictionary<int, RegionManager>();
private ChunkManager _chunkMan; _chunkMgrs = new Dictionary<int, ChunkManager>();
private BlockManager _blockMan; _blockMgrs = new Dictionary<int, BlockManager>();
}
private string _dim; public BlockManager GetBlockManager ()
private string _regionDir;
public RegionManager RegionManager
{ {
get { return _regionMan; } return GetBlockManager(Dimension.DEFAULT);
} }
public BetaWorld (string path) public BlockManager GetBlockManager (int dim)
: this(path, "region", "")
{ {
BlockManager rm;
if (_blockMgrs.TryGetValue(dim, out rm)) {
return rm;
} }
public BetaWorld (string path, string region) OpenDimension(dim);
: this(path, region, "") return _blockMgrs[dim];
}
public ChunkManager GetChunkManager ()
{ {
return GetChunkManager(Dimension.DEFAULT);
} }
public BetaWorld (string path, string region, string dim) public ChunkManager GetChunkManager (int dim)
: base(path)
{ {
_regionDir = region; ChunkManager rm;
if (_chunkMgrs.TryGetValue(dim, out rm)) {
_dim = dim; return rm;
if (_dim.Length > 0) {
path = Path.Combine(path, dim);
} }
if (!Directory.Exists(Path.Combine(path, _regionDir))) { OpenDimension(dim);
throw new Exception("Could not find region directory"); return _chunkMgrs[dim];
} }
_regionMan = new RegionManager(Path.Combine(path, _regionDir)); public RegionManager GetRegionManager ()
_chunkMan = new ChunkManager(_regionMan);
_blockMan = new BlockManager(_chunkMan);
}
public override IChunkManager ChunkManager
{ {
get { return _chunkMan; } return GetRegionManager(Dimension.DEFAULT);
} }
public override IBlockManager BlockManager public RegionManager GetRegionManager (int dim)
{ {
get { return _blockMan; } RegionManager rm;
if (_regionMgrs.TryGetValue(dim, out rm)) {
return rm;
} }
//public static BetaWorld Open (string path); OpenDimension(dim);
//public static BetaWorld Create (string path); 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<int, RegionManager> 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 DimensionNotFoundException : Exception { }
} }