using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using Substrate.Core;
using Substrate.Nbt;
namespace Substrate
{
using IO = System.IO;
///
/// Represents an Alpha-compatible (up to Beta 1.2) Minecraft world.
///
public class AlphaWorld : NbtWorld
{
private const string _PLAYER_DIR = "players";
private string _levelFile = "level.dat";
private Level _level;
private Dictionary _chunkMgrs;
private Dictionary _blockMgrs;
private PlayerManager _playerMan;
private AlphaWorld ()
{
_chunkMgrs = new Dictionary();
_blockMgrs = new Dictionary();
}
///
/// Gets a reference to this world's object.
///
public override Level Level
{
get { return _level; }
}
///
/// Gets a for the default dimension.
///
/// A tied to the default dimension in this world.
/// Get a if you need to manage blocks as a global, unbounded matrix. This abstracts away
/// any higher-level organizational divisions. If your task is going to be heavily performance-bound, consider getting a
/// instead and working with blocks on a chunk-local level.
public new BlockManager GetBlockManager ()
{
return GetBlockManagerVirt(Dimension.DEFAULT) as BlockManager;
}
///
/// Gets a for the given dimension.
///
/// The id of the dimension to look up.
/// A tied to the given dimension in this world.
/// Get a if you need to manage blocks as a global, unbounded matrix. This abstracts away
/// any higher-level organizational divisions. If your task is going to be heavily performance-bound, consider getting a
/// instead and working with blocks on a chunk-local level.
public new BlockManager GetBlockManager (int dim)
{
return GetBlockManagerVirt(dim) as BlockManager;
}
///
/// Gets a for the default dimension.
///
/// A tied to the default dimension in this world.
/// Get a if you you need to work with easily-digestible, bounded chunks of blocks.
public new AlphaChunkManager GetChunkManager ()
{
return GetChunkManagerVirt(Dimension.DEFAULT) as AlphaChunkManager;
}
///
/// Gets a for the given dimension.
///
/// The id of the dimension to look up.
/// A tied to the given dimension in this world.
/// Get a if you you need to work with easily-digestible, bounded chunks of blocks.
public new AlphaChunkManager GetChunkManager (int dim)
{
return GetChunkManagerVirt(dim) as AlphaChunkManager;
}
///
/// Gets a for maanging players on multiplayer worlds.
///
/// A for this world.
/// To manage the player of a single-player world, get a object for the world instead.
public new PlayerManager GetPlayerManager ()
{
return GetPlayerManagerVirt() as PlayerManager;
}
///
public override void Save ()
{
_level.Save();
foreach (KeyValuePair cm in _chunkMgrs) {
cm.Value.Save();
}
}
///
/// Opens an existing Alpha-compatible Minecraft world and returns a new to represent it.
///
/// The path to the directory containing the world's level.dat, or the path to level.dat itself.
/// A new object representing an existing world on disk.
public static new AlphaWorld Open (string path)
{
return new AlphaWorld().OpenWorld(path) as AlphaWorld;
}
///
/// Creates a new Alpha-compatible Minecraft world and returns a new to represent it.
///
/// The path to the directory where the new world should be stored.
/// A new object representing a new world.
/// This method will attempt to create the specified directory immediately if it does not exist, but will not
/// write out any world data unless it is explicitly saved at a later time.
public static AlphaWorld Create (string path)
{
return new AlphaWorld().CreateWorld(path) as AlphaWorld;
}
///
protected override IBlockManager GetBlockManagerVirt (int dim)
{
BlockManager rm;
if (_blockMgrs.TryGetValue(dim, out rm)) {
return rm;
}
OpenDimension(dim);
return _blockMgrs[dim];
}
///
protected override IChunkManager GetChunkManagerVirt (int dim)
{
AlphaChunkManager rm;
if (_chunkMgrs.TryGetValue(dim, out rm)) {
return rm;
}
OpenDimension(dim);
return _chunkMgrs[dim];
}
///
protected override IPlayerManager GetPlayerManagerVirt ()
{
if (_playerMan != null) {
return _playerMan;
}
string path = IO.Path.Combine(Path, _PLAYER_DIR);
_playerMan = new PlayerManager(path);
return _playerMan;
}
private void OpenDimension (int dim)
{
string path = Path;
if (dim != Dimension.DEFAULT) {
path = IO.Path.Combine(path, "DIM" + dim);
}
if (!Directory.Exists(path)) {
Directory.CreateDirectory(path);
}
AlphaChunkManager cm = new AlphaChunkManager(path);
BlockManager bm = new AlphaBlockManager(cm);
_chunkMgrs[dim] = cm;
_blockMgrs[dim] = bm;
}
private AlphaWorld OpenWorld (string path)
{
if (!Directory.Exists(path)) {
if (File.Exists(path)) {
_levelFile = IO.Path.GetFileName(path);
path = IO.Path.GetDirectoryName(path);
}
else {
throw new DirectoryNotFoundException("Directory '" + path + "' not found");
}
}
Path = path;
string ldat = IO.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 AlphaWorld CreateWorld (string path)
{
if (!Directory.Exists(path)) {
throw new DirectoryNotFoundException("Directory '" + path + "' not found");
}
Path = path;
_level = new Level(this);
_level.Version = 0;
return this;
}
private bool LoadLevel ()
{
NBTFile nf = new NBTFile(IO.Path.Combine(Path, _levelFile));
Stream nbtstr = nf.GetDataInputStream();
if (nbtstr == null) {
return false;
}
NbtTree tree = new NbtTree(nbtstr);
_level = new Level(this);
_level = _level.LoadTreeSafe(tree.Root);
return _level != null;
}
internal static void OnResolveOpen (object sender, OpenWorldEventArgs e)
{
try {
AlphaWorld world = new AlphaWorld().OpenWorld(e.Path);
if (world == null) {
return;
}
if (world.Level.Version != 0) {
return;
}
e.AddHandler(Open);
}
catch (Exception) {
return;
}
}
}
}