diff --git a/SubstrateCS/Source/AlphaBlock.cs b/SubstrateCS/Source/AlphaBlock.cs
index 417faf5..9724477 100644
--- a/SubstrateCS/Source/AlphaBlock.cs
+++ b/SubstrateCS/Source/AlphaBlock.cs
@@ -7,7 +7,7 @@ namespace Substrate
/// A single Alpha-compatible block with context-independent data.
///
/// In general, you should prefer other types for accessing block data including ,
- /// , and the property of and .
+ /// , and the property of and .
/// You should use the type when you need to copy individual blocks into a custom collection or
/// container, and context-depdendent data such as coordinates and lighting have no well-defined meaning.
/// offers a relatively compact footprint for storing the unique identity of a block's manifestation in the world.
diff --git a/SubstrateCS/Source/AlphaBlockCollection.cs b/SubstrateCS/Source/AlphaBlockCollection.cs
index a7a73e4..6f05a2d 100644
--- a/SubstrateCS/Source/AlphaBlockCollection.cs
+++ b/SubstrateCS/Source/AlphaBlockCollection.cs
@@ -9,7 +9,7 @@ namespace Substrate
/// Functions for reading and modifying a bounded-size collection of Alpha-compatible block data.
///
/// An is a wrapper around existing pieces of data. Although it
- /// holds references to data, it does not "own" the data in the same way that a does. An
+ /// holds references to data, it does not "own" the data in the same way that a does. An
/// simply overlays a higher-level interface on top of existing data.
public class AlphaBlockCollection : IBoundedAlphaBlockCollection, IBoundedActiveBlockCollection
{
diff --git a/SubstrateCS/Source/Chunk.cs b/SubstrateCS/Source/AlphaChunk.cs
similarity index 92%
rename from SubstrateCS/Source/Chunk.cs
rename to SubstrateCS/Source/AlphaChunk.cs
index a7ce9a6..f80e6b8 100644
--- a/SubstrateCS/Source/Chunk.cs
+++ b/SubstrateCS/Source/AlphaChunk.cs
@@ -1,414 +1,414 @@
-using System;
-using System.IO;
-using System.Collections.Generic;
-using Substrate.Core;
-using Substrate.Nbt;
-
-namespace Substrate
-{
- ///
- /// A Minecraft Alpha-compatible chunk data structure.
- ///
- ///
- /// A Chunk internally wraps an NBT_Tree of raw chunk data. Modifying the chunk will update the tree, and vice-versa.
- ///
- public class Chunk : IChunk, INbtObject, ICopyable
- {
- private const int XDIM = 16;
- private const int YDIM = 128;
- private const int ZDIM = 16;
-
- ///
- /// An NBT Schema definition for valid chunk data.
- ///
- public static SchemaNodeCompound LevelSchema = new SchemaNodeCompound()
- {
- new SchemaNodeCompound("Level")
- {
- new SchemaNodeArray("Blocks", 32768),
- new SchemaNodeArray("Data", 16384),
- new SchemaNodeArray("SkyLight", 16384),
- new SchemaNodeArray("BlockLight", 16384),
- new SchemaNodeArray("HeightMap", 256),
- new SchemaNodeList("Entities", TagType.TAG_COMPOUND, SchemaOptions.CREATE_ON_MISSING),
- new SchemaNodeList("TileEntities", TagType.TAG_COMPOUND, TileEntity.Schema, SchemaOptions.CREATE_ON_MISSING),
- new SchemaNodeList("TileTicks", TagType.TAG_COMPOUND, TileTick.Schema, SchemaOptions.OPTIONAL),
- new SchemaNodeScaler("LastUpdate", TagType.TAG_LONG, SchemaOptions.CREATE_ON_MISSING),
- new SchemaNodeScaler("xPos", TagType.TAG_INT),
- new SchemaNodeScaler("zPos", TagType.TAG_INT),
- new SchemaNodeScaler("TerrainPopulated", TagType.TAG_BYTE, SchemaOptions.CREATE_ON_MISSING),
- },
- };
-
- private NbtTree _tree;
-
- private int _cx;
- private int _cz;
-
- private XZYByteArray _blocks;
- private XZYNibbleArray _data;
- private XZYNibbleArray _blockLight;
- private XZYNibbleArray _skyLight;
- private ZXByteArray _heightMap;
-
- private TagNodeList _entities;
- private TagNodeList _tileEntities;
- private TagNodeList _tileTicks;
-
- private AlphaBlockCollection _blockManager;
- private EntityCollection _entityManager;
-
- ///
- /// Gets the global X-coordinate of the chunk.
- ///
- public int X
- {
- get { return _cx; }
- }
-
- ///
- /// Gets the global Z-coordinate of the chunk.
- ///
- public int Z
- {
- get { return _cz; }
- }
-
- ///
- /// Gets the collection of all blocks and their data stored in the chunk.
- ///
- public AlphaBlockCollection Blocks
- {
- get { return _blockManager; }
- }
-
- ///
- /// Gets the collection of all entities stored in the chunk.
- ///
- public EntityCollection Entities
- {
- get { return _entityManager; }
- }
-
- ///
- /// Provides raw access to the underlying NBT_Tree.
- ///
- public NbtTree Tree
- {
- get { return _tree; }
- }
-
- ///
- /// Gets or sets the chunk's TerrainPopulated status.
- ///
- public bool IsTerrainPopulated
- {
- get { return _tree.Root["Level"].ToTagCompound()["TerrainPopulated"].ToTagByte() == 1; }
- set { _tree.Root["Level"].ToTagCompound()["TerrainPopulated"].ToTagByte().Data = (byte)(value ? 1 : 0); }
- }
-
-
- private Chunk ()
- {
- }
-
- ///
- /// Creates a default (empty) chunk.
- ///
- /// Global X-coordinate of the chunk.
- /// Global Z-coordinate of the chunk.
- /// A new Chunk object.
- public static Chunk Create (int x, int z)
- {
- Chunk c = new Chunk();
-
- c._cx = x;
- c._cz = z;
-
- c.BuildNBTTree();
- return c;
- }
-
- ///
- /// Creates a chunk object from an existing NBT_Tree.
- ///
- /// An NBT_Tree conforming to the chunk schema definition.
- /// A new Chunk object wrapping an existing NBT_Tree.
- public static Chunk Create (NbtTree tree)
- {
- Chunk c = new Chunk();
-
- return c.LoadTree(tree.Root);
- }
-
- ///
- /// Creates a chunk object from a verified NBT_Tree.
- ///
- /// An NBT_Tree conforming to the chunk schema definition.
- /// A new Chunk object wrapping an existing NBT_Tree, or null on verification failure.
- public static Chunk CreateVerified (NbtTree tree)
- {
- Chunk c = new Chunk();
-
- return c.LoadTreeSafe(tree.Root);
- }
-
- ///
- /// Updates the chunk's global world coordinates.
- ///
- /// Global X-coordinate.
- /// Global Z-coordinate.
- public virtual void SetLocation (int x, int z)
- {
- int diffx = (x - _cx) * XDIM;
- int diffz = (z - _cz) * ZDIM;
-
- // Update chunk position
-
- _cx = x;
- _cz = z;
-
- _tree.Root["Level"].ToTagCompound()["xPos"].ToTagInt().Data = x;
- _tree.Root["Level"].ToTagCompound()["zPos"].ToTagInt().Data = z;
-
- // Update tile entity coordinates
-
- List tileEntites = new List();
- foreach (TagNodeCompound tag in _tileEntities) {
- TileEntity te = TileEntityFactory.Create(tag);
- if (te == null) {
- te = TileEntity.FromTreeSafe(tag);
- }
-
- if (te != null) {
- te.MoveBy(diffx, 0, diffz);
- tileEntites.Add(te);
- }
- }
-
- _tileEntities.Clear();
- foreach (TileEntity te in tileEntites) {
- _tileEntities.Add(te.BuildTree());
- }
-
- // Update tile tick coordinates
-
- if (_tileTicks != null) {
- List tileTicks = new List();
- foreach (TagNodeCompound tag in _tileTicks) {
- TileTick tt = TileTick.FromTreeSafe(tag);
-
- if (tt != null) {
- tt.MoveBy(diffx, 0, diffz);
- tileTicks.Add(tt);
- }
- }
-
- _tileTicks.Clear();
- foreach (TileTick tt in tileTicks) {
- _tileTicks.Add(tt.BuildTree());
- }
- }
-
- // Update entity coordinates
-
- List entities = new List();
- foreach (TypedEntity entity in _entityManager) {
- entity.MoveBy(diffx, 0, diffz);
- entities.Add(entity);
- }
-
- _entities.Clear();
- foreach (TypedEntity entity in entities) {
- _entityManager.Add(entity);
- }
- }
-
- ///
- /// Saves a Chunk's underlying NBT_Tree to an output stream.
- ///
- /// An open, writable output stream.
- /// True if the data is written out to the stream.
- public bool Save (Stream outStream)
- {
- if (outStream == null || !outStream.CanWrite) {
- return false;
- }
-
- BuildConditional();
-
- _tree.WriteTo(outStream);
- outStream.Close();
-
- return true;
- }
-
-
- #region INBTObject Members
-
- ///
- /// Loads the Chunk from an NBT tree rooted at the given TagValue node.
- ///
- /// Root node of an NBT tree.
- /// A reference to the current Chunk, or null if the tree is unparsable.
- public Chunk LoadTree (TagNode tree)
- {
- TagNodeCompound ctree = tree as TagNodeCompound;
- if (ctree == null) {
- return null;
- }
-
- _tree = new NbtTree(ctree);
-
- TagNodeCompound level = _tree.Root["Level"] as TagNodeCompound;
-
- _blocks = new XZYByteArray(XDIM, YDIM, ZDIM, level["Blocks"] as TagNodeByteArray);
- _data = new XZYNibbleArray(XDIM, YDIM, ZDIM, level["Data"] as TagNodeByteArray);
- _blockLight = new XZYNibbleArray(XDIM, YDIM, ZDIM, level["BlockLight"] as TagNodeByteArray);
- _skyLight = new XZYNibbleArray(XDIM, YDIM, ZDIM, level["SkyLight"] as TagNodeByteArray);
- _heightMap = new ZXByteArray(XDIM, ZDIM, level["HeightMap"] as TagNodeByteArray);
-
- _entities = level["Entities"] as TagNodeList;
- _tileEntities = level["TileEntities"] as TagNodeList;
-
- if (level.ContainsKey("TileTicks"))
- _tileTicks = level["TileTicks"] as TagNodeList;
- else
- _tileTicks = new TagNodeList(TagType.TAG_COMPOUND);
-
- // List-type patch up
- if (_entities.Count == 0) {
- level["Entities"] = new TagNodeList(TagType.TAG_COMPOUND);
- _entities = level["Entities"] as TagNodeList;
- }
-
- if (_tileEntities.Count == 0) {
- level["TileEntities"] = new TagNodeList(TagType.TAG_COMPOUND);
- _tileEntities = level["TileEntities"] as TagNodeList;
- }
-
- if (_tileTicks.Count == 0) {
- level["TileTicks"] = new TagNodeList(TagType.TAG_COMPOUND);
- _tileTicks = level["TileTicks"] as TagNodeList;
- }
-
- _cx = level["xPos"].ToTagInt();
- _cz = level["zPos"].ToTagInt();
-
- _blockManager = new AlphaBlockCollection(_blocks, _data, _blockLight, _skyLight, _heightMap, _tileEntities, _tileTicks);
- _entityManager = new EntityCollection(_entities);
-
- return this;
- }
-
- ///
- /// Loads the Chunk from a validated NBT tree rooted at the given TagValue node.
- ///
- /// Root node of an NBT tree.
- /// A reference to the current Chunk, or null if the tree does not conform to the chunk's NBT Schema definition.
- public Chunk LoadTreeSafe (TagNode tree)
- {
- if (!ValidateTree(tree)) {
- return null;
- }
-
- return LoadTree(tree);
- }
-
- ///
- /// Gets a valid NBT tree representing the Chunk.
- ///
- /// The root node of the Chunk's NBT tree.
- public TagNode BuildTree ()
- {
- BuildConditional();
-
- return _tree.Root;
- }
-
- ///
- /// Validates an NBT tree against the chunk's NBT schema definition.
- ///
- /// The root node of the NBT tree to verify.
- /// Status indicating if the tree represents a valid chunk.
- public bool ValidateTree (TagNode tree)
- {
- NbtVerifier v = new NbtVerifier(tree, LevelSchema);
- return v.Verify();
- }
-
- #endregion
-
-
- #region ICopyable Members
-
- ///
- /// Creates a deep copy of the Chunk and its underlying NBT tree.
- ///
- /// A new Chunk with copied data.
- public Chunk Copy ()
- {
- return Chunk.Create(_tree.Copy());
- }
-
- #endregion
-
-
- private void BuildConditional ()
- {
- TagNodeCompound level = _tree.Root["Level"] as TagNodeCompound;
- if (_tileTicks != _blockManager.TileTicks && _blockManager.TileTicks.Count > 0) {
- _tileTicks = _blockManager.TileTicks;
- level["TileTicks"] = _tileTicks;
- }
- }
-
- private void BuildNBTTree ()
- {
- int elements2 = XDIM * ZDIM;
- int elements3 = elements2 * YDIM;
-
- TagNodeByteArray blocks = new TagNodeByteArray(new byte[elements3]);
- TagNodeByteArray data = new TagNodeByteArray(new byte[elements3 >> 1]);
- TagNodeByteArray blocklight = new TagNodeByteArray(new byte[elements3 >> 1]);
- TagNodeByteArray skylight = new TagNodeByteArray(new byte[elements3 >> 1]);
- TagNodeByteArray heightMap = new TagNodeByteArray(new byte[elements2]);
-
- _blocks = new XZYByteArray(XDIM, YDIM, ZDIM, blocks);
- _data = new XZYNibbleArray(XDIM, YDIM, ZDIM, data);
- _blockLight = new XZYNibbleArray(XDIM, YDIM, ZDIM, blocklight);
- _skyLight = new XZYNibbleArray(XDIM, YDIM, ZDIM, skylight);
- _heightMap = new ZXByteArray(XDIM, ZDIM, heightMap);
-
- _entities = new TagNodeList(TagType.TAG_COMPOUND);
- _tileEntities = new TagNodeList(TagType.TAG_COMPOUND);
- _tileTicks = new TagNodeList(TagType.TAG_COMPOUND);
-
- TagNodeCompound level = new TagNodeCompound();
- level.Add("Blocks", blocks);
- level.Add("Data", data);
- level.Add("SkyLight", blocklight);
- level.Add("BlockLight", skylight);
- level.Add("HeightMap", heightMap);
- level.Add("Entities", _entities);
- level.Add("TileEntities", _tileEntities);
- level.Add("TileTicks", _tileTicks);
- level.Add("LastUpdate", new TagNodeLong(Timestamp()));
- level.Add("xPos", new TagNodeInt(_cx));
- level.Add("zPos", new TagNodeInt(_cz));
- level.Add("TerrainPopulated", new TagNodeByte());
-
- _tree = new NbtTree();
- _tree.Root.Add("Level", level);
-
- _blockManager = new AlphaBlockCollection(_blocks, _data, _blockLight, _skyLight, _heightMap, _tileEntities);
- _entityManager = new EntityCollection(_entities);
- }
-
- private int Timestamp ()
- {
- DateTime epoch = new DateTime(1970, 1, 1, 0, 0, 0, 0);
- return (int)((DateTime.UtcNow - epoch).Ticks / (10000L * 1000L));
- }
- }
-}
+using System;
+using System.IO;
+using System.Collections.Generic;
+using Substrate.Core;
+using Substrate.Nbt;
+
+namespace Substrate
+{
+ ///
+ /// A Minecraft Alpha- and Beta-compatible chunk data structure.
+ ///
+ ///
+ /// A Chunk internally wraps an NBT_Tree of raw chunk data. Modifying the chunk will update the tree, and vice-versa.
+ ///
+ public class AlphaChunk : IChunk, INbtObject, ICopyable
+ {
+ private const int XDIM = 16;
+ private const int YDIM = 128;
+ private const int ZDIM = 16;
+
+ ///
+ /// An NBT Schema definition for valid chunk data.
+ ///
+ public static SchemaNodeCompound LevelSchema = new SchemaNodeCompound()
+ {
+ new SchemaNodeCompound("Level")
+ {
+ new SchemaNodeArray("Blocks", 32768),
+ new SchemaNodeArray("Data", 16384),
+ new SchemaNodeArray("SkyLight", 16384),
+ new SchemaNodeArray("BlockLight", 16384),
+ new SchemaNodeArray("HeightMap", 256),
+ new SchemaNodeList("Entities", TagType.TAG_COMPOUND, SchemaOptions.CREATE_ON_MISSING),
+ new SchemaNodeList("TileEntities", TagType.TAG_COMPOUND, TileEntity.Schema, SchemaOptions.CREATE_ON_MISSING),
+ new SchemaNodeList("TileTicks", TagType.TAG_COMPOUND, TileTick.Schema, SchemaOptions.OPTIONAL),
+ new SchemaNodeScaler("LastUpdate", TagType.TAG_LONG, SchemaOptions.CREATE_ON_MISSING),
+ new SchemaNodeScaler("xPos", TagType.TAG_INT),
+ new SchemaNodeScaler("zPos", TagType.TAG_INT),
+ new SchemaNodeScaler("TerrainPopulated", TagType.TAG_BYTE, SchemaOptions.CREATE_ON_MISSING),
+ },
+ };
+
+ private NbtTree _tree;
+
+ private int _cx;
+ private int _cz;
+
+ private XZYByteArray _blocks;
+ private XZYNibbleArray _data;
+ private XZYNibbleArray _blockLight;
+ private XZYNibbleArray _skyLight;
+ private ZXByteArray _heightMap;
+
+ private TagNodeList _entities;
+ private TagNodeList _tileEntities;
+ private TagNodeList _tileTicks;
+
+ private AlphaBlockCollection _blockManager;
+ private EntityCollection _entityManager;
+
+ ///
+ /// Gets the global X-coordinate of the chunk.
+ ///
+ public int X
+ {
+ get { return _cx; }
+ }
+
+ ///
+ /// Gets the global Z-coordinate of the chunk.
+ ///
+ public int Z
+ {
+ get { return _cz; }
+ }
+
+ ///
+ /// Gets the collection of all blocks and their data stored in the chunk.
+ ///
+ public AlphaBlockCollection Blocks
+ {
+ get { return _blockManager; }
+ }
+
+ ///
+ /// Gets the collection of all entities stored in the chunk.
+ ///
+ public EntityCollection Entities
+ {
+ get { return _entityManager; }
+ }
+
+ ///
+ /// Provides raw access to the underlying NBT_Tree.
+ ///
+ public NbtTree Tree
+ {
+ get { return _tree; }
+ }
+
+ ///
+ /// Gets or sets the chunk's TerrainPopulated status.
+ ///
+ public bool IsTerrainPopulated
+ {
+ get { return _tree.Root["Level"].ToTagCompound()["TerrainPopulated"].ToTagByte() == 1; }
+ set { _tree.Root["Level"].ToTagCompound()["TerrainPopulated"].ToTagByte().Data = (byte)(value ? 1 : 0); }
+ }
+
+
+ private AlphaChunk ()
+ {
+ }
+
+ ///
+ /// Creates a default (empty) chunk.
+ ///
+ /// Global X-coordinate of the chunk.
+ /// Global Z-coordinate of the chunk.
+ /// A new Chunk object.
+ public static AlphaChunk Create (int x, int z)
+ {
+ AlphaChunk c = new AlphaChunk();
+
+ c._cx = x;
+ c._cz = z;
+
+ c.BuildNBTTree();
+ return c;
+ }
+
+ ///
+ /// Creates a chunk object from an existing NBT_Tree.
+ ///
+ /// An NBT_Tree conforming to the chunk schema definition.
+ /// A new Chunk object wrapping an existing NBT_Tree.
+ public static AlphaChunk Create (NbtTree tree)
+ {
+ AlphaChunk c = new AlphaChunk();
+
+ return c.LoadTree(tree.Root);
+ }
+
+ ///
+ /// Creates a chunk object from a verified NBT_Tree.
+ ///
+ /// An NBT_Tree conforming to the chunk schema definition.
+ /// A new Chunk object wrapping an existing NBT_Tree, or null on verification failure.
+ public static AlphaChunk CreateVerified (NbtTree tree)
+ {
+ AlphaChunk c = new AlphaChunk();
+
+ return c.LoadTreeSafe(tree.Root);
+ }
+
+ ///
+ /// Updates the chunk's global world coordinates.
+ ///
+ /// Global X-coordinate.
+ /// Global Z-coordinate.
+ public void SetLocation (int x, int z)
+ {
+ int diffx = (x - _cx) * XDIM;
+ int diffz = (z - _cz) * ZDIM;
+
+ // Update chunk position
+
+ _cx = x;
+ _cz = z;
+
+ _tree.Root["Level"].ToTagCompound()["xPos"].ToTagInt().Data = x;
+ _tree.Root["Level"].ToTagCompound()["zPos"].ToTagInt().Data = z;
+
+ // Update tile entity coordinates
+
+ List tileEntites = new List();
+ foreach (TagNodeCompound tag in _tileEntities) {
+ TileEntity te = TileEntityFactory.Create(tag);
+ if (te == null) {
+ te = TileEntity.FromTreeSafe(tag);
+ }
+
+ if (te != null) {
+ te.MoveBy(diffx, 0, diffz);
+ tileEntites.Add(te);
+ }
+ }
+
+ _tileEntities.Clear();
+ foreach (TileEntity te in tileEntites) {
+ _tileEntities.Add(te.BuildTree());
+ }
+
+ // Update tile tick coordinates
+
+ if (_tileTicks != null) {
+ List tileTicks = new List();
+ foreach (TagNodeCompound tag in _tileTicks) {
+ TileTick tt = TileTick.FromTreeSafe(tag);
+
+ if (tt != null) {
+ tt.MoveBy(diffx, 0, diffz);
+ tileTicks.Add(tt);
+ }
+ }
+
+ _tileTicks.Clear();
+ foreach (TileTick tt in tileTicks) {
+ _tileTicks.Add(tt.BuildTree());
+ }
+ }
+
+ // Update entity coordinates
+
+ List entities = new List();
+ foreach (TypedEntity entity in _entityManager) {
+ entity.MoveBy(diffx, 0, diffz);
+ entities.Add(entity);
+ }
+
+ _entities.Clear();
+ foreach (TypedEntity entity in entities) {
+ _entityManager.Add(entity);
+ }
+ }
+
+ ///
+ /// Saves a Chunk's underlying NBT_Tree to an output stream.
+ ///
+ /// An open, writable output stream.
+ /// True if the data is written out to the stream.
+ public bool Save (Stream outStream)
+ {
+ if (outStream == null || !outStream.CanWrite) {
+ return false;
+ }
+
+ BuildConditional();
+
+ _tree.WriteTo(outStream);
+ outStream.Close();
+
+ return true;
+ }
+
+
+ #region INBTObject Members
+
+ ///
+ /// Loads the Chunk from an NBT tree rooted at the given TagValue node.
+ ///
+ /// Root node of an NBT tree.
+ /// A reference to the current Chunk, or null if the tree is unparsable.
+ public AlphaChunk LoadTree (TagNode tree)
+ {
+ TagNodeCompound ctree = tree as TagNodeCompound;
+ if (ctree == null) {
+ return null;
+ }
+
+ _tree = new NbtTree(ctree);
+
+ TagNodeCompound level = _tree.Root["Level"] as TagNodeCompound;
+
+ _blocks = new XZYByteArray(XDIM, YDIM, ZDIM, level["Blocks"] as TagNodeByteArray);
+ _data = new XZYNibbleArray(XDIM, YDIM, ZDIM, level["Data"] as TagNodeByteArray);
+ _blockLight = new XZYNibbleArray(XDIM, YDIM, ZDIM, level["BlockLight"] as TagNodeByteArray);
+ _skyLight = new XZYNibbleArray(XDIM, YDIM, ZDIM, level["SkyLight"] as TagNodeByteArray);
+ _heightMap = new ZXByteArray(XDIM, ZDIM, level["HeightMap"] as TagNodeByteArray);
+
+ _entities = level["Entities"] as TagNodeList;
+ _tileEntities = level["TileEntities"] as TagNodeList;
+
+ if (level.ContainsKey("TileTicks"))
+ _tileTicks = level["TileTicks"] as TagNodeList;
+ else
+ _tileTicks = new TagNodeList(TagType.TAG_COMPOUND);
+
+ // List-type patch up
+ if (_entities.Count == 0) {
+ level["Entities"] = new TagNodeList(TagType.TAG_COMPOUND);
+ _entities = level["Entities"] as TagNodeList;
+ }
+
+ if (_tileEntities.Count == 0) {
+ level["TileEntities"] = new TagNodeList(TagType.TAG_COMPOUND);
+ _tileEntities = level["TileEntities"] as TagNodeList;
+ }
+
+ if (_tileTicks.Count == 0) {
+ level["TileTicks"] = new TagNodeList(TagType.TAG_COMPOUND);
+ _tileTicks = level["TileTicks"] as TagNodeList;
+ }
+
+ _cx = level["xPos"].ToTagInt();
+ _cz = level["zPos"].ToTagInt();
+
+ _blockManager = new AlphaBlockCollection(_blocks, _data, _blockLight, _skyLight, _heightMap, _tileEntities, _tileTicks);
+ _entityManager = new EntityCollection(_entities);
+
+ return this;
+ }
+
+ ///
+ /// Loads the Chunk from a validated NBT tree rooted at the given TagValue node.
+ ///
+ /// Root node of an NBT tree.
+ /// A reference to the current Chunk, or null if the tree does not conform to the chunk's NBT Schema definition.
+ public AlphaChunk LoadTreeSafe (TagNode tree)
+ {
+ if (!ValidateTree(tree)) {
+ return null;
+ }
+
+ return LoadTree(tree);
+ }
+
+ ///
+ /// Gets a valid NBT tree representing the Chunk.
+ ///
+ /// The root node of the Chunk's NBT tree.
+ public TagNode BuildTree ()
+ {
+ BuildConditional();
+
+ return _tree.Root;
+ }
+
+ ///
+ /// Validates an NBT tree against the chunk's NBT schema definition.
+ ///
+ /// The root node of the NBT tree to verify.
+ /// Status indicating if the tree represents a valid chunk.
+ public bool ValidateTree (TagNode tree)
+ {
+ NbtVerifier v = new NbtVerifier(tree, LevelSchema);
+ return v.Verify();
+ }
+
+ #endregion
+
+
+ #region ICopyable Members
+
+ ///
+ /// Creates a deep copy of the Chunk and its underlying NBT tree.
+ ///
+ /// A new Chunk with copied data.
+ public AlphaChunk Copy ()
+ {
+ return AlphaChunk.Create(_tree.Copy());
+ }
+
+ #endregion
+
+
+ private void BuildConditional ()
+ {
+ TagNodeCompound level = _tree.Root["Level"] as TagNodeCompound;
+ if (_tileTicks != _blockManager.TileTicks && _blockManager.TileTicks.Count > 0) {
+ _tileTicks = _blockManager.TileTicks;
+ level["TileTicks"] = _tileTicks;
+ }
+ }
+
+ private void BuildNBTTree ()
+ {
+ int elements2 = XDIM * ZDIM;
+ int elements3 = elements2 * YDIM;
+
+ TagNodeByteArray blocks = new TagNodeByteArray(new byte[elements3]);
+ TagNodeByteArray data = new TagNodeByteArray(new byte[elements3 >> 1]);
+ TagNodeByteArray blocklight = new TagNodeByteArray(new byte[elements3 >> 1]);
+ TagNodeByteArray skylight = new TagNodeByteArray(new byte[elements3 >> 1]);
+ TagNodeByteArray heightMap = new TagNodeByteArray(new byte[elements2]);
+
+ _blocks = new XZYByteArray(XDIM, YDIM, ZDIM, blocks);
+ _data = new XZYNibbleArray(XDIM, YDIM, ZDIM, data);
+ _blockLight = new XZYNibbleArray(XDIM, YDIM, ZDIM, blocklight);
+ _skyLight = new XZYNibbleArray(XDIM, YDIM, ZDIM, skylight);
+ _heightMap = new ZXByteArray(XDIM, ZDIM, heightMap);
+
+ _entities = new TagNodeList(TagType.TAG_COMPOUND);
+ _tileEntities = new TagNodeList(TagType.TAG_COMPOUND);
+ _tileTicks = new TagNodeList(TagType.TAG_COMPOUND);
+
+ TagNodeCompound level = new TagNodeCompound();
+ level.Add("Blocks", blocks);
+ level.Add("Data", data);
+ level.Add("SkyLight", blocklight);
+ level.Add("BlockLight", skylight);
+ level.Add("HeightMap", heightMap);
+ level.Add("Entities", _entities);
+ level.Add("TileEntities", _tileEntities);
+ level.Add("TileTicks", _tileTicks);
+ level.Add("LastUpdate", new TagNodeLong(Timestamp()));
+ level.Add("xPos", new TagNodeInt(_cx));
+ level.Add("zPos", new TagNodeInt(_cz));
+ level.Add("TerrainPopulated", new TagNodeByte());
+
+ _tree = new NbtTree();
+ _tree.Root.Add("Level", level);
+
+ _blockManager = new AlphaBlockCollection(_blocks, _data, _blockLight, _skyLight, _heightMap, _tileEntities);
+ _entityManager = new EntityCollection(_entities);
+ }
+
+ private int Timestamp ()
+ {
+ DateTime epoch = new DateTime(1970, 1, 1, 0, 0, 0, 0);
+ return (int)((DateTime.UtcNow - epoch).Ticks / (10000L * 1000L));
+ }
+ }
+}
diff --git a/SubstrateCS/Source/AlphaChunkManager.cs b/SubstrateCS/Source/AlphaChunkManager.cs
index 63e7c28..c2e6623 100644
--- a/SubstrateCS/Source/AlphaChunkManager.cs
+++ b/SubstrateCS/Source/AlphaChunkManager.cs
@@ -101,13 +101,13 @@ namespace Substrate
}
///
- public Chunk GetChunk (int cx, int cz)
+ public IChunk GetChunk (int cx, int cz)
{
if (!ChunkExists(cx, cz)) {
return null;
}
- return Chunk.CreateVerified(GetChunkTree(cx, cz));
+ return AlphaChunk.CreateVerified(GetChunkTree(cx, cz));
}
///
@@ -134,7 +134,7 @@ namespace Substrate
public ChunkRef CreateChunk (int cx, int cz)
{
DeleteChunk(cx, cz);
- Chunk c = Chunk.Create(cx, cz);
+ AlphaChunk c = AlphaChunk.Create(cx, cz);
c.Save(GetChunkOutStream(cx, cz));
ChunkRef cr = ChunkRef.Create(this, cx, cz);
@@ -163,7 +163,7 @@ namespace Substrate
}
///
- public ChunkRef SetChunk (int cx, int cz, Chunk chunk)
+ public ChunkRef SetChunk (int cx, int cz, IChunk chunk)
{
DeleteChunk(cx, cz);
chunk.SetLocation(cx, cz);
@@ -200,7 +200,7 @@ namespace Substrate
}
///
- public bool SaveChunk (Chunk chunk)
+ public bool SaveChunk (IChunk chunk)
{
if (chunk.Save(GetChunkOutStream(ChunkGlobalX(chunk.X), ChunkGlobalZ(chunk.Z)))) {
_dirty.Remove(new ChunkKey(chunk.X, chunk.Z));
diff --git a/SubstrateCS/Source/AlphaWorld.cs b/SubstrateCS/Source/AlphaWorld.cs
index e1c28b6..d93a70a 100644
--- a/SubstrateCS/Source/AlphaWorld.cs
+++ b/SubstrateCS/Source/AlphaWorld.cs
@@ -44,7 +44,7 @@ namespace Substrate
/// 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.
+ /// instead and working with blocks on a chunk-local level.
public new BlockManager GetBlockManager ()
{
return GetBlockManagerVirt(Dimension.DEFAULT) as BlockManager;
@@ -57,28 +57,28 @@ namespace Substrate
/// 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.
+ /// 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.
+ /// 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.
+ /// 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.
+ /// 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.
+ /// 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;
@@ -95,7 +95,7 @@ namespace Substrate
}
///
- /// Saves the world's data, and any objects known to have unsaved changes.
+ /// Saves the world's data, and any objects known to have unsaved changes.
///
public void Save ()
{
diff --git a/SubstrateCS/Source/AnvilChunk.cs b/SubstrateCS/Source/AnvilChunk.cs
index f4a07b5..0b77c16 100644
--- a/SubstrateCS/Source/AnvilChunk.cs
+++ b/SubstrateCS/Source/AnvilChunk.cs
@@ -413,7 +413,7 @@ namespace Substrate
#endregion
}
- public class Chunk : IChunk, INbtObject, ICopyable
+ public class AnvilChunk : IChunk, INbtObject, ICopyable
{
public static SchemaNodeCompound LevelSchema = new SchemaNodeCompound()
{
@@ -466,7 +466,7 @@ namespace Substrate
private EntityCollection _entityManager;
- private Chunk ()
+ private AnvilChunk ()
{
_sections = new AnvilSection[16];
}
@@ -502,9 +502,9 @@ namespace Substrate
set { _tree.Root["Level"].ToTagCompound()["TerrainPopulated"].ToTagByte().Data = (byte)(value ? 1 : 0); }
}
- public static Chunk Create (int x, int z)
+ public static AnvilChunk Create (int x, int z)
{
- Chunk c = new Chunk();
+ AnvilChunk c = new AnvilChunk();
c._cx = x;
c._cz = z;
@@ -513,16 +513,16 @@ namespace Substrate
return c;
}
- public static Chunk Create (NbtTree tree)
+ public static AnvilChunk Create (NbtTree tree)
{
- Chunk c = new Chunk();
+ AnvilChunk c = new AnvilChunk();
return c.LoadTree(tree.Root);
}
- public static Chunk CreateVerified (NbtTree tree)
+ public static AnvilChunk CreateVerified (NbtTree tree)
{
- Chunk c = new Chunk();
+ AnvilChunk c = new AnvilChunk();
return c.LoadTreeSafe(tree.Root);
}
@@ -617,7 +617,7 @@ namespace Substrate
#region INbtObject Members
- public Chunk LoadTree (TagNode tree)
+ public AnvilChunk LoadTree (TagNode tree)
{
TagNodeCompound ctree = tree as TagNodeCompound;
if (ctree == null) {
@@ -701,7 +701,7 @@ namespace Substrate
return this;
}
- public Chunk LoadTreeSafe (TagNode tree)
+ public AnvilChunk LoadTreeSafe (TagNode tree)
{
if (!ValidateTree(tree)) {
return null;
@@ -740,9 +740,9 @@ namespace Substrate
#region ICopyable Members
- public Chunk Copy ()
+ public AnvilChunk Copy ()
{
- return Chunk.Create(_tree.Copy());
+ return AnvilChunk.Create(_tree.Copy());
}
#endregion
diff --git a/SubstrateCS/Source/AnvilWorld.cs b/SubstrateCS/Source/AnvilWorld.cs
new file mode 100644
index 0000000..460f4fe
--- /dev/null
+++ b/SubstrateCS/Source/AnvilWorld.cs
@@ -0,0 +1,392 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using Substrate.Core;
+using Substrate.Nbt;
+using Substrate.Data;
+
+//TODO: Exceptions (+ Alpha)
+
+namespace Substrate
+{
+ using IO = System.IO;
+
+ ///
+ /// Represents an Anvil-compatible (Release 1.2 or higher) Minecraft world.
+ ///
+ public class AnvilWorld : NbtWorld
+ {
+ private const string _REGION_DIR = "region";
+ private const string _PLAYER_DIR = "players";
+ private string _levelFile = "level.dat";
+
+ private Level _level;
+
+ private Dictionary _regionMgrs;
+ private Dictionary _chunkMgrs;
+ private Dictionary _blockMgrs;
+
+ private Dictionary _caches;
+
+ private PlayerManager _playerMan;
+ private BetaDataManager _dataMan;
+
+ private int _prefCacheSize = 256;
+
+ private AnvilWorld ()
+ {
+ _regionMgrs = new Dictionary();
+ _chunkMgrs = new Dictionary();
+ _blockMgrs = new Dictionary();
+
+ _caches = 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 RegionChunkManager GetChunkManager ()
+ {
+ return GetChunkManagerVirt(Dimension.DEFAULT) as RegionChunkManager;
+ }
+
+ ///
+ /// 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 RegionChunkManager GetChunkManager (int dim)
+ {
+ return GetChunkManagerVirt(dim) as RegionChunkManager;
+ }
+
+ ///
+ /// Gets a for the default dimension.
+ ///
+ /// A tied to the defaul dimension in this world.
+ /// Regions are a higher-level unit of organization for blocks unique to worlds created in Beta 1.3 and beyond.
+ /// Consider using the if you are interested in working with blocks.
+ public AnvilRegionManager GetRegionManager ()
+ {
+ return GetRegionManager(Dimension.DEFAULT);
+ }
+
+ ///
+ /// Gets a for the given dimension.
+ ///
+ /// The id of the dimension to look up.
+ /// A tied to the given dimension in this world.
+ /// Regions are a higher-level unit of organization for blocks unique to worlds created in Beta 1.3 and beyond.
+ /// Consider using the if you are interested in working with blocks.
+ public AnvilRegionManager GetRegionManager (int dim)
+ {
+ AnvilRegionManager rm;
+ if (_regionMgrs.TryGetValue(dim, out rm)) {
+ return rm;
+ }
+
+ OpenDimension(dim);
+ return _regionMgrs[dim];
+ }
+
+ ///
+ /// 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;
+ }
+
+ ///
+ /// Gets a for managing data resources, such as maps.
+ ///
+ /// A for this world.
+ public new BetaDataManager GetDataManager ()
+ {
+ return GetDataManagerVirt() as BetaDataManager;
+ }
+
+ ///
+ /// Saves the world's data, and any objects known to have unsaved changes.
+ ///
+ public void Save ()
+ {
+ _level.Save();
+
+ foreach (KeyValuePair cm in _chunkMgrs) {
+ cm.Value.Save();
+ }
+ }
+
+ ///
+ /// Gets the currently managing chunks in the default dimension.
+ ///
+ /// The for the default dimension, or null if the dimension was not found.
+ public ChunkCache GetChunkCache ()
+ {
+ return GetChunkCache(Dimension.DEFAULT);
+ }
+
+ ///
+ /// Gets the currently managing chunks in the given dimension.
+ ///
+ /// The id of a dimension to look up.
+ /// The for the given dimension, or null if the dimension was not found.
+ public ChunkCache GetChunkCache (int dim)
+ {
+ if (_caches.ContainsKey(dim)) {
+ return _caches[dim];
+ }
+ return null;
+ }
+
+ ///
+ /// Opens an existing Beta-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 AnvilWorld Open (string path)
+ {
+ return new AnvilWorld().OpenWorld(path) as AnvilWorld;
+ }
+
+ ///
+ /// Opens an existing Beta-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.
+ /// The preferred cache size in chunks for each opened dimension in this world.
+ /// A new object representing an existing world on disk.
+ public static AnvilWorld Open (string path, int cacheSize)
+ {
+ AnvilWorld world = new AnvilWorld().OpenWorld(path);
+ world._prefCacheSize = cacheSize;
+
+ return world;
+ }
+
+ ///
+ /// Creates a new Beta-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 AnvilWorld Create (string path)
+ {
+ return new AnvilWorld().CreateWorld(path) as AnvilWorld;
+ }
+
+ ///
+ /// Creates a new Beta-compatible Minecraft world and returns a new to represent it.
+ ///
+ /// The path to the directory where the new world should be stored.
+ /// The preferred cache size in chunks for each opened dimension in this world.
+ /// 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 AnvilWorld Create (string path, int cacheSize)
+ {
+ AnvilWorld world = new AnvilWorld().CreateWorld(path);
+ world._prefCacheSize = cacheSize;
+
+ return world;
+ }
+
+ ///
+ 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)
+ {
+ RegionChunkManager 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;
+ }
+
+ ///
+ protected override Data.DataManager GetDataManagerVirt ()
+ {
+ if (_dataMan != null) {
+ return _dataMan;
+ }
+
+ _dataMan = new BetaDataManager(this);
+ return _dataMan;
+ }
+
+ 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(_prefCacheSize);
+
+ AnvilRegionManager rm = new AnvilRegionManager(path, cc);
+ RegionChunkManager cm = new RegionChunkManager(rm, cc);
+ BlockManager bm = new BlockManager(cm);
+
+ _regionMgrs[dim] = rm;
+ _chunkMgrs[dim] = cm;
+ _blockMgrs[dim] = bm;
+
+ _caches[dim] = cc;
+ }
+
+ private AnvilWorld 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 AnvilWorld 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 {
+ AnvilWorld world = new AnvilWorld().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 < 19133) {
+ return;
+ }
+
+ e.AddHandler(Open);
+ }
+ catch (Exception) {
+ return;
+ }
+ }
+ }
+}
diff --git a/SubstrateCS/Source/BetaChunkManager.cs b/SubstrateCS/Source/BetaChunkManager.cs
index 7a4ee0a..2870a4b 100644
--- a/SubstrateCS/Source/BetaChunkManager.cs
+++ b/SubstrateCS/Source/BetaChunkManager.cs
@@ -8,7 +8,7 @@ namespace Substrate
///
/// Represents a Beta-compatible interface for globally managing chunks.
///
- public class BetaChunkManager : IChunkManager, IEnumerable
+ public class RegionChunkManager : IChunkManager, IEnumerable
{
private const int REGION_XLEN = 32;
private const int REGION_ZLEN = 32;
@@ -19,26 +19,26 @@ namespace Substrate
private const int REGION_XMASK = 0x1F;
private const int REGION_ZMASK = 0x1F;
- private RegionManager _regionMan;
+ private IRegionManager _regionMan;
private ChunkCache _cache;
///
- /// Creates a new instance given a backing and .
+ /// Creates a new instance given a backing and .
///
/// A exposing access to regions.
/// A shared cache for storing chunks read in.
- public BetaChunkManager (RegionManager rm, ChunkCache cache)
+ public RegionChunkManager (IRegionManager rm, ChunkCache cache)
{
_regionMan = rm;
_cache = cache;
}
///
- /// Creates a new instance from another.
+ /// Creates a new instance from another.
///
- /// A to get a and from.
- public BetaChunkManager (BetaChunkManager cm)
+ /// A to get a and from.
+ public RegionChunkManager (RegionChunkManager cm)
{
_regionMan = cm._regionMan;
_cache = cm._cache;
@@ -47,7 +47,7 @@ namespace Substrate
///
/// Gets the backing this manager.
///
- public RegionManager RegionManager
+ public IRegionManager RegionManager
{
get { return _regionMan; }
}
@@ -79,9 +79,9 @@ namespace Substrate
}
///
- public Chunk GetChunk (int cx, int cz)
+ public IChunk GetChunk (int cx, int cz)
{
- Region r = GetRegion(cx, cz);
+ IRegion r = GetRegion(cx, cz);
if (r == null) {
return null;
}
@@ -92,7 +92,7 @@ namespace Substrate
///
public ChunkRef GetChunkRef (int cx, int cz)
{
- Region r = GetRegion(cx, cz);
+ IRegion r = GetRegion(cx, cz);
if (r == null) {
return null;
}
@@ -103,7 +103,7 @@ namespace Substrate
///
public bool ChunkExists (int cx, int cz)
{
- Region r = GetRegion(cx, cz);
+ IRegion r = GetRegion(cx, cz);
if (r == null) {
return false;
}
@@ -114,7 +114,7 @@ namespace Substrate
///
public ChunkRef CreateChunk (int cx, int cz)
{
- Region r = GetRegion(cx, cz);
+ IRegion r = GetRegion(cx, cz);
if (r == null) {
int rx = cx >> REGION_XLOG;
int rz = cz >> REGION_ZLOG;
@@ -125,9 +125,9 @@ namespace Substrate
}
///
- public ChunkRef SetChunk (int cx, int cz, Chunk chunk)
+ public ChunkRef SetChunk (int cx, int cz, IChunk chunk)
{
- Region r = GetRegion(cx, cz);
+ IRegion r = GetRegion(cx, cz);
if (r == null) {
int rx = cx >> REGION_XLOG;
int rz = cz >> REGION_ZLOG;
@@ -150,7 +150,7 @@ namespace Substrate
while (en.MoveNext()) {
ChunkRef chunk = en.Current;
- Region r = GetRegion(chunk.X, chunk.Z);
+ IRegion r = GetRegion(chunk.X, chunk.Z);
if (r == null) {
continue;
}
@@ -164,9 +164,9 @@ namespace Substrate
}
///
- public bool SaveChunk (Chunk chunk)
+ public bool SaveChunk (IChunk chunk)
{
- Region r = GetRegion(chunk.X, chunk.Z);
+ IRegion r = GetRegion(chunk.X, chunk.Z);
if (r == null) {
return false;
}
@@ -177,7 +177,7 @@ namespace Substrate
///
public bool DeleteChunk (int cx, int cz)
{
- Region r = GetRegion(cx, cz);
+ IRegion r = GetRegion(cx, cz);
if (r == null) {
return false;
}
@@ -211,19 +211,19 @@ namespace Substrate
/// A for the destination chunk.
public ChunkRef CopyChunk (int src_cx, int src_cz, int dst_cx, int dst_cz)
{
- Region src_r = GetRegion(src_cx, src_cz);
+ IRegion src_r = GetRegion(src_cx, src_cz);
if (src_r == null) {
return null;
}
- Region dst_r = GetRegion(dst_cx, dst_cz);
+ IRegion dst_r = GetRegion(dst_cx, dst_cz);
if (dst_r == null) {
int rx = dst_cx >> REGION_XLOG;
int rz = dst_cz >> REGION_ZLOG;
dst_r = _regionMan.CreateRegion(rx, rz);
}
- Chunk c = src_r.GetChunk(src_cx & REGION_XMASK, src_cz & REGION_ZMASK).Copy();
+ IChunk c = src_r.GetChunk(src_cx & REGION_XMASK, src_cz & REGION_ZMASK);
c.SetLocation(dst_cx, dst_cz);
dst_r.SaveChunk(c);
@@ -293,7 +293,7 @@ namespace Substrate
/// The value returned may differ from any timestamp stored in the chunk data itself.
public int GetChunkTimestamp (int cx, int cz)
{
- Region r = GetRegion(cx, cz);
+ IRegion r = GetRegion(cx, cz);
if (r == null) {
return 0;
}
@@ -311,7 +311,7 @@ namespace Substrate
/// any timestamp information in the chunk data itself.
public void SetChunkTimestamp (int cx, int cz, int timestamp)
{
- Region r = GetRegion(cx, cz);
+ IRegion r = GetRegion(cx, cz);
if (r == null) {
return;
}
@@ -319,14 +319,14 @@ namespace Substrate
r.SetChunkTimestamp(cx & REGION_XMASK, cz & REGION_ZMASK, timestamp);
}
- private ChunkRef GetChunkRefInRegion (Region r, int lcx, int lcz)
+ private ChunkRef GetChunkRefInRegion (IRegion r, int lcx, int lcz)
{
int cx = r.X * REGION_XLEN + lcx;
int cz = r.Z * REGION_ZLEN + lcz;
return GetChunkRef(cx, cz);
}
- private Region GetRegion (int cx, int cz)
+ private IRegion GetRegion (int cx, int cz)
{
cx >>= REGION_XLOG;
cz >>= REGION_ZLOG;
@@ -361,16 +361,16 @@ namespace Substrate
private class Enumerator : IEnumerator
{
- private BetaChunkManager _cm;
+ private RegionChunkManager _cm;
- private IEnumerator _enum;
- private Region _region;
+ private IEnumerator _enum;
+ private IRegion _region;
private ChunkRef _chunk;
private int _x = 0;
private int _z = -1;
- public Enumerator (BetaChunkManager cm)
+ public Enumerator (RegionChunkManager cm)
{
_cm = cm;
_enum = _cm.RegionManager.GetEnumerator();
@@ -385,7 +385,7 @@ namespace Substrate
}
else {
while (true) {
- if (_x >= BetaChunkManager.REGION_XLEN) {
+ if (_x >= RegionChunkManager.REGION_XLEN) {
if (!_enum.MoveNext()) {
return false;
}
@@ -403,8 +403,8 @@ namespace Substrate
protected bool MoveNextInRegion ()
{
- for (; _x < BetaChunkManager.REGION_XLEN; _x++) {
- for (_z++; _z < BetaChunkManager.REGION_ZLEN; _z++) {
+ for (; _x < RegionChunkManager.REGION_XLEN; _x++) {
+ for (_z++; _z < RegionChunkManager.REGION_ZLEN; _z++) {
if (_region.ChunkExists(_x, _z)) {
goto FoundNext;
}
@@ -414,7 +414,7 @@ namespace Substrate
FoundNext:
- return (_x < BetaChunkManager.REGION_XLEN);
+ return (_x < RegionChunkManager.REGION_XLEN);
}
public void Reset ()
@@ -450,7 +450,7 @@ namespace Substrate
{
get
{
- if (_x >= BetaChunkManager.REGION_XLEN) {
+ if (_x >= RegionChunkManager.REGION_XLEN) {
throw new InvalidOperationException();
}
return _chunk;
diff --git a/SubstrateCS/Source/BetaWorld.cs b/SubstrateCS/Source/BetaWorld.cs
index 8e2193c..9f8a547 100644
--- a/SubstrateCS/Source/BetaWorld.cs
+++ b/SubstrateCS/Source/BetaWorld.cs
@@ -22,8 +22,8 @@ namespace Substrate
private Level _level;
- private Dictionary _regionMgrs;
- private Dictionary _chunkMgrs;
+ private Dictionary _regionMgrs;
+ private Dictionary _chunkMgrs;
private Dictionary _blockMgrs;
private Dictionary _caches;
@@ -35,8 +35,8 @@ namespace Substrate
private BetaWorld ()
{
- _regionMgrs = new Dictionary();
- _chunkMgrs = new Dictionary();
+ _regionMgrs = new Dictionary();
+ _chunkMgrs = new Dictionary();
_blockMgrs = new Dictionary();
_caches = new Dictionary();
@@ -56,7 +56,7 @@ namespace Substrate
/// 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.
+ /// instead and working with blocks on a chunk-local level.
public new BlockManager GetBlockManager ()
{
return GetBlockManagerVirt(Dimension.DEFAULT) as BlockManager;
@@ -69,31 +69,31 @@ namespace Substrate
/// 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.
+ /// 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.
+ /// 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 BetaChunkManager GetChunkManager ()
+ /// 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 RegionChunkManager GetChunkManager ()
{
- return GetChunkManagerVirt(Dimension.DEFAULT) as BetaChunkManager;
+ return GetChunkManagerVirt(Dimension.DEFAULT) as RegionChunkManager;
}
///
- /// Gets a for the given dimension.
+ /// 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 BetaChunkManager GetChunkManager (int dim)
+ /// 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 RegionChunkManager GetChunkManager (int dim)
{
- return GetChunkManagerVirt(dim) as BetaChunkManager;
+ return GetChunkManagerVirt(dim) as RegionChunkManager;
}
///
@@ -101,8 +101,8 @@ namespace Substrate
///
/// A tied to the defaul dimension in this world.
/// Regions are a higher-level unit of organization for blocks unique to worlds created in Beta 1.3 and beyond.
- /// Consider using the if you are interested in working with blocks.
- public RegionManager GetRegionManager ()
+ /// Consider using the if you are interested in working with blocks.
+ public BetaRegionManager GetRegionManager ()
{
return GetRegionManager(Dimension.DEFAULT);
}
@@ -113,10 +113,10 @@ namespace Substrate
/// The id of the dimension to look up.
/// A tied to the given dimension in this world.
/// Regions are a higher-level unit of organization for blocks unique to worlds created in Beta 1.3 and beyond.
- /// Consider using the if you are interested in working with blocks.
- public RegionManager GetRegionManager (int dim)
+ /// Consider using the if you are interested in working with blocks.
+ public BetaRegionManager GetRegionManager (int dim)
{
- RegionManager rm;
+ BetaRegionManager rm;
if (_regionMgrs.TryGetValue(dim, out rm)) {
return rm;
}
@@ -145,13 +145,13 @@ namespace Substrate
}
///
- /// Saves the world's data, and any objects known to have unsaved changes.
+ /// Saves the world's data, and any objects known to have unsaved changes.
///
public void Save ()
{
_level.Save();
- foreach (KeyValuePair cm in _chunkMgrs) {
+ foreach (KeyValuePair cm in _chunkMgrs) {
cm.Value.Save();
}
}
@@ -245,7 +245,7 @@ namespace Substrate
///
protected override IChunkManager GetChunkManagerVirt (int dim)
{
- BetaChunkManager rm;
+ RegionChunkManager rm;
if (_chunkMgrs.TryGetValue(dim, out rm)) {
return rm;
}
@@ -295,8 +295,8 @@ namespace Substrate
ChunkCache cc = new ChunkCache(_prefCacheSize);
- RegionManager rm = new RegionManager(path, cc);
- BetaChunkManager cm = new BetaChunkManager(rm, cc);
+ BetaRegionManager rm = new BetaRegionManager(path, cc);
+ RegionChunkManager cm = new RegionChunkManager(rm, cc);
BlockManager bm = new BlockManager(cm);
_regionMgrs[dim] = rm;
@@ -378,7 +378,7 @@ namespace Substrate
return;
}
- if (world.Level.Version < 19132) {
+ if (world.Level.Version != 19132) {
return;
}
diff --git a/SubstrateCS/Source/BlockManager.cs b/SubstrateCS/Source/BlockManager.cs
index 595ca2a..a10eecd 100644
--- a/SubstrateCS/Source/BlockManager.cs
+++ b/SubstrateCS/Source/BlockManager.cs
@@ -68,7 +68,7 @@ namespace Substrate
{
chunkMan = cm;
- Chunk c = Chunk.Create(0, 0);
+ IChunk c = AlphaChunk.Create(0, 0);
chunkXDim = c.Blocks.XDim;
chunkYDim = c.Blocks.YDim;
diff --git a/SubstrateCS/Source/ChunkRef.cs b/SubstrateCS/Source/ChunkRef.cs
index 26c66e2..c56b9da 100644
--- a/SubstrateCS/Source/ChunkRef.cs
+++ b/SubstrateCS/Source/ChunkRef.cs
@@ -14,7 +14,7 @@ namespace Substrate
public class ChunkRef : IChunk
{
private IChunkContainer _container;
- private Chunk _chunk;
+ private IChunk _chunk;
private AlphaBlockCollection _blocks;
private EntityCollection _entities;
@@ -167,6 +167,15 @@ namespace Substrate
return true;
}
+ public void SetLocation (int x, int z)
+ {
+ ChunkRef c = _container.SetChunk(x, z, GetChunk());
+
+ _container = c._container;
+ _cx = c._cx;
+ _cz = c._cz;
+ }
+
///
/// Gets a ChunkRef to the chunk positioned immediately north (X - 1).
///
@@ -207,10 +216,10 @@ namespace Substrate
/// Returns a deep copy of the physical chunk underlying the ChunkRef.
///
/// A copy of the physical Chunk object.
- public Chunk GetChunkCopy ()
+ /*public Chunk GetChunkCopy ()
{
return GetChunk().Copy();
- }
+ }*/
///
/// Returns the reference of the physical chunk underlying the ChunkRef, and releases the reference from itself.
@@ -223,9 +232,9 @@ namespace Substrate
/// to modify them without intending to permanently store the changes.
///
/// The physical Chunk object underlying the ChunkRef
- public Chunk GetChunkRef ()
+ public IChunk GetChunkRef ()
{
- Chunk chunk = GetChunk();
+ IChunk chunk = GetChunk();
_chunk = null;
_dirty = false;
@@ -240,7 +249,7 @@ namespace Substrate
/// move a physical chunk between locations within a container (by taking the reference from another ChunkRef).
///
/// Physical Chunk to store into the location represented by this ChunkRef.
- public void SetChunkRef (Chunk chunk)
+ public void SetChunkRef (IChunk chunk)
{
_chunk = chunk;
_chunk.SetLocation(X, Z);
@@ -251,7 +260,7 @@ namespace Substrate
/// Gets an internal Chunk reference from cache or queries the container for it.
///
/// The ChunkRef's underlying Chunk.
- private Chunk GetChunk ()
+ private IChunk GetChunk ()
{
if (_chunk == null) {
_chunk = _container.GetChunk(_cx, _cz);
diff --git a/SubstrateCS/Source/Core/ChunkInterface.cs b/SubstrateCS/Source/Core/ChunkInterface.cs
index 78e2772..da2a089 100644
--- a/SubstrateCS/Source/Core/ChunkInterface.cs
+++ b/SubstrateCS/Source/Core/ChunkInterface.cs
@@ -36,6 +36,8 @@ namespace Substrate.Core
/// Terrain features include ores, water and lava sources, dungeons, trees, flowers, etc.
bool IsTerrainPopulated { get; set; }
+ void SetLocation (int x, int z);
+
///
/// Writes out the chunk's data to an output stream.
///
@@ -90,19 +92,19 @@ namespace Substrate.Core
int ChunkLocalZ (int cz);
///
- /// Gets an unwrapped object for the given container-local coordinates.
+ /// Gets an unwrapped object for the given container-local coordinates.
///
/// The container-local X-coordinate of a chunk.
/// The container-local Z-coordinate of a chunk.
- /// A for the given coordinates, or null if no chunk exists at those coordinates.
- Chunk GetChunk (int cx, int cz);
+ /// A for the given coordinates, or null if no chunk exists at those coordinates.
+ IChunk GetChunk (int cx, int cz);
///
/// Gets a binding a chunk to this container for the given container-local coordinates.
///
/// The container-local X-coordinate of a chunk.
/// The container-local Z-coordinate of a chunk.
- /// A for the given coordinates binding a to this container, or null if
+ /// A for the given coordinates binding a to this container, or null if
/// no chunk exists at the given coordinates.
ChunkRef GetChunkRef (int cx, int cz);
@@ -117,19 +119,19 @@ namespace Substrate.Core
ChunkRef CreateChunk (int cx, int cz);
///
- /// Saves an unwrapped to the container at the given container-local coordinates.
+ /// Saves an unwrapped to the container at the given container-local coordinates.
///
/// The container-local X-coordinate to save the chunk to.
/// The container-local Z-coordinate to save the chunk to.
- /// The to save at the given coordinates.
+ /// The to save at the given coordinates.
/// A binding to this container at the given location.
- /// The argument will be updated to reflect new global coordinates corresponding to
+ /// The argument will be updated to reflect new global coordinates corresponding to
/// the given location in this container. It is up to the developer to ensure that no competing
- /// has a handle to the argument, or an inconsistency could develop where the chunk held by the
+ /// has a handle to the argument, or an inconsistency could develop where the chunk held by the
/// other is written to the underlying data store with invalid coordinates.
/// The specification is designed to avoid this situation from occuring, but
/// class hierarchy extensions could violate these safeguards.
- ChunkRef SetChunk (int cx, int cz, Chunk chunk);
+ ChunkRef SetChunk (int cx, int cz, IChunk chunk);
///
/// Checks if a chunk exists at the given container-local coordinates.
@@ -159,7 +161,7 @@ namespace Substrate.Core
// TODO: Check that this doesn't violate borders
///
- bool SaveChunk (Chunk chunk);
+ bool SaveChunk (IChunk chunk);
///
/// Checks if this container supports delegating an action on out-of-bounds coordinates to another container.
diff --git a/SubstrateCS/Source/Core/RegionInterface.cs b/SubstrateCS/Source/Core/RegionInterface.cs
index e156f02..bf1ae32 100644
--- a/SubstrateCS/Source/Core/RegionInterface.cs
+++ b/SubstrateCS/Source/Core/RegionInterface.cs
@@ -4,17 +4,43 @@ using System.Text;
namespace Substrate.Core
{
+
public interface IRegionContainer
{
+ ///
+ /// Determines if a region exists at the given coordinates.
+ ///
+ /// The global X-coordinate of a region.
+ /// The global Z-coordinate of a region.
+ /// True if a region exists at the given global region coordinates; false otherwise.
bool RegionExists (int rx, int rz);
- Region GetRegion (int rx, int rz);
- Region CreateRegion (int rx, int rz);
+ ///
+ /// Gets an for the given region filename.
+ ///
+ /// The filename of the region to get.
+ /// A corresponding to the coordinates encoded in the filename.
+ IRegion GetRegion (int rx, int rz);
+ ///
+ /// Creates a new empty region at the given coordinates, if no region exists.
+ ///
+ /// The global X-coordinate of a region.
+ /// The global Z-coordinate of a region.
+ /// A new empty object for the given coordinates, or an existing if one exists.
+ IRegion CreateRegion (int rx, int rz);
+
+ ///
+ /// Deletes a region at the given coordinates.
+ ///
+ /// The global X-coordinate of a region.
+ /// The global Z-coordinate of a region.
+ /// True if a region was deleted; false otherwise.
bool DeleteRegion (int rx, int rz);
}
- public interface IRegionManager : IRegionContainer, IEnumerable
+ public interface IRegionManager : IRegionContainer, IEnumerable
{
+
}
}
diff --git a/SubstrateCS/Source/EntityCollection.cs b/SubstrateCS/Source/EntityCollection.cs
index f385106..8b566d8 100644
--- a/SubstrateCS/Source/EntityCollection.cs
+++ b/SubstrateCS/Source/EntityCollection.cs
@@ -89,7 +89,7 @@ namespace Substrate
/// The object to add.
/// It is up to the developer to ensure that the being added to the collection has a position that
/// is within acceptable range of the collection. transparently back other objects such as
- /// objects, which have a well-defined position in global space. The itself has
+ /// objects, which have a well-defined position in global space. The itself has
/// no concept of position and will not enforce constraints on the positions of objects being added.
public void Add (TypedEntity ent)
{
diff --git a/SubstrateCS/Source/NbtWorld.cs b/SubstrateCS/Source/NbtWorld.cs
index 84348a7..2b8473c 100644
--- a/SubstrateCS/Source/NbtWorld.cs
+++ b/SubstrateCS/Source/NbtWorld.cs
@@ -176,8 +176,9 @@ namespace Substrate
static NbtWorld ()
{
- ResolveOpen += AlphaWorld.OnResolveOpen;
+ ResolveOpen += AnvilWorld.OnResolveOpen;
ResolveOpen += BetaWorld.OnResolveOpen;
+ ResolveOpen += AlphaWorld.OnResolveOpen;
}
}
}
diff --git a/SubstrateCS/Source/Region.cs b/SubstrateCS/Source/Region.cs
index 818f269..73bf75d 100644
--- a/SubstrateCS/Source/Region.cs
+++ b/SubstrateCS/Source/Region.cs
@@ -8,29 +8,213 @@ using Substrate.Core;
namespace Substrate
{
+ public interface IRegion : IChunkContainer
+ {
+ int X { get; }
+
+ int Z { get; }
+
+ ///
+ /// Get the appropriate filename for this region.
+ ///
+ /// The filename of the region with encoded coordinates.
+ string GetFileName ();
+
+ ///
+ /// Gets the full path of the region's backing file.
+ ///
+ /// Gets the path of the region's file based on the 's region path and the region's on filename.
+ string GetFilePath ();
+
+ NbtTree GetChunkTree (int lcx, int lcz);
+ bool SaveChunkTree (int lcx, int lcz, NbtTree tree);
+ bool SaveChunkTree (int lcx, int lcz, NbtTree tree, int timestamp);
+ Stream GetChunkOutStream (int lcx, int lcz);
+
+ int ChunkCount ();
+ ChunkRef GetChunkRef (int lcx, int lcz);
+
+ ///
+ /// Creates a new chunk at the given local coordinates relative to this region and returns a new for it.
+ ///
+ /// The local X-coordinate of a chunk relative to this region.
+ /// The local Z-coordinate of a chunk relative to this region.
+ /// A for the newly created chunk.
+ /// If the local coordinates are out of bounds for this region, the action will be forwarded to the correct region
+ /// transparently.
+ ChunkRef CreateChunk (int lcx, int lcz);
+
+ int GetChunkTimestamp (int lcx, int lcz);
+ void SetChunkTimestamp (int lcx, int lcz, int timestamp);
+ }
+
+ public class BetaRegion : Region
+ {
+ private static Regex _namePattern = new Regex("r\\.(-?[0-9]+)\\.(-?[0-9]+)\\.mcr$");
+
+ public BetaRegion (BetaRegionManager rm, ChunkCache cache, int rx, int rz)
+ : base(rm, cache, rx, rz)
+ {
+ }
+
+ ///
+ public string GetFileName ()
+ {
+ return "r." + _rx + "." + _rz + ".mcr";
+
+ }
+
+ ///
+ public string GetFilePath ()
+ {
+ return System.IO.Path.Combine(_regionMan.GetRegionPath(), GetFileName());
+ }
+
+ ///
+ /// Tests if the given filename conforms to the general naming pattern for any region.
+ ///
+ /// The filename to test.
+ /// True if the filename is a valid region name; false if it does not conform to the pattern.
+ public static bool TestFileName (string filename)
+ {
+ Match match = _namePattern.Match(filename);
+ if (!match.Success) {
+ return false;
+ }
+
+ return true;
+ }
+
+ ///
+ /// Parses the given filename to extract encoded region coordinates.
+ ///
+ /// The region filename to parse.
+ /// This parameter will contain the X-coordinate of a region.
+ /// This parameter will contain the Z-coordinate of a region.
+ /// True if the filename could be correctly parse; false otherwise.
+ public static bool ParseFileName (string filename, out int x, out int z)
+ {
+ x = 0;
+ z = 0;
+
+ Match match = _namePattern.Match(filename);
+ if (!match.Success) {
+ return false;
+ }
+
+ x = Convert.ToInt32(match.Groups[1].Value);
+ z = Convert.ToInt32(match.Groups[2].Value);
+ return true;
+ }
+
+ protected override IChunk CreateChunkCore (int cx, int cz)
+ {
+ return AlphaChunk.Create(cz, cz);
+ }
+
+ protected override IChunk CreateChunkVerifiedCore (NbtTree tree)
+ {
+ return AlphaChunk.CreateVerified(tree);
+ }
+ }
+
+ public class AnvilRegion : Region
+ {
+ private static Regex _namePattern = new Regex("r\\.(-?[0-9]+)\\.(-?[0-9]+)\\.mcr$");
+
+ public AnvilRegion (AnvilRegionManager rm, ChunkCache cache, int rx, int rz)
+ : base(rm, cache, rx, rz)
+ {
+ }
+
+ ///
+ public string GetFileName ()
+ {
+ return "r." + _rx + "." + _rz + ".mcr";
+
+ }
+
+ ///
+ public string GetFilePath ()
+ {
+ return System.IO.Path.Combine(_regionMan.GetRegionPath(), GetFileName());
+ }
+
+ ///
+ /// Tests if the given filename conforms to the general naming pattern for any region.
+ ///
+ /// The filename to test.
+ /// True if the filename is a valid region name; false if it does not conform to the pattern.
+ public static bool TestFileName (string filename)
+ {
+ Match match = _namePattern.Match(filename);
+ if (!match.Success) {
+ return false;
+ }
+
+ return true;
+ }
+
+ ///
+ /// Parses the given filename to extract encoded region coordinates.
+ ///
+ /// The region filename to parse.
+ /// This parameter will contain the X-coordinate of a region.
+ /// This parameter will contain the Z-coordinate of a region.
+ /// True if the filename could be correctly parse; false otherwise.
+ public static bool ParseFileName (string filename, out int x, out int z)
+ {
+ x = 0;
+ z = 0;
+
+ Match match = _namePattern.Match(filename);
+ if (!match.Success) {
+ return false;
+ }
+
+ x = Convert.ToInt32(match.Groups[1].Value);
+ z = Convert.ToInt32(match.Groups[2].Value);
+ return true;
+ }
+
+ protected override IChunk CreateChunkCore (int cx, int cz)
+ {
+ return AlphaChunk.Create(cz, cz);
+ }
+
+ protected override IChunk CreateChunkVerifiedCore (NbtTree tree)
+ {
+ return AlphaChunk.CreateVerified(tree);
+ }
+ }
+
///
/// Represents a single region containing 32x32 chunks.
///
- public class Region : IDisposable, IChunkContainer
+ public abstract class Region : IDisposable, IRegion
{
- private const int XDIM = 32;
- private const int ZDIM = 32;
- private const int XMASK = XDIM - 1;
- private const int ZMASK = ZDIM - 1;
- private const int XLOG = 5;
- private const int ZLOG = 5;
+ protected const int XDIM = 32;
+ protected const int ZDIM = 32;
+ protected const int XMASK = XDIM - 1;
+ protected const int ZMASK = ZDIM - 1;
+ protected const int XLOG = 5;
+ protected const int ZLOG = 5;
- private int _rx;
- private int _rz;
+ protected int _rx;
+ protected int _rz;
private bool _disposed = false;
- private RegionManager _regionMan;
+ protected RegionManager _regionMan;
private static Regex _namePattern = new Regex("r\\.(-?[0-9]+)\\.(-?[0-9]+)\\.mca$");
private WeakReference _regionFile;
- private ChunkCache _cache;
+ protected ChunkCache _cache;
+
+ protected abstract IChunk CreateChunkCore (int cx, int cz);
+
+ protected abstract IChunk CreateChunkVerifiedCore (NbtTree tree);
///
/// Gets the global X-coordinate of the region.
@@ -227,7 +411,7 @@ namespace Substrate
public NbtTree GetChunkTree (int lcx, int lcz)
{
if (!LocalBoundsCheck(lcx, lcz)) {
- Region alt = GetForeignRegion(lcx, lcz);
+ IRegion alt = GetForeignRegion(lcx, lcz);
return (alt == null) ? null : alt.GetChunkTree(ForeignX(lcx), ForeignZ(lcz));
}
@@ -276,7 +460,7 @@ namespace Substrate
private bool SaveChunkTree (int lcx, int lcz, NbtTree tree, int? timestamp)
{
if (!LocalBoundsCheck(lcx, lcz)) {
- Region alt = GetForeignRegion(lcx, lcz);
+ IRegion alt = GetForeignRegion(lcx, lcz);
return (alt == null) ? false : alt.SaveChunkTree(ForeignX(lcx), ForeignZ(lcz), tree);
}
@@ -305,7 +489,7 @@ namespace Substrate
public Stream GetChunkOutStream (int lcx, int lcz)
{
if (!LocalBoundsCheck(lcx, lcz)) {
- Region alt = GetForeignRegion(lcx, lcz);
+ IRegion alt = GetForeignRegion(lcx, lcz);
return (alt == null) ? null : alt.GetChunkOutStream(ForeignX(lcx), ForeignZ(lcz));
}
@@ -342,12 +526,12 @@ namespace Substrate
/// A at the given local coordinates, or null if no chunk exists.
/// The local coordinates do not strictly need to be within the bounds of the region. If coordinates are detected
/// as being out of bounds, the lookup will be delegated to the correct region and the lookup will be performed there
- /// instead. This allows any to perform a similar task to , but with a
+ /// instead. This allows any to perform a similar task to , but with a
/// region-local frame of reference instead of a global frame of reference.
public ChunkRef GetChunkRef (int lcx, int lcz)
{
if (!LocalBoundsCheck(lcx, lcz)) {
- Region alt = GetForeignRegion(lcx, lcz);
+ IRegion alt = GetForeignRegion(lcx, lcz);
return (alt == null) ? null : alt.GetChunkRef(ForeignX(lcx), ForeignZ(lcz));
}
@@ -379,7 +563,7 @@ namespace Substrate
public ChunkRef CreateChunk (int lcx, int lcz)
{
if (!LocalBoundsCheck(lcx, lcz)) {
- Region alt = GetForeignRegion(lcx, lcz);
+ IRegion alt = GetForeignRegion(lcx, lcz);
return (alt == null) ? null : alt.CreateChunk(ForeignX(lcx), ForeignZ(lcz));
}
@@ -388,7 +572,7 @@ namespace Substrate
int cx = lcx + _rx * XDIM;
int cz = lcz + _rz * ZDIM;
- Chunk c = Chunk.Create(cx, cz);
+ AlphaChunk c = AlphaChunk.Create(cx, cz);
c.Save(GetChunkOutStream(lcx, lcz));
ChunkRef cr = ChunkRef.Create(this, lcx, lcz);
@@ -442,17 +626,17 @@ namespace Substrate
}
///
- /// Returns a given local coordinates relative to this region.
+ /// Returns a given local coordinates relative to this region.
///
/// The local X-coordinate of a chunk relative to this region.
/// The local Z-coordinate of a chunk relative to this region.
- /// A object for the given coordinates, or null if the chunk does not exist.
+ /// A object for the given coordinates, or null if the chunk does not exist.
/// If the local coordinates are out of bounds for this region, the action will be forwarded to the correct region
- /// transparently. The returned object may either come from cache, or be regenerated from disk.
- public Chunk GetChunk (int lcx, int lcz)
+ /// transparently. The returned object may either come from cache, or be regenerated from disk.
+ public IChunk GetChunk (int lcx, int lcz)
{
if (!LocalBoundsCheck(lcx, lcz)) {
- Region alt = GetForeignRegion(lcx, lcz);
+ IRegion alt = GetForeignRegion(lcx, lcz);
return (alt == null) ? null : alt.GetChunk(ForeignX(lcx), ForeignZ(lcz));
}
@@ -460,7 +644,7 @@ namespace Substrate
return null;
}
- return Chunk.CreateVerified(GetChunkTree(lcx, lcz));
+ return CreateChunkVerifiedCore(GetChunkTree(lcx, lcz));
}
///
@@ -474,7 +658,7 @@ namespace Substrate
public bool ChunkExists (int lcx, int lcz)
{
if (!LocalBoundsCheck(lcx, lcz)) {
- Region alt = GetForeignRegion(lcx, lcz);
+ IRegion alt = GetForeignRegion(lcx, lcz);
return (alt == null) ? false : alt.ChunkExists(ForeignX(lcx), ForeignZ(lcz));
}
@@ -493,7 +677,7 @@ namespace Substrate
public bool DeleteChunk (int lcx, int lcz)
{
if (!LocalBoundsCheck(lcx, lcz)) {
- Region alt = GetForeignRegion(lcx, lcz);
+ IRegion alt = GetForeignRegion(lcx, lcz);
return (alt == null) ? false : alt.DeleteChunk(ForeignX(lcx), ForeignZ(lcz));
}
@@ -516,18 +700,18 @@ namespace Substrate
}
///
- /// Saves an existing to the region at the given local coordinates.
+ /// Saves an existing to the region at the given local coordinates.
///
/// The local X-coordinate of a chunk relative to this region.
/// The local Z-coordinate of a chunk relative to this region.
- /// A to save to the given location.
- /// A represneting the at its new location.
+ /// A to save to the given location.
+ /// A represneting the at its new location.
/// If the local coordinates are out of bounds for this region, the action will be forwarded to the correct region
- /// transparently. The 's internal global coordinates will be updated to reflect the new location.
- public ChunkRef SetChunk (int lcx, int lcz, Chunk chunk)
+ /// transparently. The 's internal global coordinates will be updated to reflect the new location.
+ public ChunkRef SetChunk (int lcx, int lcz, IChunk chunk)
{
if (!LocalBoundsCheck(lcx, lcz)) {
- Region alt = GetForeignRegion(lcx, lcz);
+ IRegion alt = GetForeignRegion(lcx, lcz);
return (alt == null) ? null : alt.CreateChunk(ForeignX(lcx), ForeignZ(lcz));
}
@@ -573,7 +757,7 @@ namespace Substrate
// XXX: Allows a chunk not part of this region to be saved to it
///
- public bool SaveChunk (Chunk chunk)
+ public bool SaveChunk (IChunk chunk)
{
//Console.WriteLine("Region[{0}, {1}].Save({2}, {3})", _rx, _rz, ForeignX(chunk.X),ForeignZ(chunk.Z));
return chunk.Save(GetChunkOutStream(ForeignX(chunk.X), ForeignZ(chunk.Z)));
@@ -597,7 +781,7 @@ namespace Substrate
public int GetChunkTimestamp (int lcx, int lcz)
{
if (!LocalBoundsCheck(lcx, lcz)) {
- Region alt = GetForeignRegion(lcx, lcz);
+ IRegion alt = GetForeignRegion(lcx, lcz);
return (alt == null) ? 0 : alt.GetChunkTimestamp(ForeignX(lcx), ForeignZ(lcz));
}
@@ -616,7 +800,7 @@ namespace Substrate
public void SetChunkTimestamp (int lcx, int lcz, int timestamp)
{
if (!LocalBoundsCheck(lcx, lcz)) {
- Region alt = GetForeignRegion(lcx, lcz);
+ IRegion alt = GetForeignRegion(lcx, lcz);
if (alt != null)
alt.SetChunkTimestamp(ForeignX(lcx), ForeignZ(lcz), timestamp);
}
@@ -627,22 +811,22 @@ namespace Substrate
#endregion
- private bool LocalBoundsCheck (int lcx, int lcz)
+ protected bool LocalBoundsCheck (int lcx, int lcz)
{
return (lcx >= 0 && lcx < XDIM && lcz >= 0 && lcz < ZDIM);
}
- private Region GetForeignRegion (int lcx, int lcz)
+ protected IRegion GetForeignRegion (int lcx, int lcz)
{
return _regionMan.GetRegion(_rx + (lcx >> XLOG), _rz + (lcz >> ZLOG));
}
- private int ForeignX (int lcx)
+ protected int ForeignX (int lcx)
{
return (lcx + XDIM * 10000) & XMASK;
}
- private int ForeignZ (int lcz)
+ protected int ForeignZ (int lcz)
{
return (lcz + ZDIM * 10000) & ZMASK;
}
diff --git a/SubstrateCS/Source/RegionManager.cs b/SubstrateCS/Source/RegionManager.cs
index 74040e6..6356404 100644
--- a/SubstrateCS/Source/RegionManager.cs
+++ b/SubstrateCS/Source/RegionManager.cs
@@ -6,16 +6,99 @@ using Substrate.Core;
namespace Substrate
{
+ public class BetaRegionManager : RegionManager
+ {
+ public BetaRegionManager (string regionDir, ChunkCache cache)
+ : base(regionDir, cache)
+ {
+ }
+
+ protected override IRegion CreateRegionCore (int rx, int rz)
+ {
+ return new BetaRegion(this, _chunkCache, rx, rz);
+ }
+
+ protected override RegionFile CreateRegionFileCore (int rx, int rz)
+ {
+ string fp = "r." + rx + "." + rz + ".mcr";
+ return new RegionFile(Path.Combine(_regionPath, fp));
+ }
+
+ protected override void DeleteRegionCore (IRegion region)
+ {
+ BetaRegion r = region as BetaRegion;
+ if (r != null) {
+ r.Dispose();
+ }
+ }
+
+ public override IRegion GetRegion (string filename)
+ {
+ int rx, rz;
+ if (!BetaRegion.ParseFileName(filename, out rx, out rz)) {
+ throw new ArgumentException("Malformed region file name: " + filename, "filename");
+ }
+
+ return GetRegion(rx, rz);
+ }
+ }
+
+ public class AnvilRegionManager : RegionManager
+ {
+ public AnvilRegionManager (string regionDir, ChunkCache cache)
+ : base(regionDir, cache)
+ {
+ }
+
+ protected override IRegion CreateRegionCore (int rx, int rz)
+ {
+ return new AnvilRegion(this, _chunkCache, rx, rz);
+ }
+
+ protected override RegionFile CreateRegionFileCore (int rx, int rz)
+ {
+ string fp = "r." + rx + "." + rz + ".mca";
+ return new RegionFile(Path.Combine(_regionPath, fp));
+ }
+
+ protected override void DeleteRegionCore (IRegion region)
+ {
+ AnvilRegion r = region as AnvilRegion;
+ if (r != null) {
+ r.Dispose();
+ }
+ }
+
+ public override IRegion GetRegion (string filename)
+ {
+ int rx, rz;
+ if (!AnvilRegion.ParseFileName(filename, out rx, out rz)) {
+ throw new ArgumentException("Malformed region file name: " + filename, "filename");
+ }
+
+ return GetRegion(rx, rz);
+ }
+ }
+
///
/// Manages the regions of a Beta-compatible world.
///
- public class RegionManager : IRegionManager
+ public abstract class RegionManager : IRegionManager
{
- private string _regionPath;
+ protected string _regionPath;
- private Dictionary _cache;
+ protected Dictionary _cache;
- private ChunkCache _chunkCache;
+ protected ChunkCache _chunkCache;
+
+
+ protected abstract IRegion CreateRegionCore (int rx, int rz);
+
+ protected abstract RegionFile CreateRegionFileCore (int rx, int rz);
+
+ protected abstract void DeleteRegionCore (IRegion region);
+
+ public abstract IRegion GetRegion (string filename);
///
/// Creates a new instance of a for the given region directory and chunk cache.
@@ -26,7 +109,7 @@ namespace Substrate
{
_regionPath = regionDir;
_chunkCache = cache;
- _cache = new Dictionary();
+ _cache = new Dictionary();
}
///
@@ -35,14 +118,14 @@ namespace Substrate
/// The global X-coordinate of a region.
/// The global Z-coordinate of a region.
/// A representing a region at the given coordinates, or null if the region does not exist.
- public Region GetRegion (int rx, int rz)
+ public IRegion GetRegion (int rx, int rz)
{
RegionKey k = new RegionKey(rx, rz);
- Region r;
+ IRegion r;
try {
if (_cache.TryGetValue(k, out r) == false) {
- r = new Region(this, _chunkCache, rx, rz);
+ r = CreateRegionCore(rz, rz);
_cache.Add(k, r);
}
return r;
@@ -53,34 +136,24 @@ namespace Substrate
}
}
- ///
- /// Determines if a region exists at the given coordinates.
- ///
- /// The global X-coordinate of a region.
- /// The global Z-coordinate of a region.
- /// True if a region exists at the given global region coordinates; false otherwise.
+ ///
public bool RegionExists (int rx, int rz)
{
- Region r = GetRegion(rx, rz);
+ IRegion r = GetRegion(rx, rz);
return r != null;
}
- ///
- /// Creates a new empty region at the given coordinates, if no region exists.
- ///
- /// The global X-coordinate of a region.
- /// The global Z-coordinate of a region.
- /// A new empty object for the given coordinates, or an existing if one exists.
- public Region CreateRegion (int rx, int rz)
+ ///
+ public IRegion CreateRegion (int rx, int rz)
{
- Region r = GetRegion(rx, rz);
+ IRegion r = GetRegion(rx, rz);
if (r == null) {
string fp = "r." + rx + "." + rz + ".mca";
- using (RegionFile rf = new RegionFile(Path.Combine(_regionPath, fp))) {
+ using (RegionFile rf = CreateRegionFileCore(rx, rz)) {
}
- r = new Region(this, _chunkCache, rx, rz);
+ r = CreateRegionCore(rx, rz);
RegionKey k = new RegionKey(rx, rz);
_cache[k] = r;
@@ -89,21 +162,6 @@ namespace Substrate
return r;
}
- ///
- /// Gets a for the given region filename.
- ///
- /// The filename of the region to get.
- /// A corresponding to the coordinates encoded in the filename.
- public Region GetRegion (string filename)
- {
- int rx, rz;
- if (!Region.ParseFileName(filename, out rx, out rz)) {
- throw new ArgumentException("Malformed region file name: " + filename, "filename");
- }
-
- return GetRegion(rx, rz);
- }
-
///
/// Get the current region directory path.
///
@@ -114,15 +172,10 @@ namespace Substrate
}
// XXX: Exceptions
- ///
- /// Deletes a region at the given coordinates.
- ///
- /// The global X-coordinate of a region.
- /// The global Z-coordinate of a region.
- /// True if a region was deleted; false otherwise.
+ ///
public bool DeleteRegion (int rx, int rz)
{
- Region r = GetRegion(rx, rz);
+ IRegion r = GetRegion(rx, rz);
if (r == null) {
return false;
}
@@ -130,7 +183,7 @@ namespace Substrate
RegionKey k = new RegionKey(rx, rz);
_cache.Remove(k);
- r.Dispose();
+ DeleteRegionCore(r);
try {
File.Delete(r.GetFilePath());
@@ -143,13 +196,13 @@ namespace Substrate
return true;
}
- #region IEnumerable Members
+ #region IEnumerable Members
///
/// Returns an enumerator that iterates over all of the regions in the underlying dimension.
///
/// An enumerator instance.
- public IEnumerator GetEnumerator ()
+ public IEnumerator GetEnumerator ()
{
return new Enumerator(this);
}
@@ -170,14 +223,14 @@ namespace Substrate
#endregion
- private struct Enumerator : IEnumerator
+ private struct Enumerator : IEnumerator
{
- private List _regions;
+ private List _regions;
private int _pos;
public Enumerator (RegionManager rm)
{
- _regions = new List();
+ _regions = new List();
_pos = -1;
if (!Directory.Exists(rm.GetRegionPath())) {
@@ -189,7 +242,7 @@ namespace Substrate
foreach (string file in files) {
try {
- Region r = rm.GetRegion(file);
+ IRegion r = rm.GetRegion(file);
_regions.Add(r);
}
catch (ArgumentException) {
@@ -219,7 +272,7 @@ namespace Substrate
}
}
- Region IEnumerator.Current
+ IRegion IEnumerator.Current
{
get
{
@@ -227,7 +280,7 @@ namespace Substrate
}
}
- public Region Current
+ public IRegion Current
{
get
{