forked from mirrors/NBTExplorer
More documentation, major refactoring of World structure, moving towards CLS-compliance.
This commit is contained in:
parent
3387386295
commit
b7b6f88fbe
18 changed files with 1124 additions and 582 deletions
|
@ -1,4 +1,5 @@
|
|||
using System.Reflection;
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
|
@ -6,7 +7,7 @@ using System.Runtime.InteropServices;
|
|||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("Substrate")]
|
||||
[assembly: AssemblyDescription("Minecraft map SDK")]
|
||||
[assembly: AssemblyDescription("SDK for loading and modifying Minecraft worlds")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("Substrate")]
|
||||
|
@ -31,3 +32,6 @@ using System.Runtime.InteropServices;
|
|||
//
|
||||
[assembly: AssemblyVersion("0.7.0.0")]
|
||||
[assembly: AssemblyFileVersion("0.7.0.0")]
|
||||
|
||||
// This library is compatible with all CLS-compliant .NET programming languages.
|
||||
[assembly: CLSCompliant(true)]
|
260
Substrate/SubstrateCS/Source/AlphaWorld.cs
Normal file
260
Substrate/SubstrateCS/Source/AlphaWorld.cs
Normal file
|
@ -0,0 +1,260 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using Substrate.Core;
|
||||
using Substrate.Nbt;
|
||||
|
||||
namespace Substrate
|
||||
{
|
||||
using IO = System.IO;
|
||||
|
||||
/// <summary>
|
||||
/// Represents an Alpha-compatible (up to Beta 1.2) Minecraft world.
|
||||
/// </summary>
|
||||
public class AlphaWorld : NbtWorld
|
||||
{
|
||||
private const string _PLAYER_DIR = "players";
|
||||
private string _levelFile = "level.dat";
|
||||
|
||||
private Level _level;
|
||||
|
||||
private Dictionary<int, ChunkFileManager> _chunkMgrs;
|
||||
private Dictionary<int, BlockManager> _blockMgrs;
|
||||
|
||||
private PlayerManager _playerMan;
|
||||
|
||||
private AlphaWorld ()
|
||||
{
|
||||
_chunkMgrs = new Dictionary<int, ChunkFileManager>();
|
||||
_blockMgrs = new Dictionary<int, BlockManager>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a reference to this world's <see cref="Level"/> object.
|
||||
/// </summary>
|
||||
public override Level Level
|
||||
{
|
||||
get { return _level; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a <see cref="BlockManager"/> for the default dimension.
|
||||
/// </summary>
|
||||
/// <returns>A <see cref="BlockManager"/> tied to the default dimension in this world.</returns>
|
||||
/// <remarks>Get a <see cref="BlockManager"/> 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
|
||||
/// <see cref="ChunkManager"/> instead and working with blocks on a chunk-local level.</remarks>
|
||||
public new BlockManager GetBlockManager ()
|
||||
{
|
||||
return GetBlockManagerVirt(Dimension.DEFAULT) as BlockManager;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a <see cref="BlockManager"/> for the given dimension.
|
||||
/// </summary>
|
||||
/// <param name="dim">The id of the dimension to look up.</param>
|
||||
/// <returns>A <see cref="BlockManager"/> tied to the given dimension in this world.</returns>
|
||||
/// <remarks>Get a <see cref="BlockManager"/> 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
|
||||
/// <see cref="ChunkManager"/> instead and working with blocks on a chunk-local level.</remarks>
|
||||
public new BlockManager GetBlockManager (int dim)
|
||||
{
|
||||
return GetBlockManagerVirt(dim) as BlockManager;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a <see cref="ChunkManager"/> for the default dimension.
|
||||
/// </summary>
|
||||
/// <returns>A <see cref="ChunkManager"/> tied to the default dimension in this world.</returns>
|
||||
/// <remarks>Get a <see cref="ChunkManager"/> if you you need to work with easily-digestible, bounded chunks of blocks.</remarks>
|
||||
public new ChunkFileManager GetChunkManager ()
|
||||
{
|
||||
return GetChunkManagerVirt(Dimension.DEFAULT) as ChunkFileManager;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a <see cref="ChunkManager"/> for the given dimension.
|
||||
/// </summary>
|
||||
/// <param name="dim">The id of the dimension to look up.</param>
|
||||
/// <returns>A <see cref="ChunkManager"/> tied to the given dimension in this world.</returns>
|
||||
/// <remarks>Get a <see cref="ChunkManager"/> if you you need to work with easily-digestible, bounded chunks of blocks.</remarks>
|
||||
public new ChunkFileManager GetChunkManager (int dim)
|
||||
{
|
||||
return GetChunkManagerVirt(dim) as ChunkFileManager;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a <see cref="PlayerManager"/> for maanging players on multiplayer worlds.
|
||||
/// </summary>
|
||||
/// <returns>A <see cref="PlayerManager"/> for this world.</returns>
|
||||
/// <remarks>To manage the player of a single-player world, get a <see cref="Level"/> object for the world instead.</remarks>
|
||||
public new PlayerManager GetPlayerManager ()
|
||||
{
|
||||
return GetPlayerManagerVirt() as PlayerManager;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Saves the world's <see cref="Level"/> data, and any <see cref="Chunk"/> objects known to have unsaved changes.
|
||||
/// </summary>
|
||||
public void Save ()
|
||||
{
|
||||
_level.Save();
|
||||
|
||||
foreach (KeyValuePair<int, ChunkFileManager> cm in _chunkMgrs) {
|
||||
cm.Value.Save();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens an existing Alpha-compatible Minecraft world and returns a new <see cref="AlphaWorld"/> to represent it.
|
||||
/// </summary>
|
||||
/// <param name="path">The path to the directory containing the world's level.dat, or the path to level.dat itself.</param>
|
||||
/// <returns>A new <see cref="AlphaWorld"/> object representing an existing world on disk.</returns>
|
||||
public static AlphaWorld Open (string path)
|
||||
{
|
||||
return new AlphaWorld().OpenWorld(path) as AlphaWorld;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new Alpha-compatible Minecraft world and returns a new <see cref="AlphaWorld"/> to represent it.
|
||||
/// </summary>
|
||||
/// <param name="path">The path to the directory where the new world should be stored.</param>
|
||||
/// <returns>A new <see cref="AlphaWorld"/> object representing a new world.</returns>
|
||||
/// <remarks>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.</remarks>
|
||||
public static AlphaWorld Create (string path)
|
||||
{
|
||||
return new AlphaWorld().CreateWorld(path) as AlphaWorld;
|
||||
}
|
||||
|
||||
/// <exclude/>
|
||||
protected override IBlockManager GetBlockManagerVirt (int dim)
|
||||
{
|
||||
BlockManager rm;
|
||||
if (_blockMgrs.TryGetValue(dim, out rm)) {
|
||||
return rm;
|
||||
}
|
||||
|
||||
OpenDimension(dim);
|
||||
return _blockMgrs[dim];
|
||||
}
|
||||
|
||||
/// <exclude/>
|
||||
protected override IChunkManager GetChunkManagerVirt (int dim)
|
||||
{
|
||||
ChunkFileManager rm;
|
||||
if (_chunkMgrs.TryGetValue(dim, out rm)) {
|
||||
return rm;
|
||||
}
|
||||
|
||||
OpenDimension(dim);
|
||||
return _chunkMgrs[dim];
|
||||
}
|
||||
|
||||
/// <exclude/>
|
||||
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);
|
||||
}
|
||||
|
||||
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 = 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);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
310
Substrate/SubstrateCS/Source/BetaWorld.cs
Normal file
310
Substrate/SubstrateCS/Source/BetaWorld.cs
Normal file
|
@ -0,0 +1,310 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Substrate.Core;
|
||||
using Substrate.Nbt;
|
||||
|
||||
//TODO: Exceptions (+ Alpha)
|
||||
|
||||
namespace Substrate
|
||||
{
|
||||
using IO = System.IO;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a Beta-compatible (Beta 1.3 or higher) Minecraft world.
|
||||
/// </summary>
|
||||
public class BetaWorld : NbtWorld
|
||||
{
|
||||
private const string _REGION_DIR = "region";
|
||||
private const string _PLAYER_DIR = "players";
|
||||
private string _levelFile = "level.dat";
|
||||
|
||||
private Level _level;
|
||||
|
||||
private Dictionary<int, RegionManager> _regionMgrs;
|
||||
private Dictionary<int, ChunkManager> _chunkMgrs;
|
||||
private Dictionary<int, BlockManager> _blockMgrs;
|
||||
|
||||
private PlayerManager _playerMan;
|
||||
|
||||
private BetaWorld ()
|
||||
{
|
||||
_regionMgrs = new Dictionary<int, RegionManager>();
|
||||
_chunkMgrs = new Dictionary<int, ChunkManager>();
|
||||
_blockMgrs = new Dictionary<int, BlockManager>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a reference to this world's <see cref="Level"/> object.
|
||||
/// </summary>
|
||||
public override Level Level
|
||||
{
|
||||
get { return _level; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a <see cref="BlockManager"/> for the default dimension.
|
||||
/// </summary>
|
||||
/// <returns>A <see cref="BlockManager"/> tied to the default dimension in this world.</returns>
|
||||
/// <remarks>Get a <see cref="BlockManager"/> 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
|
||||
/// <see cref="ChunkManager"/> instead and working with blocks on a chunk-local level.</remarks>
|
||||
public new BlockManager GetBlockManager ()
|
||||
{
|
||||
return GetBlockManagerVirt(Dimension.DEFAULT) as BlockManager;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a <see cref="BlockManager"/> for the given dimension.
|
||||
/// </summary>
|
||||
/// <param name="dim">The id of the dimension to look up.</param>
|
||||
/// <returns>A <see cref="BlockManager"/> tied to the given dimension in this world.</returns>
|
||||
/// <remarks>Get a <see cref="BlockManager"/> 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
|
||||
/// <see cref="ChunkManager"/> instead and working with blocks on a chunk-local level.</remarks>
|
||||
public new BlockManager GetBlockManager (int dim)
|
||||
{
|
||||
return GetBlockManagerVirt(dim) as BlockManager;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a <see cref="ChunkManager"/> for the default dimension.
|
||||
/// </summary>
|
||||
/// <returns>A <see cref="ChunkManager"/> tied to the default dimension in this world.</returns>
|
||||
/// <remarks>Get a <see cref="ChunkManager"/> if you you need to work with easily-digestible, bounded chunks of blocks.</remarks>
|
||||
public new ChunkManager GetChunkManager ()
|
||||
{
|
||||
return GetChunkManagerVirt(Dimension.DEFAULT) as ChunkManager;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a <see cref="ChunkManager"/> for the given dimension.
|
||||
/// </summary>
|
||||
/// <param name="dim">The id of the dimension to look up.</param>
|
||||
/// <returns>A <see cref="ChunkManager"/> tied to the given dimension in this world.</returns>
|
||||
/// <remarks>Get a <see cref="ChunkManager"/> if you you need to work with easily-digestible, bounded chunks of blocks.</remarks>
|
||||
public new ChunkManager GetChunkManager (int dim)
|
||||
{
|
||||
return GetChunkManagerVirt(dim) as ChunkManager;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a <see cref="RegionManager"/> for the default dimension.
|
||||
/// </summary>
|
||||
/// <returns>A <see cref="RegionManager"/> tied to the defaul dimension in this world.</returns>
|
||||
/// <remarks>Regions are a higher-level unit of organization for blocks unique to worlds created in Beta 1.3 and beyond.
|
||||
/// Consider using the <see cref="ChunkManager"/> if you are interested in working with blocks.</remarks>
|
||||
public RegionManager GetRegionManager ()
|
||||
{
|
||||
return GetRegionManager(Dimension.DEFAULT);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a <see cref="RegionManager"/> for the given dimension.
|
||||
/// </summary>
|
||||
/// <param name="dim">The id of the dimension to look up.</param>
|
||||
/// <returns>A <see cref="RegionManager"/> tied to the given dimension in this world.</returns>
|
||||
/// <remarks>Regions are a higher-level unit of organization for blocks unique to worlds created in Beta 1.3 and beyond.
|
||||
/// Consider using the <see cref="ChunkManager"/> if you are interested in working with blocks.</remarks>
|
||||
public RegionManager GetRegionManager (int dim)
|
||||
{
|
||||
RegionManager rm;
|
||||
if (_regionMgrs.TryGetValue(dim, out rm)) {
|
||||
return rm;
|
||||
}
|
||||
|
||||
OpenDimension(dim);
|
||||
return _regionMgrs[dim];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a <see cref="PlayerManager"/> for maanging players on multiplayer worlds.
|
||||
/// </summary>
|
||||
/// <returns>A <see cref="PlayerManager"/> for this world.</returns>
|
||||
/// <remarks>To manage the player of a single-player world, get a <see cref="Level"/> object for the world instead.</remarks>
|
||||
public new PlayerManager GetPlayerManager ()
|
||||
{
|
||||
return GetPlayerManagerVirt() as PlayerManager;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Saves the world's <see cref="Level"/> data, and any <see cref="Chunk"/> objects known to have unsaved changes.
|
||||
/// </summary>
|
||||
public void Save ()
|
||||
{
|
||||
_level.Save();
|
||||
|
||||
foreach (KeyValuePair<int, ChunkManager> cm in _chunkMgrs) {
|
||||
cm.Value.Save();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens an existing Beta-compatible Minecraft world and returns a new <see cref="BetaWorld"/> to represent it.
|
||||
/// </summary>
|
||||
/// <param name="path">The path to the directory containing the world's level.dat, or the path to level.dat itself.</param>
|
||||
/// <returns>A new <see cref="BetaWorld"/> object representing an existing world on disk.</returns>
|
||||
public static BetaWorld Open (string path)
|
||||
{
|
||||
return new BetaWorld().OpenWorld(path) as BetaWorld;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new Beta-compatible Minecraft world and returns a new <see cref="BetaWorld"/> to represent it.
|
||||
/// </summary>
|
||||
/// <param name="path">The path to the directory where the new world should be stored.</param>
|
||||
/// <returns>A new <see cref="BetaWorld"/> object representing a new world.</returns>
|
||||
/// <remarks>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.</remarks>
|
||||
public static BetaWorld Create (string path)
|
||||
{
|
||||
return new BetaWorld().CreateWorld(path) as BetaWorld;
|
||||
}
|
||||
|
||||
/// <exclude/>
|
||||
protected override IBlockManager GetBlockManagerVirt (int dim)
|
||||
{
|
||||
BlockManager rm;
|
||||
if (_blockMgrs.TryGetValue(dim, out rm)) {
|
||||
return rm;
|
||||
}
|
||||
|
||||
OpenDimension(dim);
|
||||
return _blockMgrs[dim];
|
||||
}
|
||||
|
||||
/// <exclude/>
|
||||
protected override IChunkManager GetChunkManagerVirt (int dim)
|
||||
{
|
||||
ChunkManager rm;
|
||||
if (_chunkMgrs.TryGetValue(dim, out rm)) {
|
||||
return rm;
|
||||
}
|
||||
|
||||
OpenDimension(dim);
|
||||
return _chunkMgrs[dim];
|
||||
}
|
||||
|
||||
/// <exclude/>
|
||||
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, _REGION_DIR);
|
||||
}
|
||||
else {
|
||||
path = IO.Path.Combine(path, "DIM" + dim);
|
||||
path = IO.Path.Combine(path, _REGION_DIR);
|
||||
}
|
||||
|
||||
if (!Directory.Exists(path)) {
|
||||
Directory.CreateDirectory(path);
|
||||
}
|
||||
|
||||
ChunkCache cc = new ChunkCache();
|
||||
|
||||
RegionManager rm = new RegionManager(path, cc);
|
||||
ChunkManager cm = new ChunkManager(rm, cc);
|
||||
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 = 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 BetaWorld CreateWorld (string path)
|
||||
{
|
||||
if (!Directory.Exists(path)) {
|
||||
throw new DirectoryNotFoundException("Directory '" + path + "' not found");
|
||||
}
|
||||
|
||||
string regpath = IO.Path.Combine(path, _REGION_DIR);
|
||||
if (!Directory.Exists(regpath)) {
|
||||
Directory.CreateDirectory(regpath);
|
||||
}
|
||||
|
||||
Path = path;
|
||||
_level = new Level(this);
|
||||
|
||||
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 {
|
||||
BetaWorld world = new BetaWorld().OpenWorld(e.Path);
|
||||
if (world == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
string regPath = IO.Path.Combine(e.Path, _REGION_DIR);
|
||||
if (!Directory.Exists(regPath)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (world.Level.Version < 19132) {
|
||||
return;
|
||||
}
|
||||
|
||||
e.AddHandler(Open);
|
||||
}
|
||||
catch (Exception) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -12,20 +12,19 @@ namespace Substrate
|
|||
public const int MIN_Z = -32000000;
|
||||
public const int MAX_Z = 32000000;
|
||||
|
||||
protected int _chunkXDim;
|
||||
protected int _chunkYDim;
|
||||
protected int _chunkZDim;
|
||||
protected int _chunkXMask;
|
||||
protected int _chunkYMask;
|
||||
protected int _chunkZMask;
|
||||
protected int _chunkXLog;
|
||||
protected int _chunkYLog;
|
||||
protected int _chunkZLog;
|
||||
protected int chunkXDim;
|
||||
protected int chunkYDim;
|
||||
protected int chunkZDim;
|
||||
protected int chunkXMask;
|
||||
protected int chunkYMask;
|
||||
protected int chunkZMask;
|
||||
protected int chunkXLog;
|
||||
protected int chunkYLog;
|
||||
protected int chunkZLog;
|
||||
|
||||
protected IChunkManager _chunkMan;
|
||||
protected IChunkManager chunkMan;
|
||||
|
||||
protected ChunkRef _cache;
|
||||
protected AlphaBlockCollection _blocks;
|
||||
protected ChunkRef cache;
|
||||
|
||||
private bool _autoLight = true;
|
||||
private bool _autoFluid = false;
|
||||
|
@ -44,56 +43,56 @@ namespace Substrate
|
|||
|
||||
public BlockManager (IChunkManager cm)
|
||||
{
|
||||
_chunkMan = cm;
|
||||
chunkMan = cm;
|
||||
|
||||
Chunk c = Chunk.Create(0, 0);
|
||||
|
||||
_chunkXDim = c.Blocks.XDim;
|
||||
_chunkYDim = c.Blocks.YDim;
|
||||
_chunkZDim = c.Blocks.ZDim;
|
||||
_chunkXMask = _chunkXDim - 1;
|
||||
_chunkYMask = _chunkYDim - 1;
|
||||
_chunkZMask = _chunkZDim - 1;
|
||||
_chunkXLog = Log2(_chunkXDim);
|
||||
_chunkYLog = Log2(_chunkYDim);
|
||||
_chunkZLog = Log2(_chunkZDim);
|
||||
chunkXDim = c.Blocks.XDim;
|
||||
chunkYDim = c.Blocks.YDim;
|
||||
chunkZDim = c.Blocks.ZDim;
|
||||
chunkXMask = chunkXDim - 1;
|
||||
chunkYMask = chunkYDim - 1;
|
||||
chunkZMask = chunkZDim - 1;
|
||||
chunkXLog = Log2(chunkXDim);
|
||||
chunkYLog = Log2(chunkYDim);
|
||||
chunkZLog = Log2(chunkZDim);
|
||||
}
|
||||
|
||||
public AlphaBlock GetBlock (int x, int y, int z)
|
||||
{
|
||||
_cache = GetChunk(x, y, z);
|
||||
if (_cache == null || !Check(x, y, z)) {
|
||||
cache = GetChunk(x, y, z);
|
||||
if (cache == null || !Check(x, y, z)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return _cache.Blocks.GetBlock(x & _chunkXMask, y & _chunkYMask, z & _chunkZMask);
|
||||
return cache.Blocks.GetBlock(x & chunkXMask, y & chunkYMask, z & chunkZMask);
|
||||
}
|
||||
|
||||
public AlphaBlockRef GetBlockRef (int x, int y, int z)
|
||||
{
|
||||
_cache = GetChunk(x, y, z);
|
||||
if (_cache == null || !Check(x, y, z)) {
|
||||
cache = GetChunk(x, y, z);
|
||||
if (cache == null || !Check(x, y, z)) {
|
||||
return new AlphaBlockRef();
|
||||
}
|
||||
|
||||
return _cache.Blocks.GetBlockRef(x & _chunkXMask, y & _chunkYMask, z & _chunkZMask);
|
||||
return cache.Blocks.GetBlockRef(x & chunkXMask, y & chunkYMask, z & chunkZMask);
|
||||
}
|
||||
|
||||
public void SetBlock (int x, int y, int z, AlphaBlock block)
|
||||
{
|
||||
_cache = GetChunk(x, y, z);
|
||||
if (_cache == null || !Check(x, y, z)) {
|
||||
cache = GetChunk(x, y, z);
|
||||
if (cache == null || !Check(x, y, z)) {
|
||||
return;
|
||||
}
|
||||
|
||||
_cache.Blocks.SetBlock(x & _chunkXMask, y & _chunkYMask, z & _chunkZMask, block);
|
||||
cache.Blocks.SetBlock(x & chunkXMask, y & chunkYMask, z & chunkZMask, block);
|
||||
}
|
||||
|
||||
protected ChunkRef GetChunk (int x, int y, int z)
|
||||
{
|
||||
x >>= _chunkXLog;
|
||||
z >>= _chunkZLog;
|
||||
return _chunkMan.GetChunkRef(x, z);
|
||||
x >>= chunkXLog;
|
||||
z >>= chunkZLog;
|
||||
return chunkMan.GetChunkRef(x, z);
|
||||
}
|
||||
|
||||
private int Log2 (int x)
|
||||
|
@ -132,46 +131,46 @@ namespace Substrate
|
|||
|
||||
public void SetBlock (int x, int y, int z, IBlock block)
|
||||
{
|
||||
_cache.Blocks.SetBlock(x, y, z, block);
|
||||
cache.Blocks.SetBlock(x, y, z, block);
|
||||
}
|
||||
|
||||
public BlockInfo GetInfo (int x, int y, int z)
|
||||
{
|
||||
_cache = GetChunk(x, y, z);
|
||||
if (_cache == null || !Check(x, y, z)) {
|
||||
cache = GetChunk(x, y, z);
|
||||
if (cache == null || !Check(x, y, z)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return _cache.Blocks.GetInfo(x & _chunkXMask, y & _chunkYMask, z & _chunkZMask);
|
||||
return cache.Blocks.GetInfo(x & chunkXMask, y & chunkYMask, z & chunkZMask);
|
||||
}
|
||||
|
||||
public int GetID (int x, int y, int z)
|
||||
{
|
||||
_cache = GetChunk(x, y, z);
|
||||
if (_cache == null) {
|
||||
cache = GetChunk(x, y, z);
|
||||
if (cache == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return _cache.Blocks.GetID(x & _chunkXMask, y & _chunkYMask, z & _chunkZMask);
|
||||
return cache.Blocks.GetID(x & chunkXMask, y & chunkYMask, z & chunkZMask);
|
||||
}
|
||||
|
||||
public void SetID (int x, int y, int z, int id)
|
||||
{
|
||||
_cache = GetChunk(x, y, z);
|
||||
if (_cache == null || !Check(x, y, z)) {
|
||||
cache = GetChunk(x, y, z);
|
||||
if (cache == null || !Check(x, y, z)) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool autolight = _cache.Blocks.AutoLight;
|
||||
bool autofluid = _cache.Blocks.AutoFluid;
|
||||
bool autolight = cache.Blocks.AutoLight;
|
||||
bool autofluid = cache.Blocks.AutoFluid;
|
||||
|
||||
_cache.Blocks.AutoLight = _autoLight;
|
||||
_cache.Blocks.AutoFluid = _autoFluid;
|
||||
cache.Blocks.AutoLight = _autoLight;
|
||||
cache.Blocks.AutoFluid = _autoFluid;
|
||||
|
||||
_cache.Blocks.SetID(x & _chunkXMask, y & _chunkYMask, z & _chunkZMask, id);
|
||||
cache.Blocks.SetID(x & chunkXMask, y & chunkYMask, z & chunkZMask, id);
|
||||
|
||||
_cache.Blocks.AutoFluid = autofluid;
|
||||
_cache.Blocks.AutoLight = autolight;
|
||||
cache.Blocks.AutoFluid = autofluid;
|
||||
cache.Blocks.AutoLight = autolight;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
@ -191,27 +190,27 @@ namespace Substrate
|
|||
|
||||
public void SetBlock (int x, int y, int z, IDataBlock block)
|
||||
{
|
||||
_cache.Blocks.SetBlock(x, y, z, block);
|
||||
cache.Blocks.SetBlock(x, y, z, block);
|
||||
}
|
||||
|
||||
public int GetData (int x, int y, int z)
|
||||
{
|
||||
_cache = GetChunk(x, y, z);
|
||||
if (_cache == null) {
|
||||
cache = GetChunk(x, y, z);
|
||||
if (cache == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return _cache.Blocks.GetData(x & _chunkXMask, y & _chunkYMask, z & _chunkZMask);
|
||||
return cache.Blocks.GetData(x & chunkXMask, y & chunkYMask, z & chunkZMask);
|
||||
}
|
||||
|
||||
public void SetData (int x, int y, int z, int data)
|
||||
{
|
||||
_cache = GetChunk(x, y, z);
|
||||
if (_cache == null || !Check(x, y, z)) {
|
||||
cache = GetChunk(x, y, z);
|
||||
if (cache == null || !Check(x, y, z)) {
|
||||
return;
|
||||
}
|
||||
|
||||
_cache.Blocks.SetData(x & _chunkXMask, y & _chunkYMask, z & _chunkZMask, data);
|
||||
cache.Blocks.SetData(x & chunkXMask, y & chunkYMask, z & chunkZMask, data);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
@ -231,87 +230,87 @@ namespace Substrate
|
|||
|
||||
public void SetBlock (int x, int y, int z, ILitBlock block)
|
||||
{
|
||||
_cache.Blocks.SetBlock(x, y, z, block);
|
||||
cache.Blocks.SetBlock(x, y, z, block);
|
||||
}
|
||||
|
||||
public int GetBlockLight (int x, int y, int z)
|
||||
{
|
||||
_cache = GetChunk(x, y, z);
|
||||
if (_cache == null) {
|
||||
cache = GetChunk(x, y, z);
|
||||
if (cache == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return _cache.Blocks.GetBlockLight(x & _chunkXMask, y & _chunkYMask, z & _chunkZMask);
|
||||
return cache.Blocks.GetBlockLight(x & chunkXMask, y & chunkYMask, z & chunkZMask);
|
||||
}
|
||||
|
||||
public int GetSkyLight (int x, int y, int z)
|
||||
{
|
||||
_cache = GetChunk(x, y, z);
|
||||
if (_cache == null) {
|
||||
cache = GetChunk(x, y, z);
|
||||
if (cache == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return _cache.Blocks.GetSkyLight(x & _chunkXMask, y & _chunkYMask, z & _chunkZMask);
|
||||
return cache.Blocks.GetSkyLight(x & chunkXMask, y & chunkYMask, z & chunkZMask);
|
||||
}
|
||||
|
||||
public void SetBlockLight (int x, int y, int z, int light)
|
||||
{
|
||||
_cache = GetChunk(x, y, z);
|
||||
if (_cache == null || !Check(x, y, z)) {
|
||||
cache = GetChunk(x, y, z);
|
||||
if (cache == null || !Check(x, y, z)) {
|
||||
return;
|
||||
}
|
||||
|
||||
_cache.Blocks.SetBlockLight(x & _chunkXMask, y & _chunkYMask, z & _chunkZMask, light);
|
||||
cache.Blocks.SetBlockLight(x & chunkXMask, y & chunkYMask, z & chunkZMask, light);
|
||||
}
|
||||
|
||||
public void SetSkyLight (int x, int y, int z, int light)
|
||||
{
|
||||
_cache = GetChunk(x, y, z);
|
||||
if (_cache == null || !Check(x, y, z)) {
|
||||
cache = GetChunk(x, y, z);
|
||||
if (cache == null || !Check(x, y, z)) {
|
||||
return;
|
||||
}
|
||||
|
||||
_cache.Blocks.SetSkyLight(x & _chunkXMask, y & _chunkYMask, z & _chunkZMask, light);
|
||||
cache.Blocks.SetSkyLight(x & chunkXMask, y & chunkYMask, z & chunkZMask, light);
|
||||
}
|
||||
|
||||
public int GetHeight (int x, int z)
|
||||
{
|
||||
_cache = GetChunk(x, 0, z);
|
||||
if (_cache == null || !Check(x, 0, z)) {
|
||||
cache = GetChunk(x, 0, z);
|
||||
if (cache == null || !Check(x, 0, z)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return _cache.Blocks.GetHeight(x & _chunkXMask, z & _chunkZMask);
|
||||
return cache.Blocks.GetHeight(x & chunkXMask, z & chunkZMask);
|
||||
}
|
||||
|
||||
public void SetHeight (int x, int z, int height)
|
||||
{
|
||||
_cache = GetChunk(x, 0, z);
|
||||
if (_cache == null || !Check(x, 0, z)) {
|
||||
cache = GetChunk(x, 0, z);
|
||||
if (cache == null || !Check(x, 0, z)) {
|
||||
return;
|
||||
}
|
||||
|
||||
_cache.Blocks.SetHeight(x & _chunkXMask, z & _chunkZMask, height);
|
||||
cache.Blocks.SetHeight(x & chunkXMask, z & chunkZMask, height);
|
||||
}
|
||||
|
||||
public void UpdateBlockLight (int x, int y, int z)
|
||||
{
|
||||
_cache = GetChunk(x, y, z);
|
||||
if (_cache == null || !Check(x, y, z)) {
|
||||
cache = GetChunk(x, y, z);
|
||||
if (cache == null || !Check(x, y, z)) {
|
||||
return;
|
||||
}
|
||||
|
||||
_cache.Blocks.UpdateBlockLight(x & _chunkXMask, y & _chunkYMask, z & _chunkZMask);
|
||||
cache.Blocks.UpdateBlockLight(x & chunkXMask, y & chunkYMask, z & chunkZMask);
|
||||
}
|
||||
|
||||
public void UpdateSkyLight (int x, int y, int z)
|
||||
{
|
||||
_cache = GetChunk(x, y, z);
|
||||
if (_cache == null || !Check(x, y, z)) {
|
||||
cache = GetChunk(x, y, z);
|
||||
if (cache == null || !Check(x, y, z)) {
|
||||
return;
|
||||
}
|
||||
|
||||
_cache.Blocks.UpdateBlockLight(x & _chunkXMask, y & _chunkYMask, z & _chunkZMask);
|
||||
cache.Blocks.UpdateBlockLight(x & chunkXMask, y & chunkYMask, z & chunkZMask);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
@ -331,47 +330,47 @@ namespace Substrate
|
|||
|
||||
public void SetBlock (int x, int y, int z, IPropertyBlock block)
|
||||
{
|
||||
_cache.Blocks.SetBlock(x, y, z, block);
|
||||
cache.Blocks.SetBlock(x, y, z, block);
|
||||
}
|
||||
|
||||
public TileEntity GetTileEntity (int x, int y, int z)
|
||||
{
|
||||
_cache = GetChunk(x, y, z);
|
||||
if (_cache == null || !Check(x, y, z)) {
|
||||
cache = GetChunk(x, y, z);
|
||||
if (cache == null || !Check(x, y, z)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return _cache.Blocks.GetTileEntity(x & _chunkXMask, y & _chunkYMask, z & _chunkZMask);
|
||||
return cache.Blocks.GetTileEntity(x & chunkXMask, y & chunkYMask, z & chunkZMask);
|
||||
}
|
||||
|
||||
public void SetTileEntity (int x, int y, int z, TileEntity te)
|
||||
{
|
||||
_cache = GetChunk(x, y, z);
|
||||
if (_cache == null || !Check(x, y, z)) {
|
||||
cache = GetChunk(x, y, z);
|
||||
if (cache == null || !Check(x, y, z)) {
|
||||
return;
|
||||
}
|
||||
|
||||
_cache.Blocks.SetTileEntity(x & _chunkXMask, y & _chunkYMask, z & _chunkZMask, te);
|
||||
cache.Blocks.SetTileEntity(x & chunkXMask, y & chunkYMask, z & chunkZMask, te);
|
||||
}
|
||||
|
||||
public void CreateTileEntity (int x, int y, int z)
|
||||
{
|
||||
_cache = GetChunk(x, y, z);
|
||||
if (_cache == null || !Check(x, y, z)) {
|
||||
cache = GetChunk(x, y, z);
|
||||
if (cache == null || !Check(x, y, z)) {
|
||||
return;
|
||||
}
|
||||
|
||||
_cache.Blocks.CreateTileEntity(x & _chunkXMask, y & _chunkYMask, z & _chunkZMask);
|
||||
cache.Blocks.CreateTileEntity(x & chunkXMask, y & chunkYMask, z & chunkZMask);
|
||||
}
|
||||
|
||||
public void ClearTileEntity (int x, int y, int z)
|
||||
{
|
||||
_cache = GetChunk(x, y, z);
|
||||
if (_cache == null || !Check(x, y, z)) {
|
||||
cache = GetChunk(x, y, z);
|
||||
if (cache == null || !Check(x, y, z)) {
|
||||
return;
|
||||
}
|
||||
|
||||
_cache.Blocks.ClearTileEntity(x & _chunkXMask, y & _chunkYMask, z & _chunkZMask);
|
||||
cache.Blocks.ClearTileEntity(x & chunkXMask, y & chunkYMask, z & chunkZMask);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
|
|
@ -124,7 +124,6 @@ namespace Substrate
|
|||
c._cz = z;
|
||||
|
||||
c.BuildNBTTree();
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
|
|
|
@ -6,29 +6,29 @@ namespace Substrate.Core
|
|||
{
|
||||
public class ByteArray : ICopyable<ByteArray>
|
||||
{
|
||||
protected readonly byte[] _data;
|
||||
protected readonly byte[] dataArray;
|
||||
|
||||
public ByteArray (byte[] data)
|
||||
{
|
||||
_data = data;
|
||||
dataArray = data;
|
||||
}
|
||||
|
||||
public byte this[int i]
|
||||
{
|
||||
get { return _data[i]; }
|
||||
set { _data[i] = value; }
|
||||
get { return dataArray[i]; }
|
||||
set { dataArray[i] = value; }
|
||||
}
|
||||
|
||||
public int Length
|
||||
{
|
||||
get { return _data.Length; }
|
||||
get { return dataArray.Length; }
|
||||
}
|
||||
|
||||
public void Clear ()
|
||||
{
|
||||
for (int i = 0; i < _data.Length; i++)
|
||||
for (int i = 0; i < dataArray.Length; i++)
|
||||
{
|
||||
_data[i] = 0;
|
||||
dataArray[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -36,8 +36,8 @@ namespace Substrate.Core
|
|||
|
||||
public virtual ByteArray Copy ()
|
||||
{
|
||||
byte[] data = new byte[_data.Length];
|
||||
_data.CopyTo(data, 0);
|
||||
byte[] data = new byte[dataArray.Length];
|
||||
dataArray.CopyTo(data, 0);
|
||||
|
||||
return new ByteArray(data);
|
||||
}
|
||||
|
@ -69,13 +69,13 @@ namespace Substrate.Core
|
|||
get
|
||||
{
|
||||
int index = _ydim * (x * _zdim + z) + y;
|
||||
return _data[index];
|
||||
return dataArray[index];
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
int index = _ydim * (x * _zdim + z) + y;
|
||||
_data[index] = value;
|
||||
dataArray[index] = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -113,8 +113,8 @@ namespace Substrate.Core
|
|||
|
||||
public override ByteArray Copy ()
|
||||
{
|
||||
byte[] data = new byte[_data.Length];
|
||||
_data.CopyTo(data, 0);
|
||||
byte[] data = new byte[dataArray.Length];
|
||||
dataArray.CopyTo(data, 0);
|
||||
|
||||
return new XZYByteArray(_xdim, _ydim, _zdim, data);
|
||||
}
|
||||
|
@ -144,13 +144,13 @@ namespace Substrate.Core
|
|||
get
|
||||
{
|
||||
int index = z * _xdim + x;
|
||||
return _data[index];
|
||||
return dataArray[index];
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
int index = z * _xdim + x;
|
||||
_data[index] = value;
|
||||
dataArray[index] = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -168,8 +168,8 @@ namespace Substrate.Core
|
|||
|
||||
public override ByteArray Copy ()
|
||||
{
|
||||
byte[] data = new byte[_data.Length];
|
||||
_data.CopyTo(data, 0);
|
||||
byte[] data = new byte[dataArray.Length];
|
||||
dataArray.CopyTo(data, 0);
|
||||
|
||||
return new ZXByteArray(_xdim, _zdim, data);
|
||||
}
|
||||
|
|
|
@ -224,7 +224,7 @@ namespace Substrate.Core
|
|||
|
||||
public IEnumerator<ChunkRef> GetEnumerator ()
|
||||
{
|
||||
return new ChunkEnumerator(this);
|
||||
return new Enumerator(this);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
@ -233,13 +233,13 @@ namespace Substrate.Core
|
|||
|
||||
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator ()
|
||||
{
|
||||
return new ChunkEnumerator(this);
|
||||
return new Enumerator(this);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
public class ChunkEnumerator : IEnumerator<ChunkRef>
|
||||
private class Enumerator : IEnumerator<ChunkRef>
|
||||
{
|
||||
protected ChunkFileManager _cm;
|
||||
protected Queue<string> _tld;
|
||||
|
@ -250,7 +250,7 @@ namespace Substrate.Core
|
|||
private string _cursld;
|
||||
private ChunkRef _curchunk;
|
||||
|
||||
public ChunkEnumerator (ChunkFileManager cfm)
|
||||
public Enumerator (ChunkFileManager cfm)
|
||||
{
|
||||
_cm = cfm;
|
||||
|
||||
|
|
59
Substrate/SubstrateCS/Source/Core/OpenWorldEvent.cs
Normal file
59
Substrate/SubstrateCS/Source/Core/OpenWorldEvent.cs
Normal file
|
@ -0,0 +1,59 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Substrate.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// A callback function to open a world and return it as an instance of a concrete derivative of <see cref="NbtWorld"/>.
|
||||
/// </summary>
|
||||
/// <param name="path">The path to the directory of the world to open.</param>
|
||||
/// <returns>An instance of a concrete derivative of <see cref="NbtWorld"/>.</returns>
|
||||
public delegate NbtWorld OpenWorldCallback (string path);
|
||||
|
||||
/// <summary>
|
||||
/// Event arugments and response data for any handlers trying to determine if they can open a given world.
|
||||
/// </summary>
|
||||
public class OpenWorldEventArgs : EventArgs
|
||||
{
|
||||
private List<OpenWorldCallback> _handlers;
|
||||
private string _path;
|
||||
|
||||
/// <summary>
|
||||
/// Create a new instance of event arguments.
|
||||
/// </summary>
|
||||
/// <param name="path">The path to the directory of a world.</param>
|
||||
public OpenWorldEventArgs (string path)
|
||||
: base()
|
||||
{
|
||||
_path = path;
|
||||
_handlers = new List<OpenWorldCallback>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the path to the directory of a world being investigated.
|
||||
/// </summary>
|
||||
public string Path
|
||||
{
|
||||
get { return _path; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds an <see cref="OpenWorldCallback"/> delegate that can open a world and return a corresponding <see cref="NbtWorld"/> object.
|
||||
/// </summary>
|
||||
/// <param name="callback">The delegate to return to the code that raised the event.</param>
|
||||
public void AddHandler (OpenWorldCallback callback)
|
||||
{
|
||||
_handlers.Add(callback);
|
||||
}
|
||||
|
||||
internal int HandlerCount
|
||||
{
|
||||
get { return _handlers.Count; }
|
||||
}
|
||||
|
||||
internal ICollection<OpenWorldCallback> Handlers
|
||||
{
|
||||
get { return _handlers; }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -300,7 +300,7 @@ namespace Substrate
|
|||
/// <summary>
|
||||
/// Gets a <see cref="SchemaNode"/> representing the basic schema of an Entity.
|
||||
/// </summary>
|
||||
public static SchemaNodeCompound Schema
|
||||
public static new SchemaNodeCompound Schema
|
||||
{
|
||||
get { return _schema; }
|
||||
}
|
||||
|
|
|
@ -5,9 +5,12 @@ using Substrate.Nbt;
|
|||
|
||||
namespace Substrate
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents general data and metadata of a single world.
|
||||
/// </summary>
|
||||
public class Level : INbtObject<Level>, ICopyable<Level>
|
||||
{
|
||||
public static SchemaNodeCompound LevelSchema = new SchemaNodeCompound()
|
||||
private static SchemaNodeCompound _schema = new SchemaNodeCompound()
|
||||
{
|
||||
new SchemaNodeCompound("Data")
|
||||
{
|
||||
|
@ -28,7 +31,7 @@ namespace Substrate
|
|||
},
|
||||
};
|
||||
|
||||
private INBTWorld _world;
|
||||
private NbtWorld _world;
|
||||
|
||||
private long _time;
|
||||
private long _lastPlayed;
|
||||
|
@ -49,17 +52,27 @@ namespace Substrate
|
|||
private int? _rainTime;
|
||||
private int? _thunderTime;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the creation time of the world as a long timestamp.
|
||||
/// </summary>
|
||||
public long Time
|
||||
{
|
||||
get { return _time; }
|
||||
set { _time = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the time that the world was last played as a long timestamp.
|
||||
/// </summary>
|
||||
public long LastPlayed
|
||||
{
|
||||
get { return _lastPlayed; }
|
||||
set { _lastPlayed = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the player for single-player worlds.
|
||||
/// </summary>
|
||||
public Player Player
|
||||
{
|
||||
get { return _player; }
|
||||
|
@ -70,41 +83,51 @@ namespace Substrate
|
|||
}
|
||||
}
|
||||
|
||||
public int SpawnX
|
||||
/// <summary>
|
||||
/// Gets or sets the world's spawn point.
|
||||
/// </summary>
|
||||
public SpawnPoint Spawn
|
||||
{
|
||||
get { return _spawnX; }
|
||||
set { _spawnX = value; }
|
||||
}
|
||||
|
||||
public int SpawnY
|
||||
{
|
||||
get { return _spawnY; }
|
||||
set { _spawnY = value; }
|
||||
}
|
||||
|
||||
public int SpawnZ
|
||||
{
|
||||
get { return _spawnZ; }
|
||||
set { _spawnZ = value; }
|
||||
get { return new SpawnPoint(_spawnX, _spawnY, _spawnZ); }
|
||||
set
|
||||
{
|
||||
_spawnX = value.X;
|
||||
_spawnY = value.Y;
|
||||
_spawnZ = value.Z;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the estimated size of the world in bytes.
|
||||
/// </summary>
|
||||
public long SizeOnDisk
|
||||
{
|
||||
get { return _sizeOnDisk; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the world's random seed.
|
||||
/// </summary>
|
||||
public long RandomSeed
|
||||
{
|
||||
get { return _randomSeed; }
|
||||
set { _randomSeed = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the world's version number.
|
||||
/// </summary>
|
||||
public int Version
|
||||
{
|
||||
get { return _version ?? 0; }
|
||||
set { _version = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the name of the world.
|
||||
/// </summary>
|
||||
/// <remarks>If there is a <see cref="Player"/> object attached to this world, the player's world field
|
||||
/// will also be updated.</remarks>
|
||||
public string LevelName
|
||||
{
|
||||
get { return _name; }
|
||||
|
@ -117,31 +140,55 @@ namespace Substrate
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating that it is raining in the world.
|
||||
/// </summary>
|
||||
public bool IsRaining
|
||||
{
|
||||
get { return (_raining ?? 0) == 1; }
|
||||
set { _raining = value ? (byte)1 : (byte)0; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating that it is thunderstorming in the world.
|
||||
/// </summary>
|
||||
public bool IsThundering
|
||||
{
|
||||
get { return (_thundering ?? 0) == 1; }
|
||||
set { _thundering = value ? (byte)1 : (byte)0; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the timer value for controlling rain.
|
||||
/// </summary>
|
||||
public int RainTime
|
||||
{
|
||||
get { return _rainTime ?? 0; }
|
||||
set { _rainTime = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the timer value for controlling thunderstorms.
|
||||
/// </summary>
|
||||
public int ThunderTime
|
||||
{
|
||||
get { return _thunderTime ?? 0; }
|
||||
set { _thunderTime = value; }
|
||||
}
|
||||
|
||||
public Level (INBTWorld world)
|
||||
/// <summary>
|
||||
/// Gets a <see cref="SchemaNode"/> representing the schema of a level.
|
||||
/// </summary>
|
||||
public static SchemaNodeCompound Schema
|
||||
{
|
||||
get { return _schema; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="Level"/> object with reasonable defaults tied to the given world.
|
||||
/// </summary>
|
||||
/// <param name="world">The world that the <see cref="Level"/> should be tied to.</param>
|
||||
public Level (NbtWorld world)
|
||||
{
|
||||
_world = world;
|
||||
|
||||
|
@ -157,7 +204,11 @@ namespace Substrate
|
|||
_name = "Untitled";
|
||||
}
|
||||
|
||||
public Level (Level p)
|
||||
/// <summary>
|
||||
/// Creates a copy of an existing <see cref="Level"/> object.
|
||||
/// </summary>
|
||||
/// <param name="p">The <see cref="Level"/> object to copy.</param>
|
||||
protected Level (Level p)
|
||||
{
|
||||
_world = p._world;
|
||||
|
||||
|
@ -181,6 +232,9 @@ namespace Substrate
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a default player entry for this world.
|
||||
/// </summary>
|
||||
public void SetDefaultPlayer ()
|
||||
{
|
||||
_player = new Player();
|
||||
|
@ -191,27 +245,46 @@ namespace Substrate
|
|||
_player.Position.Z = _spawnZ;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Saves a <see cref="Level"/> object to disk as a standard compressed NBT stream.
|
||||
/// </summary>
|
||||
/// <returns>True if the level was saved; false otherwise.</returns>
|
||||
/// <exception cref="LevelIOException">Thrown when an error is encountered writing out the level.</exception>
|
||||
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;
|
||||
try {
|
||||
NBTFile nf = new NBTFile(Path.Combine(_world.Path, "level.dat"));
|
||||
Stream zipstr = nf.GetDataOutputStream();
|
||||
if (zipstr == null) {
|
||||
NbtIOException nex = new NbtIOException("Failed to initialize compressed NBT stream for output");
|
||||
nex.Data["Level"] = this;
|
||||
throw nex;
|
||||
}
|
||||
|
||||
new NbtTree(BuildTree() as TagNodeCompound).WriteTo(zipstr);
|
||||
zipstr.Close();
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex) {
|
||||
LevelIOException lex = new LevelIOException("Could not save level file.", ex);
|
||||
lex.Data["Level"] = this;
|
||||
throw lex;
|
||||
}
|
||||
|
||||
new NbtTree(BuildTree() as TagNodeCompound).WriteTo(zipstr);
|
||||
zipstr.Close();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
#region INBTObject<Player> Members
|
||||
|
||||
/// <summary>
|
||||
/// Attempt to load a Level subtree into the <see cref="Level"/> without validation.
|
||||
/// </summary>
|
||||
/// <param name="tree">The root node of a Level subtree.</param>
|
||||
/// <returns>The <see cref="Level"/> returns itself on success, or null if the tree was unparsable.</returns>
|
||||
public virtual Level LoadTree (TagNode tree)
|
||||
{
|
||||
TagNodeCompound dtree = tree as TagNodeCompound;
|
||||
|
@ -264,6 +337,11 @@ namespace Substrate
|
|||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempt to load a Level subtree into the <see cref="Level"/> with validation.
|
||||
/// </summary>
|
||||
/// <param name="tree">The root node of a Level subtree.</param>
|
||||
/// <returns>The <see cref="Level"/> returns itself on success, or null if the tree failed validation.</returns>
|
||||
public virtual Level LoadTreeSafe (TagNode tree)
|
||||
{
|
||||
if (!ValidateTree(tree)) {
|
||||
|
@ -273,6 +351,10 @@ namespace Substrate
|
|||
return LoadTree(tree);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Builds a Level subtree from the current data.
|
||||
/// </summary>
|
||||
/// <returns>The root node of a Level subtree representing the current data.</returns>
|
||||
public virtual TagNode BuildTree ()
|
||||
{
|
||||
TagNodeCompound data = new TagNodeCompound();
|
||||
|
@ -316,9 +398,14 @@ namespace Substrate
|
|||
return tree;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validate a Level subtree against a schema defintion.
|
||||
/// </summary>
|
||||
/// <param name="tree">The root node of a Level subtree.</param>
|
||||
/// <returns>Status indicating whether the tree was valid against the internal schema.</returns>
|
||||
public virtual bool ValidateTree (TagNode tree)
|
||||
{
|
||||
return new NbtVerifier(tree, LevelSchema).Verify();
|
||||
return new NbtVerifier(tree, _schema).Verify();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
@ -326,6 +413,10 @@ namespace Substrate
|
|||
|
||||
#region ICopyable<Entity> Members
|
||||
|
||||
/// <summary>
|
||||
/// Creates a deep-copy of the <see cref="Level"/>.
|
||||
/// </summary>
|
||||
/// <returns>A deep-copy of the <see cref="Level"/>, including a copy of the <see cref="Player"/>, if one is attached.</returns>
|
||||
public virtual Level Copy ()
|
||||
{
|
||||
return new Level(this);
|
||||
|
|
46
Substrate/SubstrateCS/Source/LevelIOException.cs
Normal file
46
Substrate/SubstrateCS/Source/LevelIOException.cs
Normal file
|
@ -0,0 +1,46 @@
|
|||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Substrate
|
||||
{
|
||||
/// <summary>
|
||||
/// The exception that is thrown when IO errors occur during level management operations.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class LevelIOException : SubstrateException
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="LevelIOException"/> class.
|
||||
/// </summary>
|
||||
public LevelIOException ()
|
||||
: base()
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="LevelIOException"/> class with a custom error message.
|
||||
/// </summary>
|
||||
/// <param name="message">A custom error message.</param>
|
||||
public LevelIOException (string message)
|
||||
: base(message)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="LevelIOException"/> class with a custom error message and a reference to
|
||||
/// an InnerException representing the original cause of the exception.
|
||||
/// </summary>
|
||||
/// <param name="message">A custom error message.</param>
|
||||
/// <param name="innerException">A reference to the original exception that caused the error.</param>
|
||||
public LevelIOException (string message, Exception innerException)
|
||||
: base(message, innerException)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="LevelIOException"/> class with serialized data.
|
||||
/// </summary>
|
||||
/// <param name="info">The object that holds the serialized object data.</param>
|
||||
/// <param name="context">The contextual information about the source or destination.</param>
|
||||
protected LevelIOException (SerializationInfo info, StreamingContext context)
|
||||
: base(info, context)
|
||||
{ }
|
||||
}
|
||||
}
|
|
@ -9,7 +9,7 @@ namespace Substrate.Nbt
|
|||
/// <remarks>In most cases, the <see cref="InnerException"/> property will contain more detailed information on the
|
||||
/// error that occurred.</remarks>
|
||||
[Serializable]
|
||||
public class NbtIOException : Exception
|
||||
public class NbtIOException : SubstrateException
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="NbtIOException"/> class.
|
||||
|
|
150
Substrate/SubstrateCS/Source/NbtWorld.cs
Normal file
150
Substrate/SubstrateCS/Source/NbtWorld.cs
Normal file
|
@ -0,0 +1,150 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using Substrate.Core;
|
||||
using Substrate.Nbt;
|
||||
|
||||
namespace Substrate
|
||||
{
|
||||
/// <summary>
|
||||
/// An abstract representation of any conforming chunk-based world.
|
||||
/// </summary>
|
||||
/// <remarks><para>By default, NbtWorld registers handlers to check if a given world can be opened as an <see cref="AlphaWorld"/> or
|
||||
/// a <see cref="BetaWorld"/>, which are used by <see cref="NbtWorld"/>'s generic <see cref="Open(string)"/> method to automatically
|
||||
/// detect a world's type and open it.</para>
|
||||
/// <para>Advanced implementors can support loading other Nbt-compatible world formats by extending <see cref="NbtWorld"/> and registering
|
||||
/// an event handler with the <see cref="ResolveOpen"/> event, which will allow the generic <see cref="Open(string)"/> method to
|
||||
/// open worlds of the new format.</para></remarks>
|
||||
public abstract class NbtWorld
|
||||
{
|
||||
private string _path;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of an <see cref="NbtWorld"/> object.
|
||||
/// </summary>
|
||||
protected NbtWorld () { }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the path to the directory containing the world.
|
||||
/// </summary>
|
||||
public string Path
|
||||
{
|
||||
get { return _path; }
|
||||
set { _path = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a reference to this world's <see cref="Level"/> object.
|
||||
/// </summary>
|
||||
public abstract Level Level { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets an <see cref="IBlockManager"/> for the default dimension.
|
||||
/// </summary>
|
||||
/// <returns>An <see cref="IBlockManager"/> tied to the default dimension in this world.</returns>
|
||||
public IBlockManager GetBlockManager ()
|
||||
{
|
||||
return GetBlockManagerVirt(Dimension.DEFAULT);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets an <see cref="IBlockManager"/> for the given dimension.
|
||||
/// </summary>
|
||||
/// <param name="dim">The id of the dimension to look up.</param>
|
||||
/// <returns>An <see cref="IBlockManager"/> tied to the given dimension in this world.</returns>
|
||||
public IBlockManager GetBlockManager (int dim)
|
||||
{
|
||||
return GetBlockManagerVirt(dim);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets an <see cref="IChunkManager"/> for the default dimension.
|
||||
/// </summary>
|
||||
/// <returns>An <see cref="IChunkManager"/> tied to the default dimension in this world.</returns>
|
||||
public IChunkManager GetChunkManager ()
|
||||
{
|
||||
return GetChunkManagerVirt(Dimension.DEFAULT);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets an <see cref="IChunkManager"/> for the given dimension.
|
||||
/// </summary>
|
||||
/// <param name="dim">The id of the dimension to look up.</param>
|
||||
/// <returns>An <see cref="IChunkManager"/> tied to the given dimension in this world.</returns>
|
||||
public IChunkManager GetChunkManager (int dim)
|
||||
{
|
||||
return GetChunkManagerVirt(dim);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets an <see cref="IPlayerManager"/> for maanging players on multiplayer worlds.
|
||||
/// </summary>
|
||||
/// <returns>An <see cref="IPlayerManager"/> for this world.</returns>
|
||||
public IPlayerManager GetPlayerManager ()
|
||||
{
|
||||
return GetPlayerManagerVirt();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to determine the best matching world type of the given path, and open the world as that type.
|
||||
/// </summary>
|
||||
/// <param name="path">The path to the directory containing the world.</param>
|
||||
/// <returns>A concrete <see cref="NbtWorld"/> type, or null if the world cannot be opened or is ambiguos.</returns>
|
||||
public static NbtWorld Open (string path)
|
||||
{
|
||||
if (ResolveOpen == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
OpenWorldEventArgs eventArgs = new OpenWorldEventArgs(path);
|
||||
ResolveOpen(null, eventArgs);
|
||||
|
||||
if (eventArgs.HandlerCount != 1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
foreach (OpenWorldCallback callback in eventArgs.Handlers) {
|
||||
return callback(path);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raised when <see cref="Open"/> is called, used to find a concrete <see cref="NbtWorld"/> type that can open the world.
|
||||
/// </summary>
|
||||
protected static event EventHandler<OpenWorldEventArgs> ResolveOpen;
|
||||
|
||||
#region Covariant Return-Type Helpers
|
||||
|
||||
/// <summary>
|
||||
/// Virtual implementor of <see cref="GetBlockManager(int)"/>.
|
||||
/// </summary>
|
||||
/// <param name="dim">The given dimension to fetch an <see cref="IBlockManager"/> for.</param>
|
||||
/// <returns>An <see cref="IBlockManager"/> for the given dimension in the world.</returns>
|
||||
protected abstract IBlockManager GetBlockManagerVirt (int dim);
|
||||
|
||||
/// <summary>
|
||||
/// Virtual implementor of <see cref="GetChunkManager(int)"/>.
|
||||
/// </summary>
|
||||
/// <param name="dim">The given dimension to fetch an <see cref="IChunkManager"/> for.</param>
|
||||
/// <returns>An <see cref="IChunkManager"/> for the given dimension in the world.</returns>
|
||||
protected abstract IChunkManager GetChunkManagerVirt (int dim);
|
||||
|
||||
/// <summary>
|
||||
/// Virtual implementor of <see cref="GetPlayerManager"/>.
|
||||
/// </summary>
|
||||
/// <returns>An <see cref="IPlayerManager"/> for the given dimension in the world.</returns>
|
||||
protected abstract IPlayerManager GetPlayerManagerVirt ();
|
||||
|
||||
#endregion
|
||||
|
||||
static NbtWorld ()
|
||||
{
|
||||
ResolveOpen += AlphaWorld.OnResolveOpen;
|
||||
ResolveOpen += BetaWorld.OnResolveOpen;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -197,7 +197,7 @@ namespace Substrate
|
|||
/// <summary>
|
||||
/// Gets a <see cref="SchemaNode"/> representing the schema of a Player.
|
||||
/// </summary>
|
||||
public static SchemaNodeCompound Schema
|
||||
public static new SchemaNodeCompound Schema
|
||||
{
|
||||
get { return _schema; }
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ namespace Substrate
|
|||
/// The exception that is thrown when IO errors occur during high-level player management operations.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class PlayerIOException : Exception
|
||||
public class PlayerIOException : SubstrateException
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PlayerIOException"/> class.
|
||||
|
|
46
Substrate/SubstrateCS/Source/SubstrateException.cs
Normal file
46
Substrate/SubstrateCS/Source/SubstrateException.cs
Normal file
|
@ -0,0 +1,46 @@
|
|||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Substrate
|
||||
{
|
||||
/// <summary>
|
||||
/// A base class for all Substrate-related exception classes.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class SubstrateException : Exception
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SubstrateException"/> class.
|
||||
/// </summary>
|
||||
public SubstrateException ()
|
||||
: base()
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SubstrateException"/> class with a custom error message.
|
||||
/// </summary>
|
||||
/// <param name="message">A custom error message.</param>
|
||||
public SubstrateException (string message)
|
||||
: base(message)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SubstrateException"/> class with a custom error message and a reference to
|
||||
/// an InnerException representing the original cause of the exception.
|
||||
/// </summary>
|
||||
/// <param name="message">A custom error message.</param>
|
||||
/// <param name="innerException">A reference to the original exception that caused the error.</param>
|
||||
public SubstrateException (string message, Exception innerException)
|
||||
: base(message, innerException)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SubstrateException"/> class with serialized data.
|
||||
/// </summary>
|
||||
/// <param name="info">The object that holds the serialized object data.</param>
|
||||
/// <param name="context">The contextual information about the source or destination.</param>
|
||||
protected SubstrateException (SerializationInfo info, StreamingContext context)
|
||||
: base(info, context)
|
||||
{ }
|
||||
}
|
||||
}
|
|
@ -13,433 +13,5 @@ namespace Substrate
|
|||
public const int DEFAULT = 0;
|
||||
}
|
||||
|
||||
public interface INBTWorld
|
||||
{
|
||||
string WorldPath { get; }
|
||||
|
||||
Level Level { get; }
|
||||
|
||||
void Save ();
|
||||
|
||||
IBlockManager GetBlockManager ();
|
||||
IBlockManager GetBlockManager (int dim);
|
||||
|
||||
IChunkManager GetChunkManager ();
|
||||
IChunkManager GetChunkManager (int dim);
|
||||
|
||||
PlayerManager GetPlayerManager ();
|
||||
}
|
||||
|
||||
public class AlphaWorld : INBTWorld
|
||||
{
|
||||
private const string _PLAYER_DIR = "players";
|
||||
protected string _path;
|
||||
protected string _levelFile = "level.dat";
|
||||
|
||||
protected Level _level;
|
||||
|
||||
private Dictionary<int, ChunkFileManager> _chunkMgrs;
|
||||
private Dictionary<int, BlockManager> _blockMgrs;
|
||||
|
||||
private PlayerManager _playerMan;
|
||||
|
||||
private AlphaWorld ()
|
||||
{
|
||||
_chunkMgrs = new Dictionary<int, ChunkFileManager>();
|
||||
_blockMgrs = new Dictionary<int, BlockManager>();
|
||||
}
|
||||
|
||||
public BlockManager GetBlockManager ()
|
||||
{
|
||||
return GetBlockManager(Dimension.DEFAULT);
|
||||
}
|
||||
|
||||
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 PlayerManager GetPlayerManager ()
|
||||
{
|
||||
if (_playerMan != null) {
|
||||
return _playerMan;
|
||||
}
|
||||
|
||||
string path = Path.Combine(_path, _PLAYER_DIR);
|
||||
|
||||
_playerMan = new PlayerManager(path);
|
||||
return _playerMan;
|
||||
}
|
||||
|
||||
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()) {
|
||||
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);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
private bool LoadLevel ()
|
||||
{
|
||||
NBTFile nf = new NBTFile(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;
|
||||
}
|
||||
|
||||
|
||||
#region INBTWorld Members
|
||||
|
||||
public string WorldPath
|
||||
{
|
||||
get { return _path; }
|
||||
}
|
||||
|
||||
public Level Level
|
||||
{
|
||||
get { return _level; }
|
||||
}
|
||||
|
||||
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 : INBTWorld {
|
||||
private const string _REGION_DIR = "region";
|
||||
private const string _PLAYER_DIR = "players";
|
||||
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 PlayerManager _playerMan;
|
||||
|
||||
private BetaWorld ()
|
||||
{
|
||||
_regionMgrs = new Dictionary<int, RegionManager>();
|
||||
_chunkMgrs = new Dictionary<int, ChunkManager>();
|
||||
_blockMgrs = new Dictionary<int, BlockManager>();
|
||||
}
|
||||
|
||||
public BlockManager GetBlockManager ()
|
||||
{
|
||||
return GetBlockManager(Dimension.DEFAULT);
|
||||
}
|
||||
|
||||
public BlockManager GetBlockManager (int dim)
|
||||
{
|
||||
BlockManager rm;
|
||||
if (_blockMgrs.TryGetValue(dim, out rm)) {
|
||||
return rm;
|
||||
}
|
||||
|
||||
OpenDimension(dim);
|
||||
return _blockMgrs[dim];
|
||||
}
|
||||
|
||||
public ChunkManager GetChunkManager ()
|
||||
{
|
||||
return GetChunkManager(Dimension.DEFAULT);
|
||||
}
|
||||
|
||||
public ChunkManager GetChunkManager (int dim)
|
||||
{
|
||||
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 PlayerManager GetPlayerManager ()
|
||||
{
|
||||
if (_playerMan != null) {
|
||||
return _playerMan;
|
||||
}
|
||||
|
||||
string path = Path.Combine(_path, _PLAYER_DIR);
|
||||
|
||||
_playerMan = new PlayerManager(path);
|
||||
return _playerMan;
|
||||
}
|
||||
|
||||
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, ChunkManager> cm in _chunkMgrs) {
|
||||
cm.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);
|
||||
}
|
||||
|
||||
ChunkCache cc = new ChunkCache();
|
||||
|
||||
RegionManager rm = new RegionManager(path, cc);
|
||||
ChunkManager cm = new ChunkManager(rm, cc);
|
||||
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");
|
||||
}
|
||||
|
||||
string regpath = Path.Combine(path, _REGION_DIR);
|
||||
if (!Directory.Exists(regpath)) {
|
||||
Directory.CreateDirectory(regpath);
|
||||
}
|
||||
|
||||
_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;
|
||||
}
|
||||
|
||||
NbtTree tree = new NbtTree(nbtstr);
|
||||
|
||||
_level = new Level(this);
|
||||
_level = _level.LoadTreeSafe(tree.Root);
|
||||
|
||||
return _level != null;
|
||||
}
|
||||
|
||||
|
||||
#region INBTWorld Members
|
||||
|
||||
public string WorldPath
|
||||
{
|
||||
get { return _path; }
|
||||
}
|
||||
|
||||
public Level Level
|
||||
{
|
||||
get { return _level; }
|
||||
}
|
||||
|
||||
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 { }
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@
|
|||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<DocumentationFile>Substrate.xml</DocumentationFile>
|
||||
<DocumentationFile>bin\Debug\Substrate.XML</DocumentationFile>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
|
@ -52,7 +52,7 @@
|
|||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<DocumentationFile>Substrate.xml</DocumentationFile>
|
||||
<DocumentationFile>bin\Release\Substrate.XML</DocumentationFile>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Ionic.Zlib, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
|
@ -62,6 +62,10 @@
|
|||
<Reference Include="System" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Source\AlphaWorld.cs" />
|
||||
<Compile Include="Source\BetaWorld.cs" />
|
||||
<Compile Include="Source\Core\OpenWorldEvent.cs" />
|
||||
<Compile Include="Source\LevelIOException.cs" />
|
||||
<Compile Include="Source\AlphaBlock.cs" />
|
||||
<Compile Include="Source\AlphaBlockRef.cs" />
|
||||
<Compile Include="Source\CacheTable.cs" />
|
||||
|
@ -76,6 +80,7 @@
|
|||
<Compile Include="Source\Core\BlockLight.cs" />
|
||||
<Compile Include="Source\Core\BlockTileEntities.cs" />
|
||||
<Compile Include="Source\Level.cs" />
|
||||
<Compile Include="Source\NbtWorld.cs" />
|
||||
<Compile Include="Source\NBT\INBTObject.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
|
@ -159,6 +164,7 @@
|
|||
<Compile Include="Source\Core\RegionKey.cs" />
|
||||
<Compile Include="Source\RegionManager.cs" />
|
||||
<Compile Include="Source\SpawnPoint.cs" />
|
||||
<Compile Include="Source\SubstrateException.cs" />
|
||||
<Compile Include="Source\TileEntities\TileEntityChest.cs" />
|
||||
<Compile Include="Source\TileEntities\TileEntityFurnace.cs" />
|
||||
<Compile Include="Source\TileEntities\TileEntityMobSpawner.cs" />
|
||||
|
|
Loading…
Reference in a new issue