From 6473402fab4186eb70b846c229de7f527a28f47c Mon Sep 17 00:00:00 2001 From: Justin Aquadro Date: Sat, 28 Jan 2012 01:42:08 -0500 Subject: [PATCH] Added TileTick infrastructure --- SubstrateCS/Properties/AssemblyInfo.cs | 4 +- SubstrateCS/Source/AlphaBlock.cs | 62 ++- SubstrateCS/Source/AlphaBlockCollection.cs | 450 ++++++++---------- SubstrateCS/Source/AlphaBlockRef.cs | 47 +- SubstrateCS/Source/BlockInfo.cs | 99 ++-- SubstrateCS/Source/BlockManager.cs | 89 +++- SubstrateCS/Source/Chunk.cs | 48 +- SubstrateCS/Source/Core/BlockInterface.cs | 74 +++ SubstrateCS/Source/Core/BlockTileTicks.cs | 179 +++++++ .../Source/Core/BoundedBlockInterface.cs | 86 ++++ .../Source/Core/UnboundedBlockInterface.cs | 88 +++- SubstrateCS/Source/TileTick.cs | 237 +++++++++ SubstrateCS/Substrate (NET2).csproj | 2 + SubstrateCS/Substrate (NET4).csproj | 2 + 14 files changed, 1163 insertions(+), 304 deletions(-) create mode 100644 SubstrateCS/Source/Core/BlockTileTicks.cs create mode 100644 SubstrateCS/Source/TileTick.cs 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 @@ +