forked from mirrors/NBTExplorer
Anvil/Beta/Alpha support unification
This commit is contained in:
parent
f65238abde
commit
63e0bc1876
17 changed files with 1289 additions and 622 deletions
|
@ -7,7 +7,7 @@ namespace Substrate
|
||||||
/// A single Alpha-compatible block with context-independent data.
|
/// A single Alpha-compatible block with context-independent data.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks><para>In general, you should prefer other types for accessing block data including <see cref="AlphaBlockRef"/>,
|
/// <remarks><para>In general, you should prefer other types for accessing block data including <see cref="AlphaBlockRef"/>,
|
||||||
/// <see cref="BlockManager"/>, and the <see cref="AlphaBlockCollection"/> property of <see cref="Chunk"/> and <see cref="ChunkRef"/>.</para>
|
/// <see cref="BlockManager"/>, and the <see cref="AlphaBlockCollection"/> property of <see cref="IChunk"/> and <see cref="ChunkRef"/>.</para>
|
||||||
/// <para>You should use the <see cref="AlphaBlock"/> type when you need to copy individual blocks into a custom collection or
|
/// <para>You should use the <see cref="AlphaBlock"/> 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. <see cref="AlphaBlock"/>
|
/// container, and context-depdendent data such as coordinates and lighting have no well-defined meaning. <see cref="AlphaBlock"/>
|
||||||
/// offers a relatively compact footprint for storing the unique identity of a block's manifestation in the world.</para>
|
/// offers a relatively compact footprint for storing the unique identity of a block's manifestation in the world.</para>
|
||||||
|
|
|
@ -9,7 +9,7 @@ namespace Substrate
|
||||||
/// Functions for reading and modifying a bounded-size collection of Alpha-compatible block data.
|
/// Functions for reading and modifying a bounded-size collection of Alpha-compatible block data.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>An <see cref="AlphaBlockCollection"/> is a wrapper around existing pieces of data. Although it
|
/// <remarks>An <see cref="AlphaBlockCollection"/> 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 <see cref="Chunk"/> does. An
|
/// holds references to data, it does not "own" the data in the same way that a <see cref="IChunk"/> does. An
|
||||||
/// <see cref="AlphaBlockCollection"/> simply overlays a higher-level interface on top of existing data.</remarks>
|
/// <see cref="AlphaBlockCollection"/> simply overlays a higher-level interface on top of existing data.</remarks>
|
||||||
public class AlphaBlockCollection : IBoundedAlphaBlockCollection, IBoundedActiveBlockCollection
|
public class AlphaBlockCollection : IBoundedAlphaBlockCollection, IBoundedActiveBlockCollection
|
||||||
{
|
{
|
||||||
|
|
|
@ -7,12 +7,12 @@ using Substrate.Nbt;
|
||||||
namespace Substrate
|
namespace Substrate
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A Minecraft Alpha-compatible chunk data structure.
|
/// A Minecraft Alpha- and Beta-compatible chunk data structure.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// A Chunk internally wraps an NBT_Tree of raw chunk data. Modifying the chunk will update the tree, and vice-versa.
|
/// A Chunk internally wraps an NBT_Tree of raw chunk data. Modifying the chunk will update the tree, and vice-versa.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public class Chunk : IChunk, INbtObject<Chunk>, ICopyable<Chunk>
|
public class AlphaChunk : IChunk, INbtObject<AlphaChunk>, ICopyable<AlphaChunk>
|
||||||
{
|
{
|
||||||
private const int XDIM = 16;
|
private const int XDIM = 16;
|
||||||
private const int YDIM = 128;
|
private const int YDIM = 128;
|
||||||
|
@ -108,7 +108,7 @@ namespace Substrate
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private Chunk ()
|
private AlphaChunk ()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,9 +118,9 @@ namespace Substrate
|
||||||
/// <param name="x">Global X-coordinate of the chunk.</param>
|
/// <param name="x">Global X-coordinate of the chunk.</param>
|
||||||
/// <param name="z">Global Z-coordinate of the chunk.</param>
|
/// <param name="z">Global Z-coordinate of the chunk.</param>
|
||||||
/// <returns>A new Chunk object.</returns>
|
/// <returns>A new Chunk object.</returns>
|
||||||
public static Chunk Create (int x, int z)
|
public static AlphaChunk Create (int x, int z)
|
||||||
{
|
{
|
||||||
Chunk c = new Chunk();
|
AlphaChunk c = new AlphaChunk();
|
||||||
|
|
||||||
c._cx = x;
|
c._cx = x;
|
||||||
c._cz = z;
|
c._cz = z;
|
||||||
|
@ -134,9 +134,9 @@ namespace Substrate
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="tree">An NBT_Tree conforming to the chunk schema definition.</param>
|
/// <param name="tree">An NBT_Tree conforming to the chunk schema definition.</param>
|
||||||
/// <returns>A new Chunk object wrapping an existing NBT_Tree.</returns>
|
/// <returns>A new Chunk object wrapping an existing NBT_Tree.</returns>
|
||||||
public static Chunk Create (NbtTree tree)
|
public static AlphaChunk Create (NbtTree tree)
|
||||||
{
|
{
|
||||||
Chunk c = new Chunk();
|
AlphaChunk c = new AlphaChunk();
|
||||||
|
|
||||||
return c.LoadTree(tree.Root);
|
return c.LoadTree(tree.Root);
|
||||||
}
|
}
|
||||||
|
@ -146,9 +146,9 @@ namespace Substrate
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="tree">An NBT_Tree conforming to the chunk schema definition.</param>
|
/// <param name="tree">An NBT_Tree conforming to the chunk schema definition.</param>
|
||||||
/// <returns>A new Chunk object wrapping an existing NBT_Tree, or null on verification failure.</returns>
|
/// <returns>A new Chunk object wrapping an existing NBT_Tree, or null on verification failure.</returns>
|
||||||
public static Chunk CreateVerified (NbtTree tree)
|
public static AlphaChunk CreateVerified (NbtTree tree)
|
||||||
{
|
{
|
||||||
Chunk c = new Chunk();
|
AlphaChunk c = new AlphaChunk();
|
||||||
|
|
||||||
return c.LoadTreeSafe(tree.Root);
|
return c.LoadTreeSafe(tree.Root);
|
||||||
}
|
}
|
||||||
|
@ -158,7 +158,7 @@ namespace Substrate
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="x">Global X-coordinate.</param>
|
/// <param name="x">Global X-coordinate.</param>
|
||||||
/// <param name="z">Global Z-coordinate.</param>
|
/// <param name="z">Global Z-coordinate.</param>
|
||||||
public virtual void SetLocation (int x, int z)
|
public void SetLocation (int x, int z)
|
||||||
{
|
{
|
||||||
int diffx = (x - _cx) * XDIM;
|
int diffx = (x - _cx) * XDIM;
|
||||||
int diffz = (z - _cz) * ZDIM;
|
int diffz = (z - _cz) * ZDIM;
|
||||||
|
@ -251,7 +251,7 @@ namespace Substrate
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="tree">Root node of an NBT tree.</param>
|
/// <param name="tree">Root node of an NBT tree.</param>
|
||||||
/// <returns>A reference to the current Chunk, or null if the tree is unparsable.</returns>
|
/// <returns>A reference to the current Chunk, or null if the tree is unparsable.</returns>
|
||||||
public Chunk LoadTree (TagNode tree)
|
public AlphaChunk LoadTree (TagNode tree)
|
||||||
{
|
{
|
||||||
TagNodeCompound ctree = tree as TagNodeCompound;
|
TagNodeCompound ctree = tree as TagNodeCompound;
|
||||||
if (ctree == null) {
|
if (ctree == null) {
|
||||||
|
@ -306,7 +306,7 @@ namespace Substrate
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="tree">Root node of an NBT tree.</param>
|
/// <param name="tree">Root node of an NBT tree.</param>
|
||||||
/// <returns>A reference to the current Chunk, or null if the tree does not conform to the chunk's NBT Schema definition.</returns>
|
/// <returns>A reference to the current Chunk, or null if the tree does not conform to the chunk's NBT Schema definition.</returns>
|
||||||
public Chunk LoadTreeSafe (TagNode tree)
|
public AlphaChunk LoadTreeSafe (TagNode tree)
|
||||||
{
|
{
|
||||||
if (!ValidateTree(tree)) {
|
if (!ValidateTree(tree)) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -346,9 +346,9 @@ namespace Substrate
|
||||||
/// Creates a deep copy of the Chunk and its underlying NBT tree.
|
/// Creates a deep copy of the Chunk and its underlying NBT tree.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>A new Chunk with copied data.</returns>
|
/// <returns>A new Chunk with copied data.</returns>
|
||||||
public Chunk Copy ()
|
public AlphaChunk Copy ()
|
||||||
{
|
{
|
||||||
return Chunk.Create(_tree.Copy());
|
return AlphaChunk.Create(_tree.Copy());
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
|
@ -101,13 +101,13 @@ namespace Substrate
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public Chunk GetChunk (int cx, int cz)
|
public IChunk GetChunk (int cx, int cz)
|
||||||
{
|
{
|
||||||
if (!ChunkExists(cx, cz)) {
|
if (!ChunkExists(cx, cz)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Chunk.CreateVerified(GetChunkTree(cx, cz));
|
return AlphaChunk.CreateVerified(GetChunkTree(cx, cz));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
|
@ -134,7 +134,7 @@ namespace Substrate
|
||||||
public ChunkRef CreateChunk (int cx, int cz)
|
public ChunkRef CreateChunk (int cx, int cz)
|
||||||
{
|
{
|
||||||
DeleteChunk(cx, cz);
|
DeleteChunk(cx, cz);
|
||||||
Chunk c = Chunk.Create(cx, cz);
|
AlphaChunk c = AlphaChunk.Create(cx, cz);
|
||||||
c.Save(GetChunkOutStream(cx, cz));
|
c.Save(GetChunkOutStream(cx, cz));
|
||||||
|
|
||||||
ChunkRef cr = ChunkRef.Create(this, cx, cz);
|
ChunkRef cr = ChunkRef.Create(this, cx, cz);
|
||||||
|
@ -163,7 +163,7 @@ namespace Substrate
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public ChunkRef SetChunk (int cx, int cz, Chunk chunk)
|
public ChunkRef SetChunk (int cx, int cz, IChunk chunk)
|
||||||
{
|
{
|
||||||
DeleteChunk(cx, cz);
|
DeleteChunk(cx, cz);
|
||||||
chunk.SetLocation(cx, cz);
|
chunk.SetLocation(cx, cz);
|
||||||
|
@ -200,7 +200,7 @@ namespace Substrate
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public bool SaveChunk (Chunk chunk)
|
public bool SaveChunk (IChunk chunk)
|
||||||
{
|
{
|
||||||
if (chunk.Save(GetChunkOutStream(ChunkGlobalX(chunk.X), ChunkGlobalZ(chunk.Z)))) {
|
if (chunk.Save(GetChunkOutStream(ChunkGlobalX(chunk.X), ChunkGlobalZ(chunk.Z)))) {
|
||||||
_dirty.Remove(new ChunkKey(chunk.X, chunk.Z));
|
_dirty.Remove(new ChunkKey(chunk.X, chunk.Z));
|
||||||
|
|
|
@ -44,7 +44,7 @@ namespace Substrate
|
||||||
/// <returns>A <see cref="BlockManager"/> tied to the default dimension in this world.</returns>
|
/// <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
|
/// <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
|
/// any higher-level organizational divisions. If your task is going to be heavily performance-bound, consider getting a
|
||||||
/// <see cref="BetaChunkManager"/> instead and working with blocks on a chunk-local level.</remarks>
|
/// <see cref="RegionChunkManager"/> instead and working with blocks on a chunk-local level.</remarks>
|
||||||
public new BlockManager GetBlockManager ()
|
public new BlockManager GetBlockManager ()
|
||||||
{
|
{
|
||||||
return GetBlockManagerVirt(Dimension.DEFAULT) as BlockManager;
|
return GetBlockManagerVirt(Dimension.DEFAULT) as BlockManager;
|
||||||
|
@ -57,28 +57,28 @@ namespace Substrate
|
||||||
/// <returns>A <see cref="BlockManager"/> tied to the given dimension in this world.</returns>
|
/// <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
|
/// <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
|
/// any higher-level organizational divisions. If your task is going to be heavily performance-bound, consider getting a
|
||||||
/// <see cref="BetaChunkManager"/> instead and working with blocks on a chunk-local level.</remarks>
|
/// <see cref="RegionChunkManager"/> instead and working with blocks on a chunk-local level.</remarks>
|
||||||
public new BlockManager GetBlockManager (int dim)
|
public new BlockManager GetBlockManager (int dim)
|
||||||
{
|
{
|
||||||
return GetBlockManagerVirt(dim) as BlockManager;
|
return GetBlockManagerVirt(dim) as BlockManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a <see cref="BetaChunkManager"/> for the default dimension.
|
/// Gets a <see cref="RegionChunkManager"/> for the default dimension.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>A <see cref="BetaChunkManager"/> tied to the default dimension in this world.</returns>
|
/// <returns>A <see cref="RegionChunkManager"/> tied to the default dimension in this world.</returns>
|
||||||
/// <remarks>Get a <see cref="BetaChunkManager"/> if you you need to work with easily-digestible, bounded chunks of blocks.</remarks>
|
/// <remarks>Get a <see cref="RegionChunkManager"/> if you you need to work with easily-digestible, bounded chunks of blocks.</remarks>
|
||||||
public new AlphaChunkManager GetChunkManager ()
|
public new AlphaChunkManager GetChunkManager ()
|
||||||
{
|
{
|
||||||
return GetChunkManagerVirt(Dimension.DEFAULT) as AlphaChunkManager;
|
return GetChunkManagerVirt(Dimension.DEFAULT) as AlphaChunkManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a <see cref="BetaChunkManager"/> for the given dimension.
|
/// Gets a <see cref="RegionChunkManager"/> for the given dimension.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="dim">The id of the dimension to look up.</param>
|
/// <param name="dim">The id of the dimension to look up.</param>
|
||||||
/// <returns>A <see cref="BetaChunkManager"/> tied to the given dimension in this world.</returns>
|
/// <returns>A <see cref="RegionChunkManager"/> tied to the given dimension in this world.</returns>
|
||||||
/// <remarks>Get a <see cref="BetaChunkManager"/> if you you need to work with easily-digestible, bounded chunks of blocks.</remarks>
|
/// <remarks>Get a <see cref="RegionChunkManager"/> if you you need to work with easily-digestible, bounded chunks of blocks.</remarks>
|
||||||
public new AlphaChunkManager GetChunkManager (int dim)
|
public new AlphaChunkManager GetChunkManager (int dim)
|
||||||
{
|
{
|
||||||
return GetChunkManagerVirt(dim) as AlphaChunkManager;
|
return GetChunkManagerVirt(dim) as AlphaChunkManager;
|
||||||
|
@ -95,7 +95,7 @@ namespace Substrate
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Saves the world's <see cref="Level"/> data, and any <see cref="Chunk"/> objects known to have unsaved changes.
|
/// Saves the world's <see cref="Level"/> data, and any <see cref="IChunk"/> objects known to have unsaved changes.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void Save ()
|
public void Save ()
|
||||||
{
|
{
|
||||||
|
|
|
@ -413,7 +413,7 @@ namespace Substrate
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Chunk : IChunk, INbtObject<Chunk>, ICopyable<Chunk>
|
public class AnvilChunk : IChunk, INbtObject<AnvilChunk>, ICopyable<AnvilChunk>
|
||||||
{
|
{
|
||||||
public static SchemaNodeCompound LevelSchema = new SchemaNodeCompound()
|
public static SchemaNodeCompound LevelSchema = new SchemaNodeCompound()
|
||||||
{
|
{
|
||||||
|
@ -466,7 +466,7 @@ namespace Substrate
|
||||||
private EntityCollection _entityManager;
|
private EntityCollection _entityManager;
|
||||||
|
|
||||||
|
|
||||||
private Chunk ()
|
private AnvilChunk ()
|
||||||
{
|
{
|
||||||
_sections = new AnvilSection[16];
|
_sections = new AnvilSection[16];
|
||||||
}
|
}
|
||||||
|
@ -502,9 +502,9 @@ namespace Substrate
|
||||||
set { _tree.Root["Level"].ToTagCompound()["TerrainPopulated"].ToTagByte().Data = (byte)(value ? 1 : 0); }
|
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._cx = x;
|
||||||
c._cz = z;
|
c._cz = z;
|
||||||
|
@ -513,16 +513,16 @@ namespace Substrate
|
||||||
return c;
|
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);
|
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);
|
return c.LoadTreeSafe(tree.Root);
|
||||||
}
|
}
|
||||||
|
@ -617,7 +617,7 @@ namespace Substrate
|
||||||
|
|
||||||
#region INbtObject<AnvilChunk> Members
|
#region INbtObject<AnvilChunk> Members
|
||||||
|
|
||||||
public Chunk LoadTree (TagNode tree)
|
public AnvilChunk LoadTree (TagNode tree)
|
||||||
{
|
{
|
||||||
TagNodeCompound ctree = tree as TagNodeCompound;
|
TagNodeCompound ctree = tree as TagNodeCompound;
|
||||||
if (ctree == null) {
|
if (ctree == null) {
|
||||||
|
@ -701,7 +701,7 @@ namespace Substrate
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Chunk LoadTreeSafe (TagNode tree)
|
public AnvilChunk LoadTreeSafe (TagNode tree)
|
||||||
{
|
{
|
||||||
if (!ValidateTree(tree)) {
|
if (!ValidateTree(tree)) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -740,9 +740,9 @@ namespace Substrate
|
||||||
|
|
||||||
#region ICopyable<AnvilChunk> Members
|
#region ICopyable<AnvilChunk> Members
|
||||||
|
|
||||||
public Chunk Copy ()
|
public AnvilChunk Copy ()
|
||||||
{
|
{
|
||||||
return Chunk.Create(_tree.Copy());
|
return AnvilChunk.Create(_tree.Copy());
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
392
SubstrateCS/Source/AnvilWorld.cs
Normal file
392
SubstrateCS/Source/AnvilWorld.cs
Normal file
|
@ -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;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents an Anvil-compatible (Release 1.2 or higher) Minecraft world.
|
||||||
|
/// </summary>
|
||||||
|
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<int, AnvilRegionManager> _regionMgrs;
|
||||||
|
private Dictionary<int, RegionChunkManager> _chunkMgrs;
|
||||||
|
private Dictionary<int, BlockManager> _blockMgrs;
|
||||||
|
|
||||||
|
private Dictionary<int, ChunkCache> _caches;
|
||||||
|
|
||||||
|
private PlayerManager _playerMan;
|
||||||
|
private BetaDataManager _dataMan;
|
||||||
|
|
||||||
|
private int _prefCacheSize = 256;
|
||||||
|
|
||||||
|
private AnvilWorld ()
|
||||||
|
{
|
||||||
|
_regionMgrs = new Dictionary<int, AnvilRegionManager>();
|
||||||
|
_chunkMgrs = new Dictionary<int, RegionChunkManager>();
|
||||||
|
_blockMgrs = new Dictionary<int, BlockManager>();
|
||||||
|
|
||||||
|
_caches = new Dictionary<int, ChunkCache>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <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="RegionChunkManager"/> 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="RegionChunkManager"/> 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="RegionChunkManager"/> for the default dimension.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>A <see cref="RegionChunkManager"/> tied to the default dimension in this world.</returns>
|
||||||
|
/// <remarks>Get a <see cref="RegionChunkManager"/> if you you need to work with easily-digestible, bounded chunks of blocks.</remarks>
|
||||||
|
public new RegionChunkManager GetChunkManager ()
|
||||||
|
{
|
||||||
|
return GetChunkManagerVirt(Dimension.DEFAULT) as RegionChunkManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a <see cref="RegionChunkManager"/> for the given dimension.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="dim">The id of the dimension to look up.</param>
|
||||||
|
/// <returns>A <see cref="RegionChunkManager"/> tied to the given dimension in this world.</returns>
|
||||||
|
/// <remarks>Get a <see cref="RegionChunkManager"/> if you you need to work with easily-digestible, bounded chunks of blocks.</remarks>
|
||||||
|
public new RegionChunkManager GetChunkManager (int dim)
|
||||||
|
{
|
||||||
|
return GetChunkManagerVirt(dim) as RegionChunkManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <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="RegionChunkManager"/> if you are interested in working with blocks.</remarks>
|
||||||
|
public AnvilRegionManager 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="RegionChunkManager"/> if you are interested in working with blocks.</remarks>
|
||||||
|
public AnvilRegionManager GetRegionManager (int dim)
|
||||||
|
{
|
||||||
|
AnvilRegionManager 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>
|
||||||
|
/// Gets a <see cref="BetaDataManager"/> for managing data resources, such as maps.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>A <see cref="BetaDataManager"/> for this world.</returns>
|
||||||
|
public new BetaDataManager GetDataManager ()
|
||||||
|
{
|
||||||
|
return GetDataManagerVirt() as BetaDataManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Saves the world's <see cref="Level"/> data, and any <see cref="IChunk"/> objects known to have unsaved changes.
|
||||||
|
/// </summary>
|
||||||
|
public void Save ()
|
||||||
|
{
|
||||||
|
_level.Save();
|
||||||
|
|
||||||
|
foreach (KeyValuePair<int, RegionChunkManager> cm in _chunkMgrs) {
|
||||||
|
cm.Value.Save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the <see cref="ChunkCache"/> currently managing chunks in the default dimension.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The <see cref="ChunkCache"/> for the default dimension, or null if the dimension was not found.</returns>
|
||||||
|
public ChunkCache GetChunkCache ()
|
||||||
|
{
|
||||||
|
return GetChunkCache(Dimension.DEFAULT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the <see cref="ChunkCache"/> currently managing chunks in the given dimension.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="dim">The id of a dimension to look up.</param>
|
||||||
|
/// <returns>The <see cref="ChunkCache"/> for the given dimension, or null if the dimension was not found.</returns>
|
||||||
|
public ChunkCache GetChunkCache (int dim)
|
||||||
|
{
|
||||||
|
if (_caches.ContainsKey(dim)) {
|
||||||
|
return _caches[dim];
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <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 new AnvilWorld Open (string path)
|
||||||
|
{
|
||||||
|
return new AnvilWorld().OpenWorld(path) as AnvilWorld;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <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>
|
||||||
|
/// <param name="cacheSize">The preferred cache size in chunks for each opened dimension in this world.</param>
|
||||||
|
/// <returns>A new <see cref="BetaWorld"/> object representing an existing world on disk.</returns>
|
||||||
|
public static AnvilWorld Open (string path, int cacheSize)
|
||||||
|
{
|
||||||
|
AnvilWorld world = new AnvilWorld().OpenWorld(path);
|
||||||
|
world._prefCacheSize = cacheSize;
|
||||||
|
|
||||||
|
return world;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <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 AnvilWorld Create (string path)
|
||||||
|
{
|
||||||
|
return new AnvilWorld().CreateWorld(path) as AnvilWorld;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <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>
|
||||||
|
/// <param name="cacheSize">The preferred cache size in chunks for each opened dimension in this world.</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 AnvilWorld Create (string path, int cacheSize)
|
||||||
|
{
|
||||||
|
AnvilWorld world = new AnvilWorld().CreateWorld(path);
|
||||||
|
world._prefCacheSize = cacheSize;
|
||||||
|
|
||||||
|
return world;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <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)
|
||||||
|
{
|
||||||
|
RegionChunkManager 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <exclude/>
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,7 +8,7 @@ namespace Substrate
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a Beta-compatible interface for globally managing chunks.
|
/// Represents a Beta-compatible interface for globally managing chunks.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class BetaChunkManager : IChunkManager, IEnumerable<ChunkRef>
|
public class RegionChunkManager : IChunkManager, IEnumerable<ChunkRef>
|
||||||
{
|
{
|
||||||
private const int REGION_XLEN = 32;
|
private const int REGION_XLEN = 32;
|
||||||
private const int REGION_ZLEN = 32;
|
private const int REGION_ZLEN = 32;
|
||||||
|
@ -19,26 +19,26 @@ namespace Substrate
|
||||||
private const int REGION_XMASK = 0x1F;
|
private const int REGION_XMASK = 0x1F;
|
||||||
private const int REGION_ZMASK = 0x1F;
|
private const int REGION_ZMASK = 0x1F;
|
||||||
|
|
||||||
private RegionManager _regionMan;
|
private IRegionManager _regionMan;
|
||||||
|
|
||||||
private ChunkCache _cache;
|
private ChunkCache _cache;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new <see cref="BetaChunkManager"/> instance given a backing <see cref="RegionManager"/> and <see cref="ChunkCache"/>.
|
/// Creates a new <see cref="RegionChunkManager"/> instance given a backing <see cref="RegionManager"/> and <see cref="ChunkCache"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="rm">A <see cref="RegionManager"/> exposing access to regions.</param>
|
/// <param name="rm">A <see cref="RegionManager"/> exposing access to regions.</param>
|
||||||
/// <param name="cache">A shared cache for storing chunks read in.</param>
|
/// <param name="cache">A shared cache for storing chunks read in.</param>
|
||||||
public BetaChunkManager (RegionManager rm, ChunkCache cache)
|
public RegionChunkManager (IRegionManager rm, ChunkCache cache)
|
||||||
{
|
{
|
||||||
_regionMan = rm;
|
_regionMan = rm;
|
||||||
_cache = cache;
|
_cache = cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new <see cref="BetaChunkManager"/> instance from another.
|
/// Creates a new <see cref="RegionChunkManager"/> instance from another.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="cm">A <see cref="BetaChunkManager"/> to get a <see cref="RegionManager"/> and <see cref="ChunkCache"/> from.</param>
|
/// <param name="cm">A <see cref="RegionChunkManager"/> to get a <see cref="RegionManager"/> and <see cref="ChunkCache"/> from.</param>
|
||||||
public BetaChunkManager (BetaChunkManager cm)
|
public RegionChunkManager (RegionChunkManager cm)
|
||||||
{
|
{
|
||||||
_regionMan = cm._regionMan;
|
_regionMan = cm._regionMan;
|
||||||
_cache = cm._cache;
|
_cache = cm._cache;
|
||||||
|
@ -47,7 +47,7 @@ namespace Substrate
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the <see cref="RegionManager"/> backing this manager.
|
/// Gets the <see cref="RegionManager"/> backing this manager.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public RegionManager RegionManager
|
public IRegionManager RegionManager
|
||||||
{
|
{
|
||||||
get { return _regionMan; }
|
get { return _regionMan; }
|
||||||
}
|
}
|
||||||
|
@ -79,9 +79,9 @@ namespace Substrate
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
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) {
|
if (r == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -92,7 +92,7 @@ namespace Substrate
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public ChunkRef GetChunkRef (int cx, int cz)
|
public ChunkRef GetChunkRef (int cx, int cz)
|
||||||
{
|
{
|
||||||
Region r = GetRegion(cx, cz);
|
IRegion r = GetRegion(cx, cz);
|
||||||
if (r == null) {
|
if (r == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -103,7 +103,7 @@ namespace Substrate
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public bool ChunkExists (int cx, int cz)
|
public bool ChunkExists (int cx, int cz)
|
||||||
{
|
{
|
||||||
Region r = GetRegion(cx, cz);
|
IRegion r = GetRegion(cx, cz);
|
||||||
if (r == null) {
|
if (r == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -114,7 +114,7 @@ namespace Substrate
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public ChunkRef CreateChunk (int cx, int cz)
|
public ChunkRef CreateChunk (int cx, int cz)
|
||||||
{
|
{
|
||||||
Region r = GetRegion(cx, cz);
|
IRegion r = GetRegion(cx, cz);
|
||||||
if (r == null) {
|
if (r == null) {
|
||||||
int rx = cx >> REGION_XLOG;
|
int rx = cx >> REGION_XLOG;
|
||||||
int rz = cz >> REGION_ZLOG;
|
int rz = cz >> REGION_ZLOG;
|
||||||
|
@ -125,9 +125,9 @@ namespace Substrate
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
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) {
|
if (r == null) {
|
||||||
int rx = cx >> REGION_XLOG;
|
int rx = cx >> REGION_XLOG;
|
||||||
int rz = cz >> REGION_ZLOG;
|
int rz = cz >> REGION_ZLOG;
|
||||||
|
@ -150,7 +150,7 @@ namespace Substrate
|
||||||
while (en.MoveNext()) {
|
while (en.MoveNext()) {
|
||||||
ChunkRef chunk = en.Current;
|
ChunkRef chunk = en.Current;
|
||||||
|
|
||||||
Region r = GetRegion(chunk.X, chunk.Z);
|
IRegion r = GetRegion(chunk.X, chunk.Z);
|
||||||
if (r == null) {
|
if (r == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -164,9 +164,9 @@ namespace Substrate
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
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) {
|
if (r == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -177,7 +177,7 @@ namespace Substrate
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public bool DeleteChunk (int cx, int cz)
|
public bool DeleteChunk (int cx, int cz)
|
||||||
{
|
{
|
||||||
Region r = GetRegion(cx, cz);
|
IRegion r = GetRegion(cx, cz);
|
||||||
if (r == null) {
|
if (r == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -211,19 +211,19 @@ namespace Substrate
|
||||||
/// <returns>A <see cref="ChunkRef"/> for the destination chunk.</returns>
|
/// <returns>A <see cref="ChunkRef"/> for the destination chunk.</returns>
|
||||||
public ChunkRef CopyChunk (int src_cx, int src_cz, int dst_cx, int dst_cz)
|
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) {
|
if (src_r == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Region dst_r = GetRegion(dst_cx, dst_cz);
|
IRegion dst_r = GetRegion(dst_cx, dst_cz);
|
||||||
if (dst_r == null) {
|
if (dst_r == null) {
|
||||||
int rx = dst_cx >> REGION_XLOG;
|
int rx = dst_cx >> REGION_XLOG;
|
||||||
int rz = dst_cz >> REGION_ZLOG;
|
int rz = dst_cz >> REGION_ZLOG;
|
||||||
dst_r = _regionMan.CreateRegion(rx, rz);
|
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);
|
c.SetLocation(dst_cx, dst_cz);
|
||||||
|
|
||||||
dst_r.SaveChunk(c);
|
dst_r.SaveChunk(c);
|
||||||
|
@ -293,7 +293,7 @@ namespace Substrate
|
||||||
/// <remarks>The value returned may differ from any timestamp stored in the chunk data itself.</remarks>
|
/// <remarks>The value returned may differ from any timestamp stored in the chunk data itself.</remarks>
|
||||||
public int GetChunkTimestamp (int cx, int cz)
|
public int GetChunkTimestamp (int cx, int cz)
|
||||||
{
|
{
|
||||||
Region r = GetRegion(cx, cz);
|
IRegion r = GetRegion(cx, cz);
|
||||||
if (r == null) {
|
if (r == null) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -311,7 +311,7 @@ namespace Substrate
|
||||||
/// any timestamp information in the chunk data itself.</remarks>
|
/// any timestamp information in the chunk data itself.</remarks>
|
||||||
public void SetChunkTimestamp (int cx, int cz, int timestamp)
|
public void SetChunkTimestamp (int cx, int cz, int timestamp)
|
||||||
{
|
{
|
||||||
Region r = GetRegion(cx, cz);
|
IRegion r = GetRegion(cx, cz);
|
||||||
if (r == null) {
|
if (r == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -319,14 +319,14 @@ namespace Substrate
|
||||||
r.SetChunkTimestamp(cx & REGION_XMASK, cz & REGION_ZMASK, timestamp);
|
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 cx = r.X * REGION_XLEN + lcx;
|
||||||
int cz = r.Z * REGION_ZLEN + lcz;
|
int cz = r.Z * REGION_ZLEN + lcz;
|
||||||
return GetChunkRef(cx, cz);
|
return GetChunkRef(cx, cz);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Region GetRegion (int cx, int cz)
|
private IRegion GetRegion (int cx, int cz)
|
||||||
{
|
{
|
||||||
cx >>= REGION_XLOG;
|
cx >>= REGION_XLOG;
|
||||||
cz >>= REGION_ZLOG;
|
cz >>= REGION_ZLOG;
|
||||||
|
@ -361,16 +361,16 @@ namespace Substrate
|
||||||
|
|
||||||
private class Enumerator : IEnumerator<ChunkRef>
|
private class Enumerator : IEnumerator<ChunkRef>
|
||||||
{
|
{
|
||||||
private BetaChunkManager _cm;
|
private RegionChunkManager _cm;
|
||||||
|
|
||||||
private IEnumerator<Region> _enum;
|
private IEnumerator<IRegion> _enum;
|
||||||
private Region _region;
|
private IRegion _region;
|
||||||
private ChunkRef _chunk;
|
private ChunkRef _chunk;
|
||||||
|
|
||||||
private int _x = 0;
|
private int _x = 0;
|
||||||
private int _z = -1;
|
private int _z = -1;
|
||||||
|
|
||||||
public Enumerator (BetaChunkManager cm)
|
public Enumerator (RegionChunkManager cm)
|
||||||
{
|
{
|
||||||
_cm = cm;
|
_cm = cm;
|
||||||
_enum = _cm.RegionManager.GetEnumerator();
|
_enum = _cm.RegionManager.GetEnumerator();
|
||||||
|
@ -385,7 +385,7 @@ namespace Substrate
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
while (true) {
|
while (true) {
|
||||||
if (_x >= BetaChunkManager.REGION_XLEN) {
|
if (_x >= RegionChunkManager.REGION_XLEN) {
|
||||||
if (!_enum.MoveNext()) {
|
if (!_enum.MoveNext()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -403,8 +403,8 @@ namespace Substrate
|
||||||
|
|
||||||
protected bool MoveNextInRegion ()
|
protected bool MoveNextInRegion ()
|
||||||
{
|
{
|
||||||
for (; _x < BetaChunkManager.REGION_XLEN; _x++) {
|
for (; _x < RegionChunkManager.REGION_XLEN; _x++) {
|
||||||
for (_z++; _z < BetaChunkManager.REGION_ZLEN; _z++) {
|
for (_z++; _z < RegionChunkManager.REGION_ZLEN; _z++) {
|
||||||
if (_region.ChunkExists(_x, _z)) {
|
if (_region.ChunkExists(_x, _z)) {
|
||||||
goto FoundNext;
|
goto FoundNext;
|
||||||
}
|
}
|
||||||
|
@ -414,7 +414,7 @@ namespace Substrate
|
||||||
|
|
||||||
FoundNext:
|
FoundNext:
|
||||||
|
|
||||||
return (_x < BetaChunkManager.REGION_XLEN);
|
return (_x < RegionChunkManager.REGION_XLEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Reset ()
|
public void Reset ()
|
||||||
|
@ -450,7 +450,7 @@ namespace Substrate
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (_x >= BetaChunkManager.REGION_XLEN) {
|
if (_x >= RegionChunkManager.REGION_XLEN) {
|
||||||
throw new InvalidOperationException();
|
throw new InvalidOperationException();
|
||||||
}
|
}
|
||||||
return _chunk;
|
return _chunk;
|
||||||
|
|
|
@ -22,8 +22,8 @@ namespace Substrate
|
||||||
|
|
||||||
private Level _level;
|
private Level _level;
|
||||||
|
|
||||||
private Dictionary<int, RegionManager> _regionMgrs;
|
private Dictionary<int, BetaRegionManager> _regionMgrs;
|
||||||
private Dictionary<int, BetaChunkManager> _chunkMgrs;
|
private Dictionary<int, RegionChunkManager> _chunkMgrs;
|
||||||
private Dictionary<int, BlockManager> _blockMgrs;
|
private Dictionary<int, BlockManager> _blockMgrs;
|
||||||
|
|
||||||
private Dictionary<int, ChunkCache> _caches;
|
private Dictionary<int, ChunkCache> _caches;
|
||||||
|
@ -35,8 +35,8 @@ namespace Substrate
|
||||||
|
|
||||||
private BetaWorld ()
|
private BetaWorld ()
|
||||||
{
|
{
|
||||||
_regionMgrs = new Dictionary<int, RegionManager>();
|
_regionMgrs = new Dictionary<int, BetaRegionManager>();
|
||||||
_chunkMgrs = new Dictionary<int, BetaChunkManager>();
|
_chunkMgrs = new Dictionary<int, RegionChunkManager>();
|
||||||
_blockMgrs = new Dictionary<int, BlockManager>();
|
_blockMgrs = new Dictionary<int, BlockManager>();
|
||||||
|
|
||||||
_caches = new Dictionary<int, ChunkCache>();
|
_caches = new Dictionary<int, ChunkCache>();
|
||||||
|
@ -56,7 +56,7 @@ namespace Substrate
|
||||||
/// <returns>A <see cref="BlockManager"/> tied to the default dimension in this world.</returns>
|
/// <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
|
/// <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
|
/// any higher-level organizational divisions. If your task is going to be heavily performance-bound, consider getting a
|
||||||
/// <see cref="BetaChunkManager"/> instead and working with blocks on a chunk-local level.</remarks>
|
/// <see cref="RegionChunkManager"/> instead and working with blocks on a chunk-local level.</remarks>
|
||||||
public new BlockManager GetBlockManager ()
|
public new BlockManager GetBlockManager ()
|
||||||
{
|
{
|
||||||
return GetBlockManagerVirt(Dimension.DEFAULT) as BlockManager;
|
return GetBlockManagerVirt(Dimension.DEFAULT) as BlockManager;
|
||||||
|
@ -69,31 +69,31 @@ namespace Substrate
|
||||||
/// <returns>A <see cref="BlockManager"/> tied to the given dimension in this world.</returns>
|
/// <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
|
/// <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
|
/// any higher-level organizational divisions. If your task is going to be heavily performance-bound, consider getting a
|
||||||
/// <see cref="BetaChunkManager"/> instead and working with blocks on a chunk-local level.</remarks>
|
/// <see cref="RegionChunkManager"/> instead and working with blocks on a chunk-local level.</remarks>
|
||||||
public new BlockManager GetBlockManager (int dim)
|
public new BlockManager GetBlockManager (int dim)
|
||||||
{
|
{
|
||||||
return GetBlockManagerVirt(dim) as BlockManager;
|
return GetBlockManagerVirt(dim) as BlockManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a <see cref="BetaChunkManager"/> for the default dimension.
|
/// Gets a <see cref="RegionChunkManager"/> for the default dimension.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>A <see cref="BetaChunkManager"/> tied to the default dimension in this world.</returns>
|
/// <returns>A <see cref="RegionChunkManager"/> tied to the default dimension in this world.</returns>
|
||||||
/// <remarks>Get a <see cref="BetaChunkManager"/> if you you need to work with easily-digestible, bounded chunks of blocks.</remarks>
|
/// <remarks>Get a <see cref="RegionChunkManager"/> if you you need to work with easily-digestible, bounded chunks of blocks.</remarks>
|
||||||
public new BetaChunkManager GetChunkManager ()
|
public new RegionChunkManager GetChunkManager ()
|
||||||
{
|
{
|
||||||
return GetChunkManagerVirt(Dimension.DEFAULT) as BetaChunkManager;
|
return GetChunkManagerVirt(Dimension.DEFAULT) as RegionChunkManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a <see cref="BetaChunkManager"/> for the given dimension.
|
/// Gets a <see cref="RegionChunkManager"/> for the given dimension.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="dim">The id of the dimension to look up.</param>
|
/// <param name="dim">The id of the dimension to look up.</param>
|
||||||
/// <returns>A <see cref="BetaChunkManager"/> tied to the given dimension in this world.</returns>
|
/// <returns>A <see cref="RegionChunkManager"/> tied to the given dimension in this world.</returns>
|
||||||
/// <remarks>Get a <see cref="BetaChunkManager"/> if you you need to work with easily-digestible, bounded chunks of blocks.</remarks>
|
/// <remarks>Get a <see cref="RegionChunkManager"/> if you you need to work with easily-digestible, bounded chunks of blocks.</remarks>
|
||||||
public new BetaChunkManager GetChunkManager (int dim)
|
public new RegionChunkManager GetChunkManager (int dim)
|
||||||
{
|
{
|
||||||
return GetChunkManagerVirt(dim) as BetaChunkManager;
|
return GetChunkManagerVirt(dim) as RegionChunkManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -101,8 +101,8 @@ namespace Substrate
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>A <see cref="RegionManager"/> tied to the defaul dimension in this world.</returns>
|
/// <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.
|
/// <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="BetaChunkManager"/> if you are interested in working with blocks.</remarks>
|
/// Consider using the <see cref="RegionChunkManager"/> if you are interested in working with blocks.</remarks>
|
||||||
public RegionManager GetRegionManager ()
|
public BetaRegionManager GetRegionManager ()
|
||||||
{
|
{
|
||||||
return GetRegionManager(Dimension.DEFAULT);
|
return GetRegionManager(Dimension.DEFAULT);
|
||||||
}
|
}
|
||||||
|
@ -113,10 +113,10 @@ namespace Substrate
|
||||||
/// <param name="dim">The id of the dimension to look up.</param>
|
/// <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>
|
/// <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.
|
/// <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="BetaChunkManager"/> if you are interested in working with blocks.</remarks>
|
/// Consider using the <see cref="RegionChunkManager"/> if you are interested in working with blocks.</remarks>
|
||||||
public RegionManager GetRegionManager (int dim)
|
public BetaRegionManager GetRegionManager (int dim)
|
||||||
{
|
{
|
||||||
RegionManager rm;
|
BetaRegionManager rm;
|
||||||
if (_regionMgrs.TryGetValue(dim, out rm)) {
|
if (_regionMgrs.TryGetValue(dim, out rm)) {
|
||||||
return rm;
|
return rm;
|
||||||
}
|
}
|
||||||
|
@ -145,13 +145,13 @@ namespace Substrate
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Saves the world's <see cref="Level"/> data, and any <see cref="Chunk"/> objects known to have unsaved changes.
|
/// Saves the world's <see cref="Level"/> data, and any <see cref="IChunk"/> objects known to have unsaved changes.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void Save ()
|
public void Save ()
|
||||||
{
|
{
|
||||||
_level.Save();
|
_level.Save();
|
||||||
|
|
||||||
foreach (KeyValuePair<int, BetaChunkManager> cm in _chunkMgrs) {
|
foreach (KeyValuePair<int, RegionChunkManager> cm in _chunkMgrs) {
|
||||||
cm.Value.Save();
|
cm.Value.Save();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -245,7 +245,7 @@ namespace Substrate
|
||||||
/// <exclude/>
|
/// <exclude/>
|
||||||
protected override IChunkManager GetChunkManagerVirt (int dim)
|
protected override IChunkManager GetChunkManagerVirt (int dim)
|
||||||
{
|
{
|
||||||
BetaChunkManager rm;
|
RegionChunkManager rm;
|
||||||
if (_chunkMgrs.TryGetValue(dim, out rm)) {
|
if (_chunkMgrs.TryGetValue(dim, out rm)) {
|
||||||
return rm;
|
return rm;
|
||||||
}
|
}
|
||||||
|
@ -295,8 +295,8 @@ namespace Substrate
|
||||||
|
|
||||||
ChunkCache cc = new ChunkCache(_prefCacheSize);
|
ChunkCache cc = new ChunkCache(_prefCacheSize);
|
||||||
|
|
||||||
RegionManager rm = new RegionManager(path, cc);
|
BetaRegionManager rm = new BetaRegionManager(path, cc);
|
||||||
BetaChunkManager cm = new BetaChunkManager(rm, cc);
|
RegionChunkManager cm = new RegionChunkManager(rm, cc);
|
||||||
BlockManager bm = new BlockManager(cm);
|
BlockManager bm = new BlockManager(cm);
|
||||||
|
|
||||||
_regionMgrs[dim] = rm;
|
_regionMgrs[dim] = rm;
|
||||||
|
@ -378,7 +378,7 @@ namespace Substrate
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (world.Level.Version < 19132) {
|
if (world.Level.Version != 19132) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -68,7 +68,7 @@ namespace Substrate
|
||||||
{
|
{
|
||||||
chunkMan = cm;
|
chunkMan = cm;
|
||||||
|
|
||||||
Chunk c = Chunk.Create(0, 0);
|
IChunk c = AlphaChunk.Create(0, 0);
|
||||||
|
|
||||||
chunkXDim = c.Blocks.XDim;
|
chunkXDim = c.Blocks.XDim;
|
||||||
chunkYDim = c.Blocks.YDim;
|
chunkYDim = c.Blocks.YDim;
|
||||||
|
|
|
@ -14,7 +14,7 @@ namespace Substrate
|
||||||
public class ChunkRef : IChunk
|
public class ChunkRef : IChunk
|
||||||
{
|
{
|
||||||
private IChunkContainer _container;
|
private IChunkContainer _container;
|
||||||
private Chunk _chunk;
|
private IChunk _chunk;
|
||||||
|
|
||||||
private AlphaBlockCollection _blocks;
|
private AlphaBlockCollection _blocks;
|
||||||
private EntityCollection _entities;
|
private EntityCollection _entities;
|
||||||
|
@ -167,6 +167,15 @@ namespace Substrate
|
||||||
return true;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a ChunkRef to the chunk positioned immediately north (X - 1).
|
/// Gets a ChunkRef to the chunk positioned immediately north (X - 1).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -207,10 +216,10 @@ namespace Substrate
|
||||||
/// Returns a deep copy of the physical chunk underlying the ChunkRef.
|
/// Returns a deep copy of the physical chunk underlying the ChunkRef.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>A copy of the physical Chunk object.</returns>
|
/// <returns>A copy of the physical Chunk object.</returns>
|
||||||
public Chunk GetChunkCopy ()
|
/*public Chunk GetChunkCopy ()
|
||||||
{
|
{
|
||||||
return GetChunk().Copy();
|
return GetChunk().Copy();
|
||||||
}
|
}*/
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns the reference of the physical chunk underlying the ChunkRef, and releases the reference from itself.
|
/// 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.
|
/// to modify them without intending to permanently store the changes.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
/// <returns>The physical Chunk object underlying the ChunkRef</returns>
|
/// <returns>The physical Chunk object underlying the ChunkRef</returns>
|
||||||
public Chunk GetChunkRef ()
|
public IChunk GetChunkRef ()
|
||||||
{
|
{
|
||||||
Chunk chunk = GetChunk();
|
IChunk chunk = GetChunk();
|
||||||
_chunk = null;
|
_chunk = null;
|
||||||
_dirty = false;
|
_dirty = false;
|
||||||
|
|
||||||
|
@ -240,7 +249,7 @@ namespace Substrate
|
||||||
/// move a physical chunk between locations within a container (by taking the reference from another ChunkRef).
|
/// move a physical chunk between locations within a container (by taking the reference from another ChunkRef).
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
/// <param name="chunk">Physical Chunk to store into the location represented by this ChunkRef.</param>
|
/// <param name="chunk">Physical Chunk to store into the location represented by this ChunkRef.</param>
|
||||||
public void SetChunkRef (Chunk chunk)
|
public void SetChunkRef (IChunk chunk)
|
||||||
{
|
{
|
||||||
_chunk = chunk;
|
_chunk = chunk;
|
||||||
_chunk.SetLocation(X, Z);
|
_chunk.SetLocation(X, Z);
|
||||||
|
@ -251,7 +260,7 @@ namespace Substrate
|
||||||
/// Gets an internal Chunk reference from cache or queries the container for it.
|
/// Gets an internal Chunk reference from cache or queries the container for it.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>The ChunkRef's underlying Chunk.</returns>
|
/// <returns>The ChunkRef's underlying Chunk.</returns>
|
||||||
private Chunk GetChunk ()
|
private IChunk GetChunk ()
|
||||||
{
|
{
|
||||||
if (_chunk == null) {
|
if (_chunk == null) {
|
||||||
_chunk = _container.GetChunk(_cx, _cz);
|
_chunk = _container.GetChunk(_cx, _cz);
|
||||||
|
|
|
@ -36,6 +36,8 @@ namespace Substrate.Core
|
||||||
/// <remarks>Terrain features include ores, water and lava sources, dungeons, trees, flowers, etc.</remarks>
|
/// <remarks>Terrain features include ores, water and lava sources, dungeons, trees, flowers, etc.</remarks>
|
||||||
bool IsTerrainPopulated { get; set; }
|
bool IsTerrainPopulated { get; set; }
|
||||||
|
|
||||||
|
void SetLocation (int x, int z);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Writes out the chunk's data to an output stream.
|
/// Writes out the chunk's data to an output stream.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -90,19 +92,19 @@ namespace Substrate.Core
|
||||||
int ChunkLocalZ (int cz);
|
int ChunkLocalZ (int cz);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets an unwrapped <see cref="Chunk"/> object for the given container-local coordinates.
|
/// Gets an unwrapped <see cref="IChunk"/> object for the given container-local coordinates.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="cx">The container-local X-coordinate of a chunk.</param>
|
/// <param name="cx">The container-local X-coordinate of a chunk.</param>
|
||||||
/// <param name="cz">The container-local Z-coordinate of a chunk.</param>
|
/// <param name="cz">The container-local Z-coordinate of a chunk.</param>
|
||||||
/// <returns>A <see cref="Chunk"/> for the given coordinates, or null if no chunk exists at those coordinates.</returns>
|
/// <returns>A <see cref="IChunk"/> for the given coordinates, or null if no chunk exists at those coordinates.</returns>
|
||||||
Chunk GetChunk (int cx, int cz);
|
IChunk GetChunk (int cx, int cz);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a <see cref="ChunkRef"/> binding a chunk to this container for the given container-local coordinates.
|
/// Gets a <see cref="ChunkRef"/> binding a chunk to this container for the given container-local coordinates.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="cx">The container-local X-coordinate of a chunk.</param>
|
/// <param name="cx">The container-local X-coordinate of a chunk.</param>
|
||||||
/// <param name="cz">The container-local Z-coordinate of a chunk.</param>
|
/// <param name="cz">The container-local Z-coordinate of a chunk.</param>
|
||||||
/// <returns>A <see cref="ChunkRef"/> for the given coordinates binding a <see cref="Chunk"/> to this container, or null if
|
/// <returns>A <see cref="ChunkRef"/> for the given coordinates binding a <see cref="IChunk"/> to this container, or null if
|
||||||
/// no chunk exists at the given coordinates.</returns>
|
/// no chunk exists at the given coordinates.</returns>
|
||||||
ChunkRef GetChunkRef (int cx, int cz);
|
ChunkRef GetChunkRef (int cx, int cz);
|
||||||
|
|
||||||
|
@ -117,19 +119,19 @@ namespace Substrate.Core
|
||||||
ChunkRef CreateChunk (int cx, int cz);
|
ChunkRef CreateChunk (int cx, int cz);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Saves an unwrapped <see cref="Chunk"/> to the container at the given container-local coordinates.
|
/// Saves an unwrapped <see cref="IChunk"/> to the container at the given container-local coordinates.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="cx">The container-local X-coordinate to save the chunk to.</param>
|
/// <param name="cx">The container-local X-coordinate to save the chunk to.</param>
|
||||||
/// <param name="cz">The container-local Z-coordinate to save the chunk to.</param>
|
/// <param name="cz">The container-local Z-coordinate to save the chunk to.</param>
|
||||||
/// <param name="chunk">The <see cref="Chunk"/> to save at the given coordinates.</param>
|
/// <param name="chunk">The <see cref="IChunk"/> to save at the given coordinates.</param>
|
||||||
/// <returns>A <see cref="ChunkRef"/> binding <paramref name="chunk"/> to this container at the given location.</returns>
|
/// <returns>A <see cref="ChunkRef"/> binding <paramref name="chunk"/> to this container at the given location.</returns>
|
||||||
/// <remarks><para>The <see cref="Chunk"/> argument will be updated to reflect new global coordinates corresponding to
|
/// <remarks><para>The <see cref="IChunk"/> 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 <see cref="ChunkRef"/>
|
/// the given location in this container. It is up to the developer to ensure that no competing <see cref="ChunkRef"/>
|
||||||
/// has a handle to the <see cref="Chunk"/> argument, or an inconsistency could develop where the chunk held by the
|
/// has a handle to the <see cref="IChunk"/> argument, or an inconsistency could develop where the chunk held by the
|
||||||
/// other <see cref="ChunkRef"/> is written to the underlying data store with invalid coordinates.</para>
|
/// other <see cref="ChunkRef"/> is written to the underlying data store with invalid coordinates.</para>
|
||||||
/// <para>The <see cref="ChunkRef"/> specification is designed to avoid this situation from occuring, but
|
/// <para>The <see cref="ChunkRef"/> specification is designed to avoid this situation from occuring, but
|
||||||
/// class hierarchy extensions could violate these safeguards.</para></remarks>
|
/// class hierarchy extensions could violate these safeguards.</para></remarks>
|
||||||
ChunkRef SetChunk (int cx, int cz, Chunk chunk);
|
ChunkRef SetChunk (int cx, int cz, IChunk chunk);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Checks if a chunk exists at the given container-local coordinates.
|
/// 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
|
// TODO: Check that this doesn't violate borders
|
||||||
/// <exclude/>
|
/// <exclude/>
|
||||||
bool SaveChunk (Chunk chunk);
|
bool SaveChunk (IChunk chunk);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Checks if this container supports delegating an action on out-of-bounds coordinates to another container.
|
/// Checks if this container supports delegating an action on out-of-bounds coordinates to another container.
|
||||||
|
|
|
@ -4,17 +4,43 @@ using System.Text;
|
||||||
|
|
||||||
namespace Substrate.Core
|
namespace Substrate.Core
|
||||||
{
|
{
|
||||||
|
|
||||||
public interface IRegionContainer
|
public interface IRegionContainer
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Determines if a region exists at the given coordinates.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="rx">The global X-coordinate of a region.</param>
|
||||||
|
/// <param name="rz">The global Z-coordinate of a region.</param>
|
||||||
|
/// <returns>True if a region exists at the given global region coordinates; false otherwise.</returns>
|
||||||
bool RegionExists (int rx, int rz);
|
bool RegionExists (int rx, int rz);
|
||||||
|
|
||||||
Region GetRegion (int rx, int rz);
|
/// <summary>
|
||||||
Region CreateRegion (int rx, int rz);
|
/// Gets an <see cref="IRegion"/> for the given region filename.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="filename">The filename of the region to get.</param>
|
||||||
|
/// <returns>A <see cref="IRegion"/> corresponding to the coordinates encoded in the filename.</returns>
|
||||||
|
IRegion GetRegion (int rx, int rz);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new empty region at the given coordinates, if no region exists.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="rx">The global X-coordinate of a region.</param>
|
||||||
|
/// <param name="rz">The global Z-coordinate of a region.</param>
|
||||||
|
/// <returns>A new empty <see cref="IRegion"/> object for the given coordinates, or an existing <see cref="IRegion"/> if one exists.</returns>
|
||||||
|
IRegion CreateRegion (int rx, int rz);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Deletes a region at the given coordinates.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="rx">The global X-coordinate of a region.</param>
|
||||||
|
/// <param name="rz">The global Z-coordinate of a region.</param>
|
||||||
|
/// <returns>True if a region was deleted; false otherwise.</returns>
|
||||||
bool DeleteRegion (int rx, int rz);
|
bool DeleteRegion (int rx, int rz);
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface IRegionManager : IRegionContainer, IEnumerable<Region>
|
public interface IRegionManager : IRegionContainer, IEnumerable<IRegion>
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -89,7 +89,7 @@ namespace Substrate
|
||||||
/// <param name="ent">The <see cref="TypedEntity"/> object to add.</param>
|
/// <param name="ent">The <see cref="TypedEntity"/> object to add.</param>
|
||||||
/// <remarks>It is up to the developer to ensure that the <see cref="TypedEntity"/> being added to the collection has a position that
|
/// <remarks>It is up to the developer to ensure that the <see cref="TypedEntity"/> being added to the collection has a position that
|
||||||
/// is within acceptable range of the collection. <see cref="EntityCollection"/> transparently back other objects such as
|
/// is within acceptable range of the collection. <see cref="EntityCollection"/> transparently back other objects such as
|
||||||
/// <see cref="Chunk"/> objects, which have a well-defined position in global space. The <see cref="EntityCollection"/> itself has
|
/// <see cref="IChunk"/> objects, which have a well-defined position in global space. The <see cref="EntityCollection"/> itself has
|
||||||
/// no concept of position and will not enforce constraints on the positions of <see cref="TypedEntity"/> objects being added.</remarks>
|
/// no concept of position and will not enforce constraints on the positions of <see cref="TypedEntity"/> objects being added.</remarks>
|
||||||
public void Add (TypedEntity ent)
|
public void Add (TypedEntity ent)
|
||||||
{
|
{
|
||||||
|
|
|
@ -176,8 +176,9 @@ namespace Substrate
|
||||||
|
|
||||||
static NbtWorld ()
|
static NbtWorld ()
|
||||||
{
|
{
|
||||||
ResolveOpen += AlphaWorld.OnResolveOpen;
|
ResolveOpen += AnvilWorld.OnResolveOpen;
|
||||||
ResolveOpen += BetaWorld.OnResolveOpen;
|
ResolveOpen += BetaWorld.OnResolveOpen;
|
||||||
|
ResolveOpen += AlphaWorld.OnResolveOpen;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,29 +8,213 @@ using Substrate.Core;
|
||||||
|
|
||||||
namespace Substrate
|
namespace Substrate
|
||||||
{
|
{
|
||||||
|
public interface IRegion : IChunkContainer
|
||||||
|
{
|
||||||
|
int X { get; }
|
||||||
|
|
||||||
|
int Z { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the appropriate filename for this region.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The filename of the region with encoded coordinates.</returns>
|
||||||
|
string GetFileName ();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the full path of the region's backing file.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Gets the path of the region's file based on the <see cref="IRegionManager"/>'s region path and the region's on filename.</returns>
|
||||||
|
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);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new chunk at the given local coordinates relative to this region and returns a new <see cref="ChunkRef"/> for it.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="lcx">The local X-coordinate of a chunk relative to this region.</param>
|
||||||
|
/// <param name="lcz">The local Z-coordinate of a chunk relative to this region.</param>
|
||||||
|
/// <returns>A <see cref="ChunkRef"/> for the newly created chunk.</returns>
|
||||||
|
/// <remarks>If the local coordinates are out of bounds for this region, the action will be forwarded to the correct region
|
||||||
|
/// transparently.</remarks>
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inherits />
|
||||||
|
public string GetFileName ()
|
||||||
|
{
|
||||||
|
return "r." + _rx + "." + _rz + ".mcr";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inherits />
|
||||||
|
public string GetFilePath ()
|
||||||
|
{
|
||||||
|
return System.IO.Path.Combine(_regionMan.GetRegionPath(), GetFileName());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Tests if the given filename conforms to the general naming pattern for any region.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="filename">The filename to test.</param>
|
||||||
|
/// <returns>True if the filename is a valid region name; false if it does not conform to the pattern.</returns>
|
||||||
|
public static bool TestFileName (string filename)
|
||||||
|
{
|
||||||
|
Match match = _namePattern.Match(filename);
|
||||||
|
if (!match.Success) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Parses the given filename to extract encoded region coordinates.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="filename">The region filename to parse.</param>
|
||||||
|
/// <param name="x">This parameter will contain the X-coordinate of a region.</param>
|
||||||
|
/// <param name="z">This parameter will contain the Z-coordinate of a region.</param>
|
||||||
|
/// <returns>True if the filename could be correctly parse; false otherwise.</returns>
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inherits />
|
||||||
|
public string GetFileName ()
|
||||||
|
{
|
||||||
|
return "r." + _rx + "." + _rz + ".mcr";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inherits />
|
||||||
|
public string GetFilePath ()
|
||||||
|
{
|
||||||
|
return System.IO.Path.Combine(_regionMan.GetRegionPath(), GetFileName());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Tests if the given filename conforms to the general naming pattern for any region.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="filename">The filename to test.</param>
|
||||||
|
/// <returns>True if the filename is a valid region name; false if it does not conform to the pattern.</returns>
|
||||||
|
public static bool TestFileName (string filename)
|
||||||
|
{
|
||||||
|
Match match = _namePattern.Match(filename);
|
||||||
|
if (!match.Success) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Parses the given filename to extract encoded region coordinates.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="filename">The region filename to parse.</param>
|
||||||
|
/// <param name="x">This parameter will contain the X-coordinate of a region.</param>
|
||||||
|
/// <param name="z">This parameter will contain the Z-coordinate of a region.</param>
|
||||||
|
/// <returns>True if the filename could be correctly parse; false otherwise.</returns>
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a single region containing 32x32 chunks.
|
/// Represents a single region containing 32x32 chunks.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class Region : IDisposable, IChunkContainer
|
public abstract class Region : IDisposable, IRegion
|
||||||
{
|
{
|
||||||
private const int XDIM = 32;
|
protected const int XDIM = 32;
|
||||||
private const int ZDIM = 32;
|
protected const int ZDIM = 32;
|
||||||
private const int XMASK = XDIM - 1;
|
protected const int XMASK = XDIM - 1;
|
||||||
private const int ZMASK = ZDIM - 1;
|
protected const int ZMASK = ZDIM - 1;
|
||||||
private const int XLOG = 5;
|
protected const int XLOG = 5;
|
||||||
private const int ZLOG = 5;
|
protected const int ZLOG = 5;
|
||||||
|
|
||||||
private int _rx;
|
protected int _rx;
|
||||||
private int _rz;
|
protected int _rz;
|
||||||
private bool _disposed = false;
|
private bool _disposed = false;
|
||||||
|
|
||||||
private RegionManager _regionMan;
|
protected RegionManager _regionMan;
|
||||||
|
|
||||||
private static Regex _namePattern = new Regex("r\\.(-?[0-9]+)\\.(-?[0-9]+)\\.mca$");
|
private static Regex _namePattern = new Regex("r\\.(-?[0-9]+)\\.(-?[0-9]+)\\.mca$");
|
||||||
|
|
||||||
private WeakReference _regionFile;
|
private WeakReference _regionFile;
|
||||||
|
|
||||||
private ChunkCache _cache;
|
protected ChunkCache _cache;
|
||||||
|
|
||||||
|
protected abstract IChunk CreateChunkCore (int cx, int cz);
|
||||||
|
|
||||||
|
protected abstract IChunk CreateChunkVerifiedCore (NbtTree tree);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the global X-coordinate of the region.
|
/// Gets the global X-coordinate of the region.
|
||||||
|
@ -227,7 +411,7 @@ namespace Substrate
|
||||||
public NbtTree GetChunkTree (int lcx, int lcz)
|
public NbtTree GetChunkTree (int lcx, int lcz)
|
||||||
{
|
{
|
||||||
if (!LocalBoundsCheck(lcx, 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));
|
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)
|
private bool SaveChunkTree (int lcx, int lcz, NbtTree tree, int? timestamp)
|
||||||
{
|
{
|
||||||
if (!LocalBoundsCheck(lcx, lcz)) {
|
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);
|
return (alt == null) ? false : alt.SaveChunkTree(ForeignX(lcx), ForeignZ(lcz), tree);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -305,7 +489,7 @@ namespace Substrate
|
||||||
public Stream GetChunkOutStream (int lcx, int lcz)
|
public Stream GetChunkOutStream (int lcx, int lcz)
|
||||||
{
|
{
|
||||||
if (!LocalBoundsCheck(lcx, 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));
|
return (alt == null) ? null : alt.GetChunkOutStream(ForeignX(lcx), ForeignZ(lcz));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -342,12 +526,12 @@ namespace Substrate
|
||||||
/// <returns>A <see cref="ChunkRef"/> at the given local coordinates, or null if no chunk exists.</returns>
|
/// <returns>A <see cref="ChunkRef"/> at the given local coordinates, or null if no chunk exists.</returns>
|
||||||
/// <remarks>The local coordinates do not strictly need to be within the bounds of the region. If coordinates are detected
|
/// <remarks>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
|
/// 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 <see cref="Region"/> to perform a similar task to <see cref="BetaChunkManager"/>, but with a
|
/// instead. This allows any <see cref="Region"/> to perform a similar task to <see cref="RegionChunkManager"/>, but with a
|
||||||
/// region-local frame of reference instead of a global frame of reference.</remarks>
|
/// region-local frame of reference instead of a global frame of reference.</remarks>
|
||||||
public ChunkRef GetChunkRef (int lcx, int lcz)
|
public ChunkRef GetChunkRef (int lcx, int lcz)
|
||||||
{
|
{
|
||||||
if (!LocalBoundsCheck(lcx, 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));
|
return (alt == null) ? null : alt.GetChunkRef(ForeignX(lcx), ForeignZ(lcz));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -379,7 +563,7 @@ namespace Substrate
|
||||||
public ChunkRef CreateChunk (int lcx, int lcz)
|
public ChunkRef CreateChunk (int lcx, int lcz)
|
||||||
{
|
{
|
||||||
if (!LocalBoundsCheck(lcx, 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));
|
return (alt == null) ? null : alt.CreateChunk(ForeignX(lcx), ForeignZ(lcz));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -388,7 +572,7 @@ namespace Substrate
|
||||||
int cx = lcx + _rx * XDIM;
|
int cx = lcx + _rx * XDIM;
|
||||||
int cz = lcz + _rz * ZDIM;
|
int cz = lcz + _rz * ZDIM;
|
||||||
|
|
||||||
Chunk c = Chunk.Create(cx, cz);
|
AlphaChunk c = AlphaChunk.Create(cx, cz);
|
||||||
c.Save(GetChunkOutStream(lcx, lcz));
|
c.Save(GetChunkOutStream(lcx, lcz));
|
||||||
|
|
||||||
ChunkRef cr = ChunkRef.Create(this, lcx, lcz);
|
ChunkRef cr = ChunkRef.Create(this, lcx, lcz);
|
||||||
|
@ -442,17 +626,17 @@ namespace Substrate
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns a <see cref="Chunk"/> given local coordinates relative to this region.
|
/// Returns a <see cref="IChunk"/> given local coordinates relative to this region.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="lcx">The local X-coordinate of a chunk relative to this region.</param>
|
/// <param name="lcx">The local X-coordinate of a chunk relative to this region.</param>
|
||||||
/// <param name="lcz">The local Z-coordinate of a chunk relative to this region.</param>
|
/// <param name="lcz">The local Z-coordinate of a chunk relative to this region.</param>
|
||||||
/// <returns>A <see cref="Chunk"/> object for the given coordinates, or null if the chunk does not exist.</returns>
|
/// <returns>A <see cref="IChunk"/> object for the given coordinates, or null if the chunk does not exist.</returns>
|
||||||
/// <remarks>If the local coordinates are out of bounds for this region, the action will be forwarded to the correct region
|
/// <remarks>If the local coordinates are out of bounds for this region, the action will be forwarded to the correct region
|
||||||
/// transparently. The returned <see cref="Chunk"/> object may either come from cache, or be regenerated from disk.</remarks>
|
/// transparently. The returned <see cref="IChunk"/> object may either come from cache, or be regenerated from disk.</remarks>
|
||||||
public Chunk GetChunk (int lcx, int lcz)
|
public IChunk GetChunk (int lcx, int lcz)
|
||||||
{
|
{
|
||||||
if (!LocalBoundsCheck(lcx, 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));
|
return (alt == null) ? null : alt.GetChunk(ForeignX(lcx), ForeignZ(lcz));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -460,7 +644,7 @@ namespace Substrate
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Chunk.CreateVerified(GetChunkTree(lcx, lcz));
|
return CreateChunkVerifiedCore(GetChunkTree(lcx, lcz));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -474,7 +658,7 @@ namespace Substrate
|
||||||
public bool ChunkExists (int lcx, int lcz)
|
public bool ChunkExists (int lcx, int lcz)
|
||||||
{
|
{
|
||||||
if (!LocalBoundsCheck(lcx, 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));
|
return (alt == null) ? false : alt.ChunkExists(ForeignX(lcx), ForeignZ(lcz));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -493,7 +677,7 @@ namespace Substrate
|
||||||
public bool DeleteChunk (int lcx, int lcz)
|
public bool DeleteChunk (int lcx, int lcz)
|
||||||
{
|
{
|
||||||
if (!LocalBoundsCheck(lcx, 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));
|
return (alt == null) ? false : alt.DeleteChunk(ForeignX(lcx), ForeignZ(lcz));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -516,18 +700,18 @@ namespace Substrate
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Saves an existing <see cref="Chunk"/> to the region at the given local coordinates.
|
/// Saves an existing <see cref="IChunk"/> to the region at the given local coordinates.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="lcx">The local X-coordinate of a chunk relative to this region.</param>
|
/// <param name="lcx">The local X-coordinate of a chunk relative to this region.</param>
|
||||||
/// <param name="lcz">The local Z-coordinate of a chunk relative to this region.</param>
|
/// <param name="lcz">The local Z-coordinate of a chunk relative to this region.</param>
|
||||||
/// <param name="chunk">A <see cref="Chunk"/> to save to the given location.</param>
|
/// <param name="chunk">A <see cref="IChunk"/> to save to the given location.</param>
|
||||||
/// <returns>A <see cref="ChunkRef"/> represneting the <see cref="Chunk"/> at its new location.</returns>
|
/// <returns>A <see cref="ChunkRef"/> represneting the <see cref="IChunk"/> at its new location.</returns>
|
||||||
/// <remarks>If the local coordinates are out of bounds for this region, the action will be forwarded to the correct region
|
/// <remarks>If the local coordinates are out of bounds for this region, the action will be forwarded to the correct region
|
||||||
/// transparently. The <see cref="Chunk"/>'s internal global coordinates will be updated to reflect the new location.</remarks>
|
/// transparently. The <see cref="IChunk"/>'s internal global coordinates will be updated to reflect the new location.</remarks>
|
||||||
public ChunkRef SetChunk (int lcx, int lcz, Chunk chunk)
|
public ChunkRef SetChunk (int lcx, int lcz, IChunk chunk)
|
||||||
{
|
{
|
||||||
if (!LocalBoundsCheck(lcx, 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));
|
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
|
// XXX: Allows a chunk not part of this region to be saved to it
|
||||||
/// <exclude/>
|
/// <exclude/>
|
||||||
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));
|
//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)));
|
return chunk.Save(GetChunkOutStream(ForeignX(chunk.X), ForeignZ(chunk.Z)));
|
||||||
|
@ -597,7 +781,7 @@ namespace Substrate
|
||||||
public int GetChunkTimestamp (int lcx, int lcz)
|
public int GetChunkTimestamp (int lcx, int lcz)
|
||||||
{
|
{
|
||||||
if (!LocalBoundsCheck(lcx, 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));
|
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)
|
public void SetChunkTimestamp (int lcx, int lcz, int timestamp)
|
||||||
{
|
{
|
||||||
if (!LocalBoundsCheck(lcx, lcz)) {
|
if (!LocalBoundsCheck(lcx, lcz)) {
|
||||||
Region alt = GetForeignRegion(lcx, lcz);
|
IRegion alt = GetForeignRegion(lcx, lcz);
|
||||||
if (alt != null)
|
if (alt != null)
|
||||||
alt.SetChunkTimestamp(ForeignX(lcx), ForeignZ(lcz), timestamp);
|
alt.SetChunkTimestamp(ForeignX(lcx), ForeignZ(lcz), timestamp);
|
||||||
}
|
}
|
||||||
|
@ -627,22 +811,22 @@ namespace Substrate
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
private bool LocalBoundsCheck (int lcx, int lcz)
|
protected bool LocalBoundsCheck (int lcx, int lcz)
|
||||||
{
|
{
|
||||||
return (lcx >= 0 && lcx < XDIM && lcz >= 0 && lcz < ZDIM);
|
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));
|
return _regionMan.GetRegion(_rx + (lcx >> XLOG), _rz + (lcz >> ZLOG));
|
||||||
}
|
}
|
||||||
|
|
||||||
private int ForeignX (int lcx)
|
protected int ForeignX (int lcx)
|
||||||
{
|
{
|
||||||
return (lcx + XDIM * 10000) & XMASK;
|
return (lcx + XDIM * 10000) & XMASK;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int ForeignZ (int lcz)
|
protected int ForeignZ (int lcz)
|
||||||
{
|
{
|
||||||
return (lcz + ZDIM * 10000) & ZMASK;
|
return (lcz + ZDIM * 10000) & ZMASK;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,16 +6,99 @@ using Substrate.Core;
|
||||||
|
|
||||||
namespace Substrate
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Manages the regions of a Beta-compatible world.
|
/// Manages the regions of a Beta-compatible world.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class RegionManager : IRegionManager
|
public abstract class RegionManager : IRegionManager
|
||||||
{
|
{
|
||||||
private string _regionPath;
|
protected string _regionPath;
|
||||||
|
|
||||||
private Dictionary<RegionKey, Region> _cache;
|
protected Dictionary<RegionKey, IRegion> _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);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new instance of a <see cref="RegionManager"/> for the given region directory and chunk cache.
|
/// Creates a new instance of a <see cref="RegionManager"/> for the given region directory and chunk cache.
|
||||||
|
@ -26,7 +109,7 @@ namespace Substrate
|
||||||
{
|
{
|
||||||
_regionPath = regionDir;
|
_regionPath = regionDir;
|
||||||
_chunkCache = cache;
|
_chunkCache = cache;
|
||||||
_cache = new Dictionary<RegionKey, Region>();
|
_cache = new Dictionary<RegionKey, IRegion>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -35,14 +118,14 @@ namespace Substrate
|
||||||
/// <param name="rx">The global X-coordinate of a region.</param>
|
/// <param name="rx">The global X-coordinate of a region.</param>
|
||||||
/// <param name="rz">The global Z-coordinate of a region.</param>
|
/// <param name="rz">The global Z-coordinate of a region.</param>
|
||||||
/// <returns>A <see cref="Region"/> representing a region at the given coordinates, or null if the region does not exist.</returns>
|
/// <returns>A <see cref="Region"/> representing a region at the given coordinates, or null if the region does not exist.</returns>
|
||||||
public Region GetRegion (int rx, int rz)
|
public IRegion GetRegion (int rx, int rz)
|
||||||
{
|
{
|
||||||
RegionKey k = new RegionKey(rx, rz);
|
RegionKey k = new RegionKey(rx, rz);
|
||||||
Region r;
|
IRegion r;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (_cache.TryGetValue(k, out r) == false) {
|
if (_cache.TryGetValue(k, out r) == false) {
|
||||||
r = new Region(this, _chunkCache, rx, rz);
|
r = CreateRegionCore(rz, rz);
|
||||||
_cache.Add(k, r);
|
_cache.Add(k, r);
|
||||||
}
|
}
|
||||||
return r;
|
return r;
|
||||||
|
@ -53,34 +136,24 @@ namespace Substrate
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <inherits />
|
||||||
/// Determines if a region exists at the given coordinates.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="rx">The global X-coordinate of a region.</param>
|
|
||||||
/// <param name="rz">The global Z-coordinate of a region.</param>
|
|
||||||
/// <returns>True if a region exists at the given global region coordinates; false otherwise.</returns>
|
|
||||||
public bool RegionExists (int rx, int rz)
|
public bool RegionExists (int rx, int rz)
|
||||||
{
|
{
|
||||||
Region r = GetRegion(rx, rz);
|
IRegion r = GetRegion(rx, rz);
|
||||||
return r != null;
|
return r != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <inherits />
|
||||||
/// Creates a new empty region at the given coordinates, if no region exists.
|
public IRegion CreateRegion (int rx, int rz)
|
||||||
/// </summary>
|
|
||||||
/// <param name="rx">The global X-coordinate of a region.</param>
|
|
||||||
/// <param name="rz">The global Z-coordinate of a region.</param>
|
|
||||||
/// <returns>A new empty <see cref="Region"/> object for the given coordinates, or an existing <see cref="Region"/> if one exists.</returns>
|
|
||||||
public Region CreateRegion (int rx, int rz)
|
|
||||||
{
|
{
|
||||||
Region r = GetRegion(rx, rz);
|
IRegion r = GetRegion(rx, rz);
|
||||||
if (r == null) {
|
if (r == null) {
|
||||||
string fp = "r." + rx + "." + rz + ".mca";
|
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);
|
RegionKey k = new RegionKey(rx, rz);
|
||||||
_cache[k] = r;
|
_cache[k] = r;
|
||||||
|
@ -89,21 +162,6 @@ namespace Substrate
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a <see cref="Region"/> for the given region filename.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="filename">The filename of the region to get.</param>
|
|
||||||
/// <returns>A <see cref="Region"/> corresponding to the coordinates encoded in the filename.</returns>
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get the current region directory path.
|
/// Get the current region directory path.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -114,15 +172,10 @@ namespace Substrate
|
||||||
}
|
}
|
||||||
|
|
||||||
// XXX: Exceptions
|
// XXX: Exceptions
|
||||||
/// <summary>
|
/// <inherits />
|
||||||
/// Deletes a region at the given coordinates.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="rx">The global X-coordinate of a region.</param>
|
|
||||||
/// <param name="rz">The global Z-coordinate of a region.</param>
|
|
||||||
/// <returns>True if a region was deleted; false otherwise.</returns>
|
|
||||||
public bool DeleteRegion (int rx, int rz)
|
public bool DeleteRegion (int rx, int rz)
|
||||||
{
|
{
|
||||||
Region r = GetRegion(rx, rz);
|
IRegion r = GetRegion(rx, rz);
|
||||||
if (r == null) {
|
if (r == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -130,7 +183,7 @@ namespace Substrate
|
||||||
RegionKey k = new RegionKey(rx, rz);
|
RegionKey k = new RegionKey(rx, rz);
|
||||||
_cache.Remove(k);
|
_cache.Remove(k);
|
||||||
|
|
||||||
r.Dispose();
|
DeleteRegionCore(r);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
File.Delete(r.GetFilePath());
|
File.Delete(r.GetFilePath());
|
||||||
|
@ -143,13 +196,13 @@ namespace Substrate
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#region IEnumerable<Region> Members
|
#region IEnumerable<IRegion> Members
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns an enumerator that iterates over all of the regions in the underlying dimension.
|
/// Returns an enumerator that iterates over all of the regions in the underlying dimension.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>An enumerator instance.</returns>
|
/// <returns>An enumerator instance.</returns>
|
||||||
public IEnumerator<Region> GetEnumerator ()
|
public IEnumerator<IRegion> GetEnumerator ()
|
||||||
{
|
{
|
||||||
return new Enumerator(this);
|
return new Enumerator(this);
|
||||||
}
|
}
|
||||||
|
@ -170,14 +223,14 @@ namespace Substrate
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
private struct Enumerator : IEnumerator<Region>
|
private struct Enumerator : IEnumerator<IRegion>
|
||||||
{
|
{
|
||||||
private List<Region> _regions;
|
private List<IRegion> _regions;
|
||||||
private int _pos;
|
private int _pos;
|
||||||
|
|
||||||
public Enumerator (RegionManager rm)
|
public Enumerator (RegionManager rm)
|
||||||
{
|
{
|
||||||
_regions = new List<Region>();
|
_regions = new List<IRegion>();
|
||||||
_pos = -1;
|
_pos = -1;
|
||||||
|
|
||||||
if (!Directory.Exists(rm.GetRegionPath())) {
|
if (!Directory.Exists(rm.GetRegionPath())) {
|
||||||
|
@ -189,7 +242,7 @@ namespace Substrate
|
||||||
|
|
||||||
foreach (string file in files) {
|
foreach (string file in files) {
|
||||||
try {
|
try {
|
||||||
Region r = rm.GetRegion(file);
|
IRegion r = rm.GetRegion(file);
|
||||||
_regions.Add(r);
|
_regions.Add(r);
|
||||||
}
|
}
|
||||||
catch (ArgumentException) {
|
catch (ArgumentException) {
|
||||||
|
@ -219,7 +272,7 @@ namespace Substrate
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Region IEnumerator<Region>.Current
|
IRegion IEnumerator<IRegion>.Current
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
|
@ -227,7 +280,7 @@ namespace Substrate
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Region Current
|
public IRegion Current
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue