diff --git a/SubstrateCS/Properties/AssemblyInfo.cs b/SubstrateCS/Properties/AssemblyInfo.cs
index 8dd63fb..25e35d6 100644
--- a/SubstrateCS/Properties/AssemblyInfo.cs
+++ b/SubstrateCS/Properties/AssemblyInfo.cs
@@ -30,8 +30,8 @@ using System.Runtime.InteropServices;
// Build Number
// Revision
//
-[assembly: AssemblyVersion("1.0.3.0")]
-[assembly: AssemblyFileVersion("1.0.3.0")]
+[assembly: AssemblyVersion("1.1.0.0")]
+[assembly: AssemblyFileVersion("1.1.0.0")]
// This library is compatible with all CLS-compliant .NET programming languages.
[assembly: CLSCompliant(true)]
\ No newline at end of file
diff --git a/SubstrateCS/Source/AlphaBlock.cs b/SubstrateCS/Source/AlphaBlock.cs
index 248a28e..417faf5 100644
--- a/SubstrateCS/Source/AlphaBlock.cs
+++ b/SubstrateCS/Source/AlphaBlock.cs
@@ -13,12 +13,13 @@ namespace Substrate
/// offers a relatively compact footprint for storing the unique identity of a block's manifestation in the world.
/// A single object may also provide a convenient way to paste a block into many locations in
/// a block collection type.
- public class AlphaBlock : IDataBlock, IPropertyBlock, ICopyable
+ public class AlphaBlock : IDataBlock, IPropertyBlock, IActiveBlock, ICopyable
{
private int _id;
private int _data;
private TileEntity _tileEntity;
+ private TileTick _tileTick;
///
/// Create a new instance of the given type with default data.
@@ -175,6 +176,65 @@ namespace Substrate
#endregion
+ #region IActiveBlock Members
+
+ public int TileTickValue
+ {
+ get
+ {
+ if (_tileTick == null)
+ return 0;
+ return _tileTick.Ticks;
+ }
+
+ set
+ {
+ if (_tileTick == null)
+ CreateTileTick();
+ _tileTick.Ticks = value;
+ }
+ }
+
+ ///
+ /// Gets the record of the block if it has one.
+ ///
+ /// The attached to this block, or null if the block type does not require a Tile Entity.
+ public TileTick GetTileTick ()
+ {
+ return _tileTick;
+ }
+
+ ///
+ /// Sets a new record for the block.
+ ///
+ /// A record compatible with the block's type.
+ public void SetTileTick (TileTick tt)
+ {
+ _tileTick = tt;
+ }
+
+ ///
+ /// Creates a default record appropriate for the block.
+ ///
+ public void CreateTileTick ()
+ {
+ _tileTick = new TileTick()
+ {
+ ID = _id,
+ };
+ }
+
+ ///
+ /// Removes any currently attached to the block.
+ ///
+ public void ClearTileTick ()
+ {
+ _tileTick = null;
+ }
+
+ #endregion
+
+
#region ICopyable Members
///
diff --git a/SubstrateCS/Source/AlphaBlockCollection.cs b/SubstrateCS/Source/AlphaBlockCollection.cs
index c2ed8f4..4be69a9 100644
--- a/SubstrateCS/Source/AlphaBlockCollection.cs
+++ b/SubstrateCS/Source/AlphaBlockCollection.cs
@@ -11,7 +11,7 @@ namespace Substrate
/// An is a wrapper around existing pieces of data. Although it
/// holds references to data, it does not "own" the data in the same way that a does. An
/// simply overlays a higher-level interface on top of existing data.
- public class AlphaBlockCollection : IBoundedAlphaBlockCollection
+ public class AlphaBlockCollection : IBoundedAlphaBlockCollection, IBoundedActiveBlockCollection
{
private readonly int _xdim;
private readonly int _ydim;
@@ -24,14 +24,17 @@ namespace Substrate
private ZXByteArray _heightMap;
private TagNodeList _tileEntities;
+ private TagNodeList _tileTicks;
private BlockLight _lightManager;
private BlockFluid _fluidManager;
private BlockTileEntities _tileEntityManager;
+ private BlockTileTicks _tileTickManager;
private bool _dirty = false;
private bool _autoLight = true;
private bool _autoFluid = false;
+ private bool _autoTick = false;
public delegate AlphaBlockCollection NeighborLookupHandler (int relx, int rely, int relz);
@@ -49,6 +52,7 @@ namespace Substrate
_skyLight = new XZYNibbleArray(xdim, ydim, zdim);
_heightMap = new ZXByteArray(xdim, zdim);
_tileEntities = new TagNodeList(TagType.TAG_COMPOUND);
+ _tileTicks = new TagNodeList(TagType.TAG_COMPOUND);
_xdim = xdim;
_ydim = ydim;
@@ -73,6 +77,28 @@ namespace Substrate
XZYNibbleArray skyLight,
ZXByteArray heightMap,
TagNodeList tileEntities)
+ : this(blocks, data, blockLight, skyLight, heightMap, tileEntities, null)
+ {
+ }
+
+ ///
+ /// Creates a new overlay on top of Alpha-specific units of data.
+ ///
+ /// An array of Block IDs.
+ /// An array of data nibbles.
+ /// An array of block light nibbles.
+ /// An array of sky light nibbles.
+ /// An array of height map values.
+ /// A list of tile entities corresponding to blocks in this collection.
+ /// A list of tile ticks corresponding to blocks in this collection.
+ public AlphaBlockCollection (
+ XZYByteArray blocks,
+ XZYNibbleArray data,
+ XZYNibbleArray blockLight,
+ XZYNibbleArray skyLight,
+ ZXByteArray heightMap,
+ TagNodeList tileEntities,
+ TagNodeList tileTicks)
{
_blocks = blocks;
_data = data;
@@ -80,6 +106,10 @@ namespace Substrate
_skyLight = skyLight;
_heightMap = heightMap;
_tileEntities = tileEntities;
+ _tileTicks = tileTicks;
+
+ if (_tileTicks == null)
+ _tileTicks = new TagNodeList(TagType.TAG_COMPOUND);
_xdim = _blocks.XDim;
_ydim = _blocks.YDim;
@@ -96,6 +126,12 @@ namespace Substrate
_lightManager = new BlockLight(this);
_fluidManager = new BlockFluid(this);
_tileEntityManager = new BlockTileEntities(_blocks, _tileEntities);
+ _tileTickManager = new BlockTileTicks(_blocks, _tileTicks);
+ }
+
+ internal TagNodeList TileTicks
+ {
+ get { return _tileTicks; }
}
#region Events
@@ -150,6 +186,15 @@ namespace Substrate
set { _autoFluid = value; }
}
+ ///
+ /// Gets or sets a value indicating whether changes to blocks will create tile tick entries.
+ ///
+ public bool AutoTileTick
+ {
+ get { return _autoTick; }
+ set { _autoTick = value; }
+ }
+
///
/// Gets or sets a value indicating whether this needs to be saved.
///
@@ -208,6 +253,11 @@ namespace Substrate
if (te != null) {
SetTileEntity(x, y, z, te.Copy());
}
+
+ TileTick tt = block.GetTileTick();
+ if (tt != null) {
+ SetTileTick(x, y, z, tt.Copy());
+ }
}
#region IBoundedBlockCollection Members
@@ -327,6 +377,17 @@ namespace Substrate
}
}
+ // TileTick consistency
+
+ if (_autoTick) {
+ if (info1.ID != info2.ID) {
+ ClearTileTick(x, y, z);
+ if (info2.Tick > 0) {
+ SetTileTickValue(x, y, z, info2.Tick);
+ }
+ }
+ }
+
_dirty = true;
}
@@ -674,6 +735,123 @@ namespace Substrate
#endregion
+
+ #region IBoundedActiveBlockCollection Members
+
+ IActiveBlock IBoundedActiveBlockCollection.GetBlock (int x, int y, int z)
+ {
+ return GetBlock(x, y, z);
+ }
+
+ IActiveBlock IBoundedActiveBlockCollection.GetBlockRef (int x, int y, int z)
+ {
+ return GetBlockRef(x, y, z);
+ }
+
+ ///
+ public void SetBlock (int x, int y, int z, IActiveBlock block)
+ {
+ SetID(x, y, z, block.ID);
+ SetTileTick(x, y, z, block.GetTileTick().Copy());
+ }
+
+ ///
+ public int GetTileTickValue (int x, int y, int z)
+ {
+ return _tileTickManager.GetTileTickValue(x, y, z);
+ }
+
+ internal int GetTileTickValue (int index)
+ {
+ int x, y, z;
+ _blocks.GetMultiIndex(index, out x, out y, out z);
+
+ return _tileTickManager.GetTileTickValue(x, y, z);
+ }
+
+ ///
+ public void SetTileTickValue (int x, int y, int z, int tickValue)
+ {
+ _tileTickManager.SetTileTickValue(x, y, z, tickValue);
+ _dirty = true;
+ }
+
+ internal void SetTileTickValue (int index, int tickValue)
+ {
+ int x, y, z;
+ _blocks.GetMultiIndex(index, out x, out y, out z);
+
+ _tileTickManager.SetTileTickValue(x, y, z, tickValue);
+ _dirty = true;
+ }
+
+ ///
+ public TileTick GetTileTick (int x, int y, int z)
+ {
+ return _tileTickManager.GetTileTick(x, y, z);
+ }
+
+ internal TileTick GetTileTick (int index)
+ {
+ int x, y, z;
+ _blocks.GetMultiIndex(index, out x, out y, out z);
+
+ return _tileTickManager.GetTileTick(x, y, z);
+ }
+
+ ///
+ public void SetTileTick (int x, int y, int z, TileTick tt)
+ {
+ _tileTickManager.SetTileTick(x, y, z, tt);
+ _dirty = true;
+ }
+
+ internal void SetTileTick (int index, TileTick tt)
+ {
+ int x, y, z;
+ _blocks.GetMultiIndex(index, out x, out y, out z);
+
+ _tileTickManager.SetTileTick(x, y, z, tt);
+ _dirty = true;
+ }
+
+ ///
+ public void CreateTileTick (int x, int y, int z)
+ {
+ _tileTickManager.CreateTileTick(x, y, z);
+ _dirty = true;
+ }
+
+ internal void CreateTileTick (int index)
+ {
+ int x, y, z;
+ _blocks.GetMultiIndex(index, out x, out y, out z);
+
+ _tileTickManager.CreateTileTick(x, y, z);
+ _dirty = true;
+ }
+
+ ///
+ public void ClearTileTick (int x, int y, int z)
+ {
+ _tileTickManager.ClearTileTick(x, y, z);
+ _dirty = true;
+ }
+
+ internal void ClearTileTick (int index)
+ {
+ int x, y, z;
+ _blocks.GetMultiIndex(index, out x, out y, out z);
+
+ _tileTickManager.ClearTileTick(x, y, z);
+ _dirty = true;
+ }
+
+ #endregion
+
+ ///
+ /// Resets all fluid blocks in the collection to their inactive type.
+ ///
public void ResetFluid ()
{
_fluidManager.ResetWater(_blocks, _data);
@@ -681,6 +859,12 @@ namespace Substrate
_dirty = true;
}
+ ///
+ /// Performs fluid simulation on all fluid blocks on this container.
+ ///
+ /// Simulation will cause inactive fluid blocks to convert into and spread active fluid blocks according
+ /// to the fluid calculation rules in Minecraft. Fluid calculation may spill into neighboring block collections
+ /// (and beyond).
public void RebuildFluid ()
{
_fluidManager.RebuildWater();
@@ -688,6 +872,12 @@ namespace Substrate
_dirty = true;
}
+ ///
+ /// Recalculates fluid starting from a given fluid block in this collection.
+ ///
+ /// Local X-coordinate of block.
+ /// Local Y-coordinate of block.
+ /// Local Z-coordiante of block.
public void UpdateFluid (int x, int y, int z)
{
bool autofluid = _autoFluid;
@@ -707,264 +897,6 @@ namespace Substrate
_autoFluid = autofluid;
}
-
- #region Unbounded Container Implementations
-
- /*IBlock IBlockCollection.GetBlock (int x, int y, int z)
- {
- if (x >= 0 && x < _xdim && y >= 0 && y < _ydim && z >= 0 && z < ZDim) {
- return GetBlock(x, y, z);
- }
- throw new ArgumentOutOfRangeException(x < 0 || x >= _xdim ? "x" : y < 0 || y >= _ydim ? "y" : "z");
- }
-
- IBlock IBlockCollection.GetBlockRef (int x, int y, int z)
- {
- if (x >= 0 && x < _xdim && y >= 0 && y < _ydim && z >= 0 && z < ZDim) {
- return GetBlockRef(x, y, z);
- }
- throw new ArgumentOutOfRangeException(x < 0 || x >= _xdim ? "x" : y < 0 || y >= _ydim ? "y" : "z");
- }
-
- void IBlockCollection.SetBlock (int x, int y, int z, IBlock block)
- {
- if (x >= 0 && x < _xdim && y >= 0 && y < _ydim && z >= 0 && z < ZDim) {
- SetBlock(x, y, z, block);
- }
- throw new ArgumentOutOfRangeException(x < 0 || x >= _xdim ? "x" : y < 0 || y >= _ydim ? "y" : "z");
- }
-
- BlockInfo IBlockCollection.GetInfo (int x, int y, int z)
- {
- if (x >= 0 && x < _xdim && y >= 0 && y < _ydim && z >= 0 && z < ZDim) {
- return GetInfo(x, y, z);
- }
- throw new ArgumentOutOfRangeException(x < 0 || x >= _xdim ? "x" : y < 0 || y >= _ydim ? "y" : "z");
- }
-
- int IBlockCollection.GetID (int x, int y, int z)
- {
- if (x >= 0 && x < _xdim && y >= 0 && y < _ydim && z >= 0 && z < ZDim) {
- return GetID(x, y, z);
- }
- throw new ArgumentOutOfRangeException(x < 0 || x >= _xdim ? "x" : y < 0 || y >= _ydim ? "y" : "z");
- }
-
- void IBlockCollection.SetID (int x, int y, int z, int id)
- {
- if (x >= 0 && x < _xdim && y >= 0 && y < _ydim && z >= 0 && z < ZDim) {
- SetID(x, y, z, id);
- }
- throw new ArgumentOutOfRangeException(x < 0 || x >= _xdim ? "x" : y < 0 || y >= _ydim ? "y" : "z");
- }
-
- IDataBlock IDataBlockCollection.GetBlock (int x, int y, int z)
- {
- if (x >= 0 && x < _xdim && y >= 0 && y < _ydim && z >= 0 && z < ZDim) {
- return GetBlock(x, y, z);
- }
- throw new ArgumentOutOfRangeException(x < 0 || x >= _xdim ? "x" : y < 0 || y >= _ydim ? "y" : "z");
- }
-
- IDataBlock IDataBlockCollection.GetBlockRef (int x, int y, int z)
- {
- if (x >= 0 && x < _xdim && y >= 0 && y < _ydim && z >= 0 && z < ZDim) {
- return GetBlockRef(x, y, z);
- }
- throw new ArgumentOutOfRangeException(x < 0 || x >= _xdim ? "x" : y < 0 || y >= _ydim ? "y" : "z");
- }
-
- void IDataBlockCollection.SetBlock (int x, int y, int z, IDataBlock block)
- {
- if (x >= 0 && x < _xdim && y >= 0 && y < _ydim && z >= 0 && z < ZDim) {
- SetBlock(x, y, z, block);
- }
- throw new ArgumentOutOfRangeException(x < 0 || x >= _xdim ? "x" : y < 0 || y >= _ydim ? "y" : "z");
- }
-
- int IDataBlockCollection.GetData (int x, int y, int z)
- {
- if (x >= 0 && x < _xdim && y >= 0 && y < _ydim && z >= 0 && z < ZDim) {
- return GetData(x, y, z);
- }
- throw new ArgumentOutOfRangeException(x < 0 || x >= _xdim ? "x" : y < 0 || y >= _ydim ? "y" : "z");
- }
-
- void IDataBlockCollection.SetData (int x, int y, int z, int data)
- {
- if (x >= 0 && x < _xdim && y >= 0 && y < _ydim && z >= 0 && z < ZDim) {
- SetData(x, y, z, data);
- }
- throw new ArgumentOutOfRangeException(x < 0 || x >= _xdim ? "x" : y < 0 || y >= _ydim ? "y" : "z");
- }
-
- ILitBlock ILitBlockCollection.GetBlock (int x, int y, int z)
- {
- throw new NotImplementedException();
- }
-
- ILitBlock ILitBlockCollection.GetBlockRef (int x, int y, int z)
- {
- if (x >= 0 && x < _xdim && y >= 0 && y < _ydim && z >= 0 && z < ZDim) {
- return GetBlockRef(x, y, z);
- }
- throw new ArgumentOutOfRangeException(x < 0 || x >= _xdim ? "x" : y < 0 || y >= _ydim ? "y" : "z");
- }
-
- void ILitBlockCollection.SetBlock (int x, int y, int z, ILitBlock block)
- {
- if (x >= 0 && x < _xdim && y >= 0 && y < _ydim && z >= 0 && z < ZDim) {
- SetBlock(x, y, z, block);
- }
- throw new ArgumentOutOfRangeException(x < 0 || x >= _xdim ? "x" : y < 0 || y >= _ydim ? "y" : "z");
- }
-
- int ILitBlockCollection.GetBlockLight (int x, int y, int z)
- {
- if (x >= 0 && x < _xdim && y >= 0 && y < _ydim && z >= 0 && z < ZDim) {
- return GetBlockLight(x, y, z);
- }
- throw new ArgumentOutOfRangeException(x < 0 || x >= _xdim ? "x" : y < 0 || y >= _ydim ? "y" : "z");
- }
-
- void ILitBlockCollection.SetBlockLight (int x, int y, int z, int light)
- {
- if (x >= 0 && x < _xdim && y >= 0 && y < _ydim && z >= 0 && z < ZDim) {
- SetBlockLight(x, y, z, light);
- }
- throw new ArgumentOutOfRangeException(x < 0 || x >= _xdim ? "x" : y < 0 || y >= _ydim ? "y" : "z");
- }
-
- int ILitBlockCollection.GetSkyLight (int x, int y, int z)
- {
- if (x >= 0 && x < _xdim && y >= 0 && y < _ydim && z >= 0 && z < ZDim) {
- return GetSkyLight(x, y, z);
- }
- throw new ArgumentOutOfRangeException(x < 0 || x >= _xdim ? "x" : y < 0 || y >= _ydim ? "y" : "z");
- }
-
- void ILitBlockCollection.SetSkyLight (int x, int y, int z, int light)
- {
- if (x >= 0 && x < _xdim && y >= 0 && y < _ydim && z >= 0 && z < ZDim) {
- SetSkyLight(x, y, z, light);
- }
- throw new ArgumentOutOfRangeException(x < 0 || x >= _xdim ? "x" : y < 0 || y >= _ydim ? "y" : "z");
- }
-
- int ILitBlockCollection.GetHeight (int x, int z)
- {
- if (x >= 0 && x < _xdim && z >= 0 && z < ZDim) {
- return GetHeight(x, z);
- }
- throw new ArgumentOutOfRangeException(x < 0 || x >= _xdim ? "x" : "z");
- }
-
- void ILitBlockCollection.SetHeight (int x, int z, int height)
- {
- if (x >= 0 && x < _xdim && z >= 0 && z < ZDim) {
- SetHeight(x, z, height);
- }
- throw new ArgumentOutOfRangeException(x < 0 || x >= _xdim ? "x" : "z");
- }
-
- void ILitBlockCollection.UpdateBlockLight (int x, int y, int z)
- {
- if (x >= 0 && x < _xdim && y >= 0 && y < _ydim && z >= 0 && z < ZDim) {
- UpdateBlockLight(x, y, z);
- }
- throw new ArgumentOutOfRangeException(x < 0 || x >= _xdim ? "x" : y < 0 || y >= _ydim ? "y" : "z");
- }
-
- void ILitBlockCollection.UpdateSkyLight (int x, int y, int z)
- {
- if (x >= 0 && x < _xdim && y >= 0 && y < _ydim && z >= 0 && z < ZDim) {
- UpdateSkyLight(x, y, z);
- }
- throw new ArgumentOutOfRangeException(x < 0 || x >= _xdim ? "x" : y < 0 || y >= _ydim ? "y" : "z");
- }
-
- IPropertyBlock IPropertyBlockCollection.GetBlock (int x, int y, int z)
- {
- if (x >= 0 && x < _xdim && y >= 0 && y < _ydim && z >= 0 && z < ZDim) {
- return GetBlock(x, y, z);
- }
- throw new ArgumentOutOfRangeException(x < 0 || x >= _xdim ? "x" : y < 0 || y >= _ydim ? "y" : "z");
- }
-
- IPropertyBlock IPropertyBlockCollection.GetBlockRef (int x, int y, int z)
- {
- if (x >= 0 && x < _xdim && y >= 0 && y < _ydim && z >= 0 && z < ZDim) {
- return GetBlockRef(x, y, z);
- }
- throw new ArgumentOutOfRangeException(x < 0 || x >= _xdim ? "x" : y < 0 || y >= _ydim ? "y" : "z");
- }
-
- void IPropertyBlockCollection.SetBlock (int x, int y, int z, IPropertyBlock block)
- {
- if (x >= 0 && x < _xdim && y >= 0 && y < _ydim && z >= 0 && z < ZDim) {
- SetBlock(x, y, z, block);
- }
- throw new ArgumentOutOfRangeException(x < 0 || x >= _xdim ? "x" : y < 0 || y >= _ydim ? "y" : "z");
- }
-
- TileEntity IPropertyBlockCollection.GetTileEntity (int x, int y, int z)
- {
- if (x >= 0 && x < _xdim && y >= 0 && y < _ydim && z >= 0 && z < ZDim) {
- return GetTileEntity(x, y, z);
- }
- throw new ArgumentOutOfRangeException(x < 0 || x >= _xdim ? "x" : y < 0 || y >= _ydim ? "y" : "z");
- }
-
- void IPropertyBlockCollection.SetTileEntity (int x, int y, int z, TileEntity te)
- {
- if (x >= 0 && x < _xdim && y >= 0 && y < _ydim && z >= 0 && z < ZDim) {
- SetTileEntity(x, y, z, te);
- }
- throw new ArgumentOutOfRangeException(x < 0 || x >= _xdim ? "x" : y < 0 || y >= _ydim ? "y" : "z");
- }
-
- void IPropertyBlockCollection.CreateTileEntity (int x, int y, int z)
- {
- if (x >= 0 && x < _xdim && y >= 0 && y < _ydim && z >= 0 && z < ZDim) {
- CreateTileEntity(x, y, z);
- }
- throw new ArgumentOutOfRangeException(x < 0 || x >= _xdim ? "x" : y < 0 || y >= _ydim ? "y" : "z");
- }
-
- void IPropertyBlockCollection.ClearTileEntity (int x, int y, int z)
- {
- if (x >= 0 && x < _xdim && y >= 0 && y < _ydim && z >= 0 && z < ZDim) {
- ClearTileEntity(x, y, z);
- }
- throw new ArgumentOutOfRangeException(x < 0 || x >= _xdim ? "x" : y < 0 || y >= _ydim ? "y" : "z");
- }
-
- AlphaBlock IAlphaBlockCollection.GetBlock (int x, int y, int z)
- {
- if (x >= 0 && x < _xdim && y >= 0 && y < _ydim && z >= 0 && z < ZDim) {
- return GetBlock(x, y, z);
- }
- throw new ArgumentOutOfRangeException(x < 0 || x >= _xdim ? "x" : y < 0 || y >= _ydim ? "y" : "z");
- }
-
- AlphaBlockRef IAlphaBlockCollection.GetBlockRef (int x, int y, int z)
- {
- if (x >= 0 && x < _xdim && y >= 0 && y < _ydim && z >= 0 && z < ZDim) {
- return GetBlockRef(x, y, z);
- }
- throw new ArgumentOutOfRangeException(x < 0 || x >= _xdim ? "x" : y < 0 || y >= _ydim ? "y" : "z");
- }
-
- void IAlphaBlockCollection.SetBlock (int x, int y, int z, AlphaBlock block)
- {
- if (x >= 0 && x < _xdim && y >= 0 && y < _ydim && z >= 0 && z < ZDim) {
- SetBlock(x, y, z, block);
- }
- throw new ArgumentOutOfRangeException(x < 0 || x >= _xdim ? "x" : y < 0 || y >= _ydim ? "y" : "z");
- }*/
-
- #endregion
-
/*#region IEnumerable Members
public IEnumerator GetEnumerator ()
diff --git a/SubstrateCS/Source/AlphaBlockRef.cs b/SubstrateCS/Source/AlphaBlockRef.cs
index 54d9007..b9abda0 100644
--- a/SubstrateCS/Source/AlphaBlockRef.cs
+++ b/SubstrateCS/Source/AlphaBlockRef.cs
@@ -24,7 +24,7 @@ namespace Substrate
/// (or similar) directly would incur the expensive lookup on each operation. See NBToolkit for an example of this
/// use case.
/// Unlike the object, this type exposed access to context-dependent data such as lighting.
- public struct AlphaBlockRef : IAlphaBlockRef
+ public struct AlphaBlockRef : IVersion10BlockRef
{
private readonly AlphaBlockCollection _collection;
private readonly int _index;
@@ -160,5 +160,50 @@ namespace Substrate
}
#endregion
+
+
+ #region IActiveBlock Members
+
+ public int TileTickValue
+ {
+ get { return _collection.GetTileTickValue(_index); }
+ set { _collection.SetTileTickValue(_index, value); }
+ }
+
+ ///
+ /// Gets the record of the block if it has one.
+ ///
+ /// The attached to this block, or null if the block type does not require a Tile Entity.
+ public TileTick GetTileTick ()
+ {
+ return _collection.GetTileTick(_index);
+ }
+
+ ///
+ /// Sets a new record for the block.
+ ///
+ /// A record compatible with the block's type.
+ public void SetTileTick (TileTick te)
+ {
+ _collection.SetTileTick(_index, te);
+ }
+
+ ///
+ /// Creates a default record appropriate for the block.
+ ///
+ public void CreateTileTick ()
+ {
+ _collection.CreateTileTick(_index);
+ }
+
+ ///
+ /// Removes any currently attached to the block.
+ ///
+ public void ClearTileTick ()
+ {
+ _collection.ClearTileTick(_index);
+ }
+
+ #endregion
}
}
diff --git a/SubstrateCS/Source/BlockInfo.cs b/SubstrateCS/Source/BlockInfo.cs
index 4fda1c6..d6f4cda 100644
--- a/SubstrateCS/Source/BlockInfo.cs
+++ b/SubstrateCS/Source/BlockInfo.cs
@@ -253,6 +253,7 @@ namespace Substrate
private int _id = 0;
private string _name = "";
+ private int _tick = 0;
private int _opacity = MAX_OPACITY;
private int _luminance = MIN_LUMINANCE;
private bool _transmitLight = false;
@@ -366,6 +367,11 @@ namespace Substrate
get { return _registered; }
}
+ public int Tick
+ {
+ get { return _tick; }
+ }
+
internal BlockInfo (int id)
{
_id = id;
@@ -392,6 +398,7 @@ namespace Substrate
///
/// A new opacity value.
/// The object instance used to invoke this method.
+ ///
public BlockInfo SetOpacity (int opacity)
{
_opacity = MIN_OPACITY + opacity;
@@ -412,6 +419,7 @@ namespace Substrate
///
/// A new luminance value.
/// The object instance used to invoke this method.
+ ///
public BlockInfo SetLuminance (int luminance)
{
_luminance = luminance;
@@ -424,6 +432,7 @@ namespace Substrate
///
/// True if this block type can transmit light to neighbors, false otherwise.
/// The object instance used to invoke this method.
+ ///
public BlockInfo SetLightTransmission (bool transmit)
{
_transmitLight = transmit;
@@ -467,12 +476,26 @@ namespace Substrate
///
/// True if this block type blocks fluids, false otherwise.
/// The object instance used to invoke this method.
+ ///
public BlockInfo SetBlocksFluid (bool blocks)
{
_blocksFluid = blocks;
return this;
}
+ ///
+ /// Sets the default tick rate/delay used for updating this block.
+ ///
+ /// Set to 0 to indicate that this block is not processed by tick updates.
+ /// The tick rate in frames between scheduled updates on this block.
+ /// The object instance used to invoke this method.
+ ///
+ public BlockInfo SetTick (int tick)
+ {
+ _tick = tick;
+ return this;
+ }
+
///
/// Tests if the given data value is valid for this block type.
///
@@ -623,33 +646,33 @@ namespace Substrate
Air = new BlockInfo(0, "Air").SetOpacity(0).SetState(BlockState.NONSOLID);
Stone = new BlockInfo(1, "Stone");
- Grass = new BlockInfo(2, "Grass");
+ Grass = new BlockInfo(2, "Grass").SetTick(10);
Dirt = new BlockInfo(3, "Dirt");
Cobblestone = new BlockInfo(4, "Cobblestone");
WoodPlank = new BlockInfo(5, "Wooden Plank");
- Sapling = new BlockInfo(6, "Sapling").SetOpacity(0).SetState(BlockState.NONSOLID);
+ Sapling = new BlockInfo(6, "Sapling").SetOpacity(0).SetState(BlockState.NONSOLID).SetTick(10);
Bedrock = new BlockInfo(7, "Bedrock");
- Water = new BlockInfo(8, "Water").SetOpacity(3).SetState(BlockState.FLUID);
+ Water = new BlockInfo(8, "Water").SetOpacity(3).SetState(BlockState.FLUID).SetTick(5);
StationaryWater = new BlockInfo(9, "Stationary Water").SetOpacity(3).SetState(BlockState.FLUID);
- Lava = new BlockInfo(10, "Lava").SetOpacity(0).SetLuminance(MAX_LUMINANCE).SetState(BlockState.FLUID);
- StationaryLava = new BlockInfo(11, "Stationary Lava").SetOpacity(0).SetLuminance(MAX_LUMINANCE).SetState(BlockState.FLUID);
- Sand = new BlockInfo(12, "Sand");
- Gravel = new BlockInfo(13, "Gravel");
+ Lava = new BlockInfo(10, "Lava").SetOpacity(0).SetLuminance(MAX_LUMINANCE).SetState(BlockState.FLUID).SetTick(30);
+ StationaryLava = new BlockInfo(11, "Stationary Lava").SetOpacity(0).SetLuminance(MAX_LUMINANCE).SetState(BlockState.FLUID).SetTick(10);
+ Sand = new BlockInfo(12, "Sand").SetTick(3);
+ Gravel = new BlockInfo(13, "Gravel").SetTick(3);
GoldOre = new BlockInfo(14, "Gold Ore");
IronOre = new BlockInfo(15, "Iron Ore");
CoalOre = new BlockInfo(16, "Coal Ore");
Wood = new BlockInfo(17, "Wood");
- Leaves = new BlockInfo(18, "Leaves").SetOpacity(1);
+ Leaves = new BlockInfo(18, "Leaves").SetOpacity(1).SetTick(10);
Sponge = new BlockInfo(19, "Sponge");
Glass = new BlockInfo(20, "Glass").SetOpacity(0);
LapisOre = new BlockInfo(21, "Lapis Lazuli Ore");
LapisBlock = new BlockInfo(22, "Lapis Lazuli Block");
- Dispenser = new BlockInfoEx(23, "Dispenser");
+ Dispenser = (BlockInfoEx)new BlockInfoEx(23, "Dispenser").SetTick(4);
Sandstone = new BlockInfo(24, "Sandstone");
NoteBlock = new BlockInfoEx(25, "Note Block");
Bed = new BlockInfo(26, "Bed").SetOpacity(0);
PoweredRail = new BlockInfo(27, "Powered Rail").SetOpacity(0).SetState(BlockState.NONSOLID);
- DetectorRail = new BlockInfo(28, "Detector Rail").SetOpacity(0).SetState(BlockState.NONSOLID);
+ DetectorRail = new BlockInfo(28, "Detector Rail").SetOpacity(0).SetState(BlockState.NONSOLID).SetTick(20);
StickyPiston = new BlockInfo(29, "Sticky Piston").SetOpacity(0);
Cobweb = new BlockInfo(30, "Cobweb").SetOpacity(0).SetState(BlockState.NONSOLID);
TallGrass = new BlockInfo(31, "Tall Grass").SetOpacity(0).SetState(BlockState.NONSOLID);
@@ -658,10 +681,10 @@ namespace Substrate
PistonHead = new BlockInfo(34, "Piston Head").SetOpacity(0);
Wool = new BlockInfo(35, "Wool");
PistonMoving = (BlockInfoEx)new BlockInfoEx(36, "Piston Moving").SetOpacity(0);
- YellowFlower = new BlockInfo(37, "Yellow Flower").SetOpacity(0).SetState(BlockState.NONSOLID);
- RedRose = new BlockInfo(38, "Red Rose").SetOpacity(0).SetState(BlockState.NONSOLID);
- BrownMushroom = new BlockInfo(39, "Brown Mushroom").SetOpacity(0).SetLuminance(1).SetState(BlockState.NONSOLID);
- RedMushroom = new BlockInfo(40, "Red Mushroom").SetOpacity(0).SetState(BlockState.NONSOLID);
+ YellowFlower = new BlockInfo(37, "Yellow Flower").SetOpacity(0).SetState(BlockState.NONSOLID).SetTick(10);
+ RedRose = new BlockInfo(38, "Red Rose").SetOpacity(0).SetState(BlockState.NONSOLID).SetTick(10);
+ BrownMushroom = new BlockInfo(39, "Brown Mushroom").SetOpacity(0).SetLuminance(1).SetState(BlockState.NONSOLID).SetTick(10);
+ RedMushroom = new BlockInfo(40, "Red Mushroom").SetOpacity(0).SetState(BlockState.NONSOLID).SetTick(10);
GoldBlock = new BlockInfo(41, "Gold Block");
IronBlock = new BlockInfo(42, "Iron Block");
DoubleSlab = new BlockInfo(43, "Double Slab");
@@ -671,8 +694,8 @@ namespace Substrate
Bookshelf = new BlockInfo(47, "Bookshelf");
MossStone = new BlockInfo(48, "Moss Stone");
Obsidian = new BlockInfo(49, "Obsidian");
- Torch = new BlockInfo(50, "Torch").SetOpacity(0).SetLuminance(MAX_LUMINANCE - 1).SetState(BlockState.NONSOLID);
- Fire = new BlockInfo(51, "Fire").SetOpacity(0).SetLuminance(MAX_LUMINANCE).SetState(BlockState.NONSOLID);
+ Torch = new BlockInfo(50, "Torch").SetOpacity(0).SetLuminance(MAX_LUMINANCE - 1).SetState(BlockState.NONSOLID).SetTick(10);
+ Fire = new BlockInfo(51, "Fire").SetOpacity(0).SetLuminance(MAX_LUMINANCE).SetState(BlockState.NONSOLID).SetTick(40);
MonsterSpawner = (BlockInfoEx)new BlockInfoEx(52, "Monster Spawner").SetOpacity(0);
WoodStairs = new BlockInfo(53, "Wooden Stairs").SetOpacity(0);
Chest = (BlockInfoEx)new BlockInfoEx(54, "Chest").SetOpacity(0);
@@ -680,8 +703,8 @@ namespace Substrate
DiamondOre = new BlockInfo(56, "Diamond Ore");
DiamondBlock = new BlockInfo(57, "Diamond Block");
CraftTable = new BlockInfo(58, "Crafting Table");
- Crops = new BlockInfo(59, "Crops").SetOpacity(0).SetState(BlockState.NONSOLID);
- Farmland = new BlockInfo(60, "Farmland").SetOpacity(0);
+ Crops = new BlockInfo(59, "Crops").SetOpacity(0).SetState(BlockState.NONSOLID).SetTick(10);
+ Farmland = new BlockInfo(60, "Farmland").SetOpacity(0).SetTick(10);
Furnace = new BlockInfoEx(61, "Furnace");
BurningFurnace = (BlockInfoEx)new BlockInfoEx(62, "Burning Furnace").SetLuminance(MAX_LUMINANCE - 1);
SignPost = (BlockInfoEx)new BlockInfoEx(63, "Sign Post").SetOpacity(0).SetState(BlockState.NONSOLID);
@@ -691,20 +714,20 @@ namespace Substrate
CobbleStairs = new BlockInfo(67, "Cobblestone Stairs").SetOpacity(0);
WallSign = (BlockInfoEx)new BlockInfoEx(68, "Wall Sign").SetOpacity(0).SetState(BlockState.NONSOLID);
Lever = new BlockInfo(69, "Lever").SetOpacity(0).SetState(BlockState.NONSOLID);
- StonePlate = new BlockInfo(70, "Stone Pressure Plate").SetOpacity(0).SetState(BlockState.NONSOLID);
+ StonePlate = new BlockInfo(70, "Stone Pressure Plate").SetOpacity(0).SetState(BlockState.NONSOLID).SetTick(20);
IronDoor = new BlockInfo(71, "Iron Door").SetOpacity(0);
- WoodPlate = new BlockInfo(72, "Wooden Pressure Plate").SetOpacity(0).SetState(BlockState.NONSOLID);
- RedstoneOre = new BlockInfo(73, "Redstone Ore");
- GlowRedstoneOre = new BlockInfo(74, "Glowing Redstone Ore").SetLuminance(9);
- RedstoneTorch = new BlockInfo(75, "Redstone Torch (Off)").SetOpacity(0).SetState(BlockState.NONSOLID);
- RedstoneTorchOn = new BlockInfo(76, "Redstone Torch (On)").SetOpacity(0).SetLuminance(7).SetState(BlockState.NONSOLID);
+ WoodPlate = new BlockInfo(72, "Wooden Pressure Plate").SetOpacity(0).SetState(BlockState.NONSOLID).SetTick(20);
+ RedstoneOre = new BlockInfo(73, "Redstone Ore").SetTick(30);
+ GlowRedstoneOre = new BlockInfo(74, "Glowing Redstone Ore").SetLuminance(9).SetTick(30);
+ RedstoneTorch = new BlockInfo(75, "Redstone Torch (Off)").SetOpacity(0).SetState(BlockState.NONSOLID).SetTick(2);
+ RedstoneTorchOn = new BlockInfo(76, "Redstone Torch (On)").SetOpacity(0).SetLuminance(7).SetState(BlockState.NONSOLID).SetTick(2);
StoneButton = new BlockInfo(77, "Stone Button").SetOpacity(0).SetState(BlockState.NONSOLID);
- Snow = new BlockInfo(78, "Snow").SetOpacity(0).SetState(BlockState.NONSOLID);
- Ice = new BlockInfo(79, "Ice").SetOpacity(3);
- SnowBlock = new BlockInfo(80, "Snow Block");
- Cactus = new BlockInfo(81, "Cactus").SetOpacity(0);
+ Snow = new BlockInfo(78, "Snow").SetOpacity(0).SetState(BlockState.NONSOLID).SetTick(10);
+ Ice = new BlockInfo(79, "Ice").SetOpacity(3).SetTick(10);
+ SnowBlock = new BlockInfo(80, "Snow Block").SetTick(10);
+ Cactus = new BlockInfo(81, "Cactus").SetOpacity(0).SetTick(10);
ClayBlock = new BlockInfo(82, "Clay Block");
- SugarCane = new BlockInfo(83, "Sugar Cane").SetOpacity(0).SetState(BlockState.NONSOLID);
+ SugarCane = new BlockInfo(83, "Sugar Cane").SetOpacity(0).SetState(BlockState.NONSOLID).SetTick(10);
Jukebox = new BlockInfo(84, "Jukebox");
Fence = new BlockInfo(85, "Fence").SetOpacity(0);
Pumpkin = new BlockInfo(86, "Pumpkin");
@@ -714,9 +737,9 @@ namespace Substrate
Portal = new BlockInfo(90, "Portal").SetOpacity(0).SetLuminance(11).SetState(BlockState.NONSOLID);
JackOLantern = new BlockInfo(91, "Jack-O-Lantern").SetLuminance(MAX_LUMINANCE);
CakeBlock = new BlockInfo(92, "Cake Block").SetOpacity(0);
- RedstoneRepeater = new BlockInfo(93, "Redstone Repeater (Off)").SetOpacity(0);
- RedstoneRepeaterOn = new BlockInfo(94, "Redstone Repeater (On)").SetOpacity(0).SetLuminance(7);
- LockedChest = (BlockInfoEx)new BlockInfoEx(95, "Locked Chest").SetLuminance(MAX_LUMINANCE);
+ RedstoneRepeater = new BlockInfo(93, "Redstone Repeater (Off)").SetOpacity(0).SetTick(10);
+ RedstoneRepeaterOn = new BlockInfo(94, "Redstone Repeater (On)").SetOpacity(0).SetLuminance(7).SetTick(10);
+ LockedChest = (BlockInfoEx)new BlockInfoEx(95, "Locked Chest").SetLuminance(MAX_LUMINANCE).SetTick(10);
Trapdoor = new BlockInfo(96, "Trapdoor").SetOpacity(0);
SilverfishStone = new BlockInfo(97, "Stone with Silverfish");
StoneBrick = new BlockInfo(98, "Stone Brick");
@@ -725,25 +748,25 @@ namespace Substrate
IronBars = new BlockInfo(101, "Iron Bars").SetOpacity(0);
GlassPane = new BlockInfo(102, "Glass Pane").SetOpacity(0);
Melon = new BlockInfo(103, "Melon");
- PumpkinStem = new BlockInfo(104, "Pumpkin Stem").SetOpacity(0).SetState(BlockState.NONSOLID);
- MelonStem = new BlockInfo(105, "Melon Stem").SetOpacity(0).SetState(BlockState.NONSOLID);
- Vines = new BlockInfo(106, "Vines").SetOpacity(0).SetState(BlockState.NONSOLID);
+ PumpkinStem = new BlockInfo(104, "Pumpkin Stem").SetOpacity(0).SetState(BlockState.NONSOLID).SetTick(10);
+ MelonStem = new BlockInfo(105, "Melon Stem").SetOpacity(0).SetState(BlockState.NONSOLID).SetTick(10);
+ Vines = new BlockInfo(106, "Vines").SetOpacity(0).SetState(BlockState.NONSOLID).SetTick(10);
FenceGate = new BlockInfo(107, "Fence Gate").SetOpacity(0);
BrickStairs = new BlockInfo(108, "Brick Stairs").SetOpacity(0);
StoneBrickStairs = new BlockInfo(109, "Stone Brick Stairs").SetOpacity(0);
- Mycelium = new BlockInfo(110, "Mycelium");
+ Mycelium = new BlockInfo(110, "Mycelium").SetTick(10);
LillyPad = new BlockInfo(111, "Lilly Pad").SetOpacity(0).SetState(BlockState.NONSOLID);
NetherBrick = new BlockInfo(112, "Nether Brick");
NetherBrickFence = new BlockInfo(113, "Nether Brick Fence").SetOpacity(0);
NetherBrickStairs = new BlockInfo(114, "Nether Brick Stairs").SetOpacity(0);
- NetherWart = new BlockInfo(115, "Nether Wart").SetOpacity(0).SetState(BlockState.NONSOLID);
+ NetherWart = new BlockInfo(115, "Nether Wart").SetOpacity(0).SetState(BlockState.NONSOLID).SetTick(10);
EnchantmentTable = (BlockInfoEx)new BlockInfoEx(116, "Enchantment Table").SetOpacity(0);
BrewingStand = (BlockInfoEx)new BlockInfoEx(117, "Brewing Stand").SetOpacity(0);
Cauldron = new BlockInfo(118, "Cauldron").SetOpacity(0);
EndPortal = (BlockInfoEx)new BlockInfoEx(119, "End Portal").SetOpacity(0).SetLuminance(MAX_LUMINANCE).SetState(BlockState.NONSOLID);
EndPortalFrame = new BlockInfo(120, "End Portal Frame").SetLuminance(MAX_LUMINANCE);
EndStone = new BlockInfo(121, "End Stone");
- DragonEgg = new BlockInfo(122, "Dragon Egg").SetOpacity(0).SetLuminance(1);
+ DragonEgg = new BlockInfo(122, "Dragon Egg").SetOpacity(0).SetLuminance(1).SetTick(3);
for (int i = 0; i < MAX_BLOCKS; i++) {
if (_blockTable[i] == null) {
diff --git a/SubstrateCS/Source/BlockManager.cs b/SubstrateCS/Source/BlockManager.cs
index b53ed66..1e3325b 100644
--- a/SubstrateCS/Source/BlockManager.cs
+++ b/SubstrateCS/Source/BlockManager.cs
@@ -6,7 +6,7 @@ namespace Substrate
///
/// Represents an Alpha-compatible interface for globally managing blocks.
///
- public class BlockManager : IBlockManager
+ public class BlockManager : IVersion10BlockManager, IBlockManager
{
public const int MIN_X = -32000000;
public const int MAX_X = 32000000;
@@ -441,5 +441,92 @@ namespace Substrate
}
#endregion
+
+
+ #region IActiveBlockContainer Members
+
+ IActiveBlock IActiveBlockCollection.GetBlock (int x, int y, int z)
+ {
+ return GetBlock(x, y, z);
+ }
+
+ IActiveBlock IActiveBlockCollection.GetBlockRef (int x, int y, int z)
+ {
+ return GetBlockRef(x, y, z);
+ }
+
+ ///
+ public void SetBlock (int x, int y, int z, IActiveBlock block)
+ {
+ cache.Blocks.SetBlock(x, y, z, block);
+ }
+
+ ///
+ public int GetTileTickValue (int x, int y, int z)
+ {
+ cache = GetChunk(x, y, z);
+ if (cache == null || !Check(x, y, z)) {
+ return 0;
+ }
+
+ return cache.Blocks.GetTileTickValue(x & chunkXMask, y & chunkYMask, z & chunkZMask);
+ }
+
+ ///
+ public void SetTileTickValue (int x, int y, int z, int tickValue)
+ {
+ cache = GetChunk(x, y, z);
+ if (cache == null || !Check(x, y, z)) {
+ return;
+ }
+
+ cache.Blocks.SetTileTickValue(x & chunkXMask, y & chunkYMask, z & chunkZMask, tickValue);
+ }
+
+ ///
+ public TileTick GetTileTick (int x, int y, int z)
+ {
+ cache = GetChunk(x, y, z);
+ if (cache == null || !Check(x, y, z)) {
+ return null;
+ }
+
+ return cache.Blocks.GetTileTick(x & chunkXMask, y & chunkYMask, z & chunkZMask);
+ }
+
+ ///
+ public void SetTileTick (int x, int y, int z, TileTick te)
+ {
+ cache = GetChunk(x, y, z);
+ if (cache == null || !Check(x, y, z)) {
+ return;
+ }
+
+ cache.Blocks.SetTileTick(x & chunkXMask, y & chunkYMask, z & chunkZMask, te);
+ }
+
+ ///
+ public void CreateTileTick (int x, int y, int z)
+ {
+ cache = GetChunk(x, y, z);
+ if (cache == null || !Check(x, y, z)) {
+ return;
+ }
+
+ cache.Blocks.CreateTileTick(x & chunkXMask, y & chunkYMask, z & chunkZMask);
+ }
+
+ ///
+ public void ClearTileTick (int x, int y, int z)
+ {
+ cache = GetChunk(x, y, z);
+ if (cache == null || !Check(x, y, z)) {
+ return;
+ }
+
+ cache.Blocks.ClearTileTick(x & chunkXMask, y & chunkYMask, z & chunkZMask);
+ }
+
+ #endregion
}
}
diff --git a/SubstrateCS/Source/Chunk.cs b/SubstrateCS/Source/Chunk.cs
index f5fb8fe..a7ce9a6 100644
--- a/SubstrateCS/Source/Chunk.cs
+++ b/SubstrateCS/Source/Chunk.cs
@@ -32,6 +32,7 @@ namespace Substrate
new SchemaNodeArray("HeightMap", 256),
new SchemaNodeList("Entities", TagType.TAG_COMPOUND, SchemaOptions.CREATE_ON_MISSING),
new SchemaNodeList("TileEntities", TagType.TAG_COMPOUND, TileEntity.Schema, SchemaOptions.CREATE_ON_MISSING),
+ new SchemaNodeList("TileTicks", TagType.TAG_COMPOUND, TileTick.Schema, SchemaOptions.OPTIONAL),
new SchemaNodeScaler("LastUpdate", TagType.TAG_LONG, SchemaOptions.CREATE_ON_MISSING),
new SchemaNodeScaler("xPos", TagType.TAG_INT),
new SchemaNodeScaler("zPos", TagType.TAG_INT),
@@ -52,6 +53,7 @@ namespace Substrate
private TagNodeList _entities;
private TagNodeList _tileEntities;
+ private TagNodeList _tileTicks;
private AlphaBlockCollection _blockManager;
private EntityCollection _entityManager;
@@ -189,6 +191,25 @@ namespace Substrate
_tileEntities.Add(te.BuildTree());
}
+ // Update tile tick coordinates
+
+ if (_tileTicks != null) {
+ List tileTicks = new List();
+ foreach (TagNodeCompound tag in _tileTicks) {
+ TileTick tt = TileTick.FromTreeSafe(tag);
+
+ if (tt != null) {
+ tt.MoveBy(diffx, 0, diffz);
+ tileTicks.Add(tt);
+ }
+ }
+
+ _tileTicks.Clear();
+ foreach (TileTick tt in tileTicks) {
+ _tileTicks.Add(tt.BuildTree());
+ }
+ }
+
// Update entity coordinates
List entities = new List();
@@ -214,6 +235,8 @@ namespace Substrate
return false;
}
+ BuildConditional();
+
_tree.WriteTo(outStream);
outStream.Close();
@@ -248,6 +271,11 @@ namespace Substrate
_entities = level["Entities"] as TagNodeList;
_tileEntities = level["TileEntities"] as TagNodeList;
+ if (level.ContainsKey("TileTicks"))
+ _tileTicks = level["TileTicks"] as TagNodeList;
+ else
+ _tileTicks = new TagNodeList(TagType.TAG_COMPOUND);
+
// List-type patch up
if (_entities.Count == 0) {
level["Entities"] = new TagNodeList(TagType.TAG_COMPOUND);
@@ -259,10 +287,15 @@ namespace Substrate
_tileEntities = level["TileEntities"] as TagNodeList;
}
+ if (_tileTicks.Count == 0) {
+ level["TileTicks"] = new TagNodeList(TagType.TAG_COMPOUND);
+ _tileTicks = level["TileTicks"] as TagNodeList;
+ }
+
_cx = level["xPos"].ToTagInt();
_cz = level["zPos"].ToTagInt();
- _blockManager = new AlphaBlockCollection(_blocks, _data, _blockLight, _skyLight, _heightMap, _tileEntities);
+ _blockManager = new AlphaBlockCollection(_blocks, _data, _blockLight, _skyLight, _heightMap, _tileEntities, _tileTicks);
_entityManager = new EntityCollection(_entities);
return this;
@@ -288,6 +321,8 @@ namespace Substrate
/// The root node of the Chunk's NBT tree.
public TagNode BuildTree ()
{
+ BuildConditional();
+
return _tree.Root;
}
@@ -319,6 +354,15 @@ namespace Substrate
#endregion
+ private void BuildConditional ()
+ {
+ TagNodeCompound level = _tree.Root["Level"] as TagNodeCompound;
+ if (_tileTicks != _blockManager.TileTicks && _blockManager.TileTicks.Count > 0) {
+ _tileTicks = _blockManager.TileTicks;
+ level["TileTicks"] = _tileTicks;
+ }
+ }
+
private void BuildNBTTree ()
{
int elements2 = XDIM * ZDIM;
@@ -338,6 +382,7 @@ namespace Substrate
_entities = new TagNodeList(TagType.TAG_COMPOUND);
_tileEntities = new TagNodeList(TagType.TAG_COMPOUND);
+ _tileTicks = new TagNodeList(TagType.TAG_COMPOUND);
TagNodeCompound level = new TagNodeCompound();
level.Add("Blocks", blocks);
@@ -347,6 +392,7 @@ namespace Substrate
level.Add("HeightMap", heightMap);
level.Add("Entities", _entities);
level.Add("TileEntities", _tileEntities);
+ level.Add("TileTicks", _tileTicks);
level.Add("LastUpdate", new TagNodeLong(Timestamp()));
level.Add("xPos", new TagNodeInt(_cx));
level.Add("zPos", new TagNodeInt(_cz));
diff --git a/SubstrateCS/Source/Core/BlockInterface.cs b/SubstrateCS/Source/Core/BlockInterface.cs
index 76d1cfd..399f24d 100644
--- a/SubstrateCS/Source/Core/BlockInterface.cs
+++ b/SubstrateCS/Source/Core/BlockInterface.cs
@@ -2,11 +2,29 @@
namespace Substrate.Core
{
+ ///
+ /// Represents the cardinal direction of a block collection's neighboring collection.
+ ///
public enum BlockCollectionEdge
{
+ ///
+ /// Refers to a chunk/collection to the east of the current chunk/collection.
+ ///
EAST = 0,
+
+ ///
+ /// Refers to a chunk/collection to the north of the current chunk/collection.
+ ///
NORTH = 1,
+
+ ///
+ /// Refers to a chunk/collection to the west of the current chunk/collection.
+ ///
WEST = 2,
+
+ ///
+ /// Refers to a chunk/collection to the south of the current chunk/collection.
+ ///
SOUTH = 3
}
@@ -86,6 +104,41 @@ namespace Substrate.Core
void ClearTileEntity ();
}
+ ///
+ /// A block type supporting active tick state.
+ ///
+ public interface IActiveBlock : IBlock
+ {
+ ///
+ /// Gets a entry attached to this block.
+ ///
+ /// A for this block, or null if one has not been created yet.
+ TileTick GetTileTick ();
+
+ ///
+ /// Sets the attached to this block.
+ ///
+ /// A representing the delay until this block is next processed in-game.
+ void SetTileTick (TileTick tt);
+
+ ///
+ /// Creates a default entry for this block.
+ ///
+ /// This method will overwrite any existing attached to the block.
+ void CreateTileTick ();
+
+ ///
+ /// Deletes the entry attached to this block, if one exists.
+ ///
+ void ClearTileTick ();
+
+ ///
+ /// Gets or sets the the actual tick delay associated with this block.
+ ///
+ /// If no underlying entry exists for this block, one will be created.
+ int TileTickValue { get; set; }
+ }
+
///
/// An Alpha-compatible context-free block type supporting data and properties.
///
@@ -104,10 +157,31 @@ namespace Substrate.Core
bool IsValid { get; }
}
+ ///
+ /// A version-1.0-compatible context-free block type supporting data, properties, and active tick state.
+ ///
+ public interface IVersion10Block : IAlphaBlock, IActiveBlock
+ {
+ }
+
+ ///
+ /// A version-1.0-compatible reference type supporting data, lighting, properties, and active tick state.
+ ///
+ public interface IVersion10BlockRef : IAlphaBlockRef, IActiveBlock
+ {
+ }
+
///
/// Provides a common interface for block containers that provide global management.
///
public interface IBlockManager : IAlphaBlockCollection
{
}
+
+ ///
+ /// Provides a common interface for block containers that provide global management, extended through Version 1.0 capabilities.
+ ///
+ public interface IVersion10BlockManager : IBlockManager, IActiveBlockCollection
+ {
+ }
}
diff --git a/SubstrateCS/Source/Core/BlockTileTicks.cs b/SubstrateCS/Source/Core/BlockTileTicks.cs
new file mode 100644
index 0000000..c9185f9
--- /dev/null
+++ b/SubstrateCS/Source/Core/BlockTileTicks.cs
@@ -0,0 +1,179 @@
+using System;
+using System.Collections.Generic;
+using Substrate.Nbt;
+
+namespace Substrate.Core
+{
+ public class BlockTileTicks
+ {
+ private XZYByteArray _blocks;
+ private TagNodeList _tileTicks;
+
+ private Dictionary _tileTickTable;
+
+ public event BlockCoordinateHandler TranslateCoordinates;
+
+ public BlockTileTicks (XZYByteArray blocks, TagNodeList tileTicks)
+ {
+ _blocks = blocks;
+ _tileTicks = tileTicks;
+
+ BuildTileTickCache();
+ }
+
+ public BlockTileTicks (BlockTileTicks bte)
+ {
+ _blocks = bte._blocks;
+ _tileTicks = bte._tileTicks;
+
+ BuildTileTickCache();
+ }
+
+ public int GetTileTickValue (int x, int y, int z)
+ {
+ BlockKey key = (TranslateCoordinates != null)
+ ? TranslateCoordinates(x, y, z)
+ : new BlockKey(x, y, z);
+
+ TagNodeCompound te;
+
+ if (!_tileTickTable.TryGetValue(key, out te)) {
+ return 0;
+ }
+
+ if (!te.ContainsKey("t"))
+ return 0;
+
+ return te["t"].ToTagInt().Data;
+ }
+
+ public void SetTileTickValue (int x, int y, int z, int tickValue)
+ {
+ BlockKey key = (TranslateCoordinates != null)
+ ? TranslateCoordinates(x, y, z)
+ : new BlockKey(x, y, z);
+
+ TagNodeCompound te;
+
+ if (!_tileTickTable.TryGetValue(key, out te)) {
+ TileTick tt = new TileTick()
+ {
+ ID = _blocks[x, y, z],
+ Ticks = tickValue,
+ X = key.x,
+ Y = key.y,
+ Z = key.z,
+ };
+ te = tt.BuildTree() as TagNodeCompound;
+
+ _tileTicks.Add(te);
+ _tileTickTable[key] = te;
+ }
+ else {
+ te["Ticks"].ToTagInt().Data = tickValue;
+ }
+ }
+
+ public TileTick GetTileTick (int x, int y, int z)
+ {
+ BlockKey key = (TranslateCoordinates != null)
+ ? TranslateCoordinates(x, y, z)
+ : new BlockKey(x, y, z);
+
+ TagNodeCompound te;
+
+ if (!_tileTickTable.TryGetValue(key, out te)) {
+ return null;
+ }
+
+ if (!te.ContainsKey("i")) {
+ return null;
+ }
+
+ return TileTick.FromTreeSafe(te);
+ }
+
+ public void SetTileTick (int x, int y, int z, TileTick te)
+ {
+ if (te.ID != _blocks[x, y, z]) {
+ throw new ArgumentException("The TileTick type is not valid for this block.", "te");
+ }
+
+ BlockKey key = (TranslateCoordinates != null)
+ ? TranslateCoordinates(x, y, z)
+ : new BlockKey(x, y, z);
+
+ TagNodeCompound oldte;
+
+ if (_tileTickTable.TryGetValue(key, out oldte)) {
+ _tileTicks.Remove(oldte);
+ }
+
+ te.X = key.x;
+ te.Y = key.y;
+ te.Z = key.z;
+
+ TagNodeCompound tree = te.BuildTree() as TagNodeCompound;
+
+ _tileTicks.Add(tree);
+ _tileTickTable[key] = tree;
+ }
+
+ public void CreateTileTick (int x, int y, int z)
+ {
+ TileTick te = new TileTick()
+ {
+ ID = _blocks[x, y, z],
+ };
+
+ BlockKey key = (TranslateCoordinates != null)
+ ? TranslateCoordinates(x, y, z)
+ : new BlockKey(x, y, z);
+
+ TagNodeCompound oldte;
+
+ if (_tileTickTable.TryGetValue(key, out oldte)) {
+ _tileTicks.Remove(oldte);
+ }
+
+ te.X = key.x;
+ te.Y = key.y;
+ te.Z = key.z;
+
+ TagNodeCompound tree = te.BuildTree() as TagNodeCompound;
+
+ _tileTicks.Add(tree);
+ _tileTickTable[key] = tree;
+ }
+
+ public void ClearTileTick (int x, int y, int z)
+ {
+ BlockKey key = (TranslateCoordinates != null)
+ ? TranslateCoordinates(x, y, z)
+ : new BlockKey(x, y, z);
+
+ TagNodeCompound te;
+
+ if (!_tileTickTable.TryGetValue(key, out te)) {
+ return;
+ }
+
+ _tileTicks.Remove(te);
+ _tileTickTable.Remove(key);
+ }
+
+ private void BuildTileTickCache ()
+ {
+ _tileTickTable = new Dictionary();
+
+ foreach (TagNodeCompound te in _tileTicks) {
+ int tex = te["x"].ToTagInt();
+ int tey = te["y"].ToTagInt();
+ int tez = te["z"].ToTagInt();
+
+ BlockKey key = new BlockKey(tex, tey, tez);
+ _tileTickTable[key] = te;
+ }
+ }
+ }
+}
diff --git a/SubstrateCS/Source/Core/BoundedBlockInterface.cs b/SubstrateCS/Source/Core/BoundedBlockInterface.cs
index b52b594..b1cb6e1 100644
--- a/SubstrateCS/Source/Core/BoundedBlockInterface.cs
+++ b/SubstrateCS/Source/Core/BoundedBlockInterface.cs
@@ -415,6 +415,92 @@ namespace Substrate.Core
void ClearTileEntity (int x, int y, int z);
}
+ ///
+ /// A bounded container for blocks supporting active processing properties.
+ ///
+ ///
+ public interface IBoundedActiveBlockCollection : IBoundedBlockCollection
+ {
+ ///
+ /// Gets a block supporting active processing properties from a bounded block container.
+ ///
+ /// The container-local X-coordinate of a block.
+ /// The container-local Y-coordinate of a block.
+ /// The container-local Z-coordinate of a block.
+ /// An from the collection at the given coordinates.
+ new IActiveBlock GetBlock (int x, int y, int z);
+
+ ///
+ /// Gets a reference object to a block supporting active processing properties within a bounded block container.
+ ///
+ /// The container-local X-coordinate of a block.
+ /// The container-local Y-coordinate of a block.
+ /// The container-local Z-coordinate of a block.
+ /// An acting as a reference directly into the container at the given coordinates.
+ new IActiveBlock GetBlockRef (int x, int y, int z);
+
+ ///
+ /// Updates a block in a bounded block container with data from an existing object.
+ ///
+ /// The container-local X-coordinate of a block.
+ /// The container-local Y-coordinate of a block.
+ /// The container-local Z-coordinate of a block.
+ /// The to copy data from.
+ void SetBlock (int x, int y, int z, IActiveBlock block);
+
+ ///
+ /// Gets the record of a block within a bounded block container.
+ ///
+ /// The container-local X-coordinate of a block.
+ /// The container-local Y-coordinate of a block.
+ /// The container-local Z-coordinate of a block.
+ /// A record attached to a block at the given coordinates, or null if no tile entity is set.
+ TileTick GetTileTick (int x, int y, int z);
+
+ ///
+ /// Sets a record to a block within a bounded block container.
+ ///
+ /// The container-local X-coordinate of a block.
+ /// The container-local Y-coordinate of a block.
+ /// The container-local Z-coordinate of a block.
+ /// The record to assign to the given block.
+ void SetTileTick (int x, int y, int z, TileTick tt);
+
+ ///
+ /// Creates a new default record for a block within a bounded block container.
+ ///
+ /// The container-local X-coordinate of a block.
+ /// The container-local Y-coordinate of a block.
+ /// The container-local Z-coordinate of a block.
+ void CreateTileTick (int x, int y, int z);
+
+ ///
+ /// Deletes a record associated with a block within a bounded block container, if it exists.
+ ///
+ /// The container-local X-coordinate of a block.
+ /// The container-local Y-coordinate of a block.
+ /// The container-local Z-coordinate of a block.
+ void ClearTileTick (int x, int y, int z);
+
+ ///
+ /// Gets the tick delay specified in a block's entry, if it exists.
+ ///
+ /// The container-local X-coordinate of a block.
+ /// The container-local Y-coordinate of a block.
+ /// The container-local Z-coordinate of a block.
+ /// The tick delay in a block's entry, or 0 if no entry exists.
+ int GetTileTickValue (int x, int y, int z);
+
+ ///
+ /// Sets the tick delay in a block's entry.
+ ///
+ /// The container-local X-coordinate of a block.
+ /// The container-local Y-coordinate of a block.
+ /// The container-local Z-coordinate of a block.
+ /// The tick delay that specifies when this block should next be processed for update.
+ void SetTileTickValue (int x, int y, int z, int tickValue);
+ }
+
///
/// A bounded container of blocks supporting data, lighting, and properties.
///
diff --git a/SubstrateCS/Source/Core/UnboundedBlockInterface.cs b/SubstrateCS/Source/Core/UnboundedBlockInterface.cs
index e37ba22..a7c8b5f 100644
--- a/SubstrateCS/Source/Core/UnboundedBlockInterface.cs
+++ b/SubstrateCS/Source/Core/UnboundedBlockInterface.cs
@@ -236,7 +236,7 @@ namespace Substrate.Core
}
///
- /// An unbounded container for blocks supporting additional properties.
+ /// An unbounded container for blocks supporting extra properties.
///
///
public interface IPropertyBlockCollection : IBlockCollection
@@ -307,6 +307,92 @@ namespace Substrate.Core
void ClearTileEntity (int x, int y, int z);
}
+ ///
+ /// An unbounded container for blocks supporting active processing properties.
+ ///
+ ///
+ public interface IActiveBlockCollection : IBlockCollection
+ {
+ ///
+ /// Gets a block supporting active processing properties from an unbounded block container.
+ ///
+ /// The global X-coordinate of a block.
+ /// The global Y-coordinate of a block.
+ /// The global Z-coordinate of a block.
+ /// An from the collection at the given coordinates.
+ new IActiveBlock GetBlock (int x, int y, int z);
+
+ ///
+ /// Gets a reference object to a block supporting active processing properties within an unbounded block container.
+ ///
+ /// The global X-coordinate of a block.
+ /// The global Y-coordinate of a block.
+ /// The global Z-coordinate of a block.
+ /// An acting as a reference directly into the container at the given coordinates.
+ new IActiveBlock GetBlockRef (int x, int y, int z);
+
+ ///
+ /// Updates a block in an unbounded block container with data from an existing object.
+ ///
+ /// The global X-coordinate of a block.
+ /// The global Y-coordinate of a block.
+ /// The global Z-coordinate of a block.
+ /// The to copy data from.
+ void SetBlock (int x, int y, int z, IActiveBlock block);
+
+ ///
+ /// Gets the record of a block within an unbounded block container.
+ ///
+ /// The global X-coordinate of a block.
+ /// The global Y-coordinate of a block.
+ /// The global Z-coordinate of a block.
+ /// A record attached to a block at the given coordinates, or null if no tile entity is set.
+ TileTick GetTileTick (int x, int y, int z);
+
+ ///
+ /// Sets a record to a block within an unbounded block container.
+ ///
+ /// The global X-coordinate of a block.
+ /// The global Y-coordinate of a block.
+ /// The global Z-coordinate of a block.
+ /// The record to assign to the given block.
+ void SetTileTick (int x, int y, int z, TileTick tt);
+
+ ///
+ /// Creates a new default record for a block within an unbounded block container.
+ ///
+ /// The global X-coordinate of a block.
+ /// The global Y-coordinate of a block.
+ /// The global Z-coordinate of a block.
+ void CreateTileTick (int x, int y, int z);
+
+ ///
+ /// Deletes a record associated with a block within an unbounded block container, if it exists.
+ ///
+ /// The global X-coordinate of a block.
+ /// The global Y-coordinate of a block.
+ /// The global Z-coordinate of a block.
+ void ClearTileTick (int x, int y, int z);
+
+ ///
+ /// Gets the tick delay specified in a block's entry, if it exists.
+ ///
+ /// The global X-coordinate of a block.
+ /// The global Y-coordinate of a block.
+ /// The global Z-coordinate of a block.
+ /// The tick delay in a block's entry, or 0 if no entry exists.
+ int GetTileTickValue (int x, int y, int z);
+
+ ///
+ /// Sets the tick delay in a block's entry.
+ ///
+ /// The global X-coordinate of a block.
+ /// The global Y-coordinate of a block.
+ /// The global Z-coordinate of a block.
+ /// The tick delay that specifies when this block should next be processed for update.
+ void SetTileTickValue (int x, int y, int z, int tickValue);
+ }
+
///
/// An unbounded container of blocks supporting data, lighting, and properties.
///
diff --git a/SubstrateCS/Source/TileTick.cs b/SubstrateCS/Source/TileTick.cs
new file mode 100644
index 0000000..3d28943
--- /dev/null
+++ b/SubstrateCS/Source/TileTick.cs
@@ -0,0 +1,237 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Substrate.Nbt;
+using Substrate.Core;
+
+namespace Substrate
+{
+ ///
+ /// Represents a TileTick record, which is used to queue a block for processing in the future.
+ ///
+ public class TileTick : INbtObject, ICopyable
+ {
+ private static readonly SchemaNodeCompound _schema = new SchemaNodeCompound("")
+ {
+ new SchemaNodeScaler("i", TagType.TAG_INT),
+ new SchemaNodeScaler("t", TagType.TAG_INT),
+ new SchemaNodeScaler("x", TagType.TAG_INT),
+ new SchemaNodeScaler("y", TagType.TAG_INT),
+ new SchemaNodeScaler("z", TagType.TAG_INT),
+ };
+
+ private int _blockId;
+ private int _ticks;
+ private int _x;
+ private int _y;
+ private int _z;
+
+ private TagNodeCompound _source;
+
+ ///
+ /// Constructs an empty object.
+ ///
+ public TileTick ()
+ {
+ }
+
+ ///
+ /// Constructs a by copying an existing one.
+ ///
+ /// The to copy.
+ public TileTick (TileTick tt)
+ {
+ _blockId = tt._blockId;
+ _ticks = tt._ticks;
+ _x = tt._x;
+ _y = tt._y;
+ _z = tt._z;
+
+ if (tt._source != null) {
+ _source = tt._source.Copy() as TagNodeCompound;
+ }
+ }
+
+ ///
+ /// Gets or sets the ID (type) of the block that this is associated with.
+ ///
+ public int ID
+ {
+ get { return _blockId; }
+ set { _blockId = value; }
+ }
+
+ ///
+ /// Gets or sets the number of ticks remaining until the associated block is processed.
+ ///
+ public int Ticks
+ {
+ get { return _ticks; }
+ set { _ticks = value; }
+ }
+
+ ///
+ /// Gets or sets the global X-coordinate of the block that this is associated with.
+ ///
+ public int X
+ {
+ get { return _x; }
+ set { _x = value; }
+ }
+
+ ///
+ /// Gets or sets the global Y-coordinate of the block that this is associated with.
+ ///
+ public int Y
+ {
+ get { return _y; }
+ set { _y = value; }
+ }
+
+ ///
+ /// Gets or sets the global Z-coordinate of the block that this is associated with.
+ ///
+ public int Z
+ {
+ get { return _z; }
+ set { _z = value; }
+ }
+
+ ///
+ /// Checks whether the is located (associated with a block) at the specific global coordinates.
+ ///
+ /// The global X-coordinate to test.
+ /// The global Y-coordinate to test.
+ /// The global Z-coordinate to test.
+ /// Status indicating whether the is located at the specified global coordinates.
+ public bool LocatedAt (int x, int y, int z)
+ {
+ return _x == x && _y == y && _z == z;
+ }
+
+ ///
+ /// Moves the by given block offsets.
+ ///
+ /// The X-offset to move by, in blocks.
+ /// The Y-offset to move by, in blocks.
+ /// The Z-offset to move by, in blocks.
+ public virtual void MoveBy (int diffX, int diffY, int diffZ)
+ {
+ _x += diffX;
+ _y += diffY;
+ _z += diffZ;
+ }
+
+ ///
+ /// Attempt to construct a new from a Tile Entity subtree without validation.
+ ///
+ /// The root node of a subtree.
+ /// A new on success, or null if the tree was unparsable.
+ public static TileTick FromTree (TagNode tree)
+ {
+ return new TileTick().LoadTree(tree);
+ }
+
+ ///
+ /// Attempt to construct a new from a Tile Entity subtree with validation.
+ ///
+ /// The root node of a subtree.
+ /// A new on success, or null if the tree failed validation.
+ public static TileTick FromTreeSafe (TagNode tree)
+ {
+ return new TileTick().LoadTreeSafe(tree);
+ }
+
+ #region INbtObject Members
+
+ ///
+ /// Gets a representing the basic schema of a .
+ ///
+ public static SchemaNodeCompound Schema
+ {
+ get { return _schema; }
+ }
+
+ ///
+ /// Attempt to load a subtree into the without validation.
+ ///
+ /// The root node of a subtree.
+ /// The returns itself on success, or null if the tree was unparsable.
+ public TileTick LoadTree (TagNode tree)
+ {
+ TagNodeCompound ctree = tree as TagNodeCompound;
+ if (ctree == null) {
+ return null;
+ }
+
+ _blockId = ctree["i"].ToTagInt();
+ _ticks = ctree["t"].ToTagInt();
+ _x = ctree["x"].ToTagInt();
+ _y = ctree["y"].ToTagInt();
+ _z = ctree["z"].ToTagInt();
+
+ _source = ctree.Copy() as TagNodeCompound;
+
+ return this;
+ }
+
+ ///
+ /// Attempt to load a subtree into the with validation.
+ ///
+ /// The root node of a subtree.
+ /// The returns itself on success, or null if the tree failed validation.
+ public TileTick LoadTreeSafe (TagNode tree)
+ {
+ if (!ValidateTree(tree)) {
+ return null;
+ }
+
+ return LoadTree(tree);
+ }
+
+ ///
+ /// Builds a subtree from the current data.
+ ///
+ /// The root node of a subtree representing the current data.
+ public TagNode BuildTree ()
+ {
+ TagNodeCompound tree = new TagNodeCompound();
+ tree["i"] = new TagNodeInt(_blockId);
+ tree["t"] = new TagNodeInt(_ticks);
+ tree["x"] = new TagNodeInt(_x);
+ tree["y"] = new TagNodeInt(_y);
+ tree["z"] = new TagNodeInt(_z);
+
+ if (_source != null) {
+ tree.MergeFrom(_source);
+ }
+
+ return tree;
+ }
+
+ ///
+ /// Validate a subtree against a basic schema.
+ ///
+ /// The root node of a subtree.
+ /// Status indicating whether the tree was valid against the internal schema.
+ public bool ValidateTree (TagNode tree)
+ {
+ return new NbtVerifier(tree, _schema).Verify();
+ }
+
+ #endregion
+
+ #region ICopyable Members
+
+ ///
+ /// Creates a deep-copy of the including any data defined in a subtype.
+ ///
+ /// A deep-copy of the .
+ public virtual TileTick Copy ()
+ {
+ return new TileTick(this);
+ }
+
+ #endregion
+ }
+}
diff --git a/SubstrateCS/Substrate (NET2).csproj b/SubstrateCS/Substrate (NET2).csproj
index a272b84..0209e0a 100644
--- a/SubstrateCS/Substrate (NET2).csproj
+++ b/SubstrateCS/Substrate (NET2).csproj
@@ -62,6 +62,7 @@
+
@@ -212,6 +213,7 @@
+
diff --git a/SubstrateCS/Substrate (NET4).csproj b/SubstrateCS/Substrate (NET4).csproj
index b7d4ca9..817fddf 100644
--- a/SubstrateCS/Substrate (NET4).csproj
+++ b/SubstrateCS/Substrate (NET4).csproj
@@ -62,6 +62,7 @@
+
@@ -212,6 +213,7 @@
+