diff --git a/SubstrateCS/Source/AlphaBlockCollection.cs b/SubstrateCS/Source/AlphaBlockCollection.cs
index 4be69a9..054d7c7 100644
--- a/SubstrateCS/Source/AlphaBlockCollection.cs
+++ b/SubstrateCS/Source/AlphaBlockCollection.cs
@@ -17,10 +17,15 @@ namespace Substrate
private readonly int _ydim;
private readonly int _zdim;
- private XZYByteArray _blocks;
- private XZYNibbleArray _data;
- private XZYNibbleArray _blockLight;
- private XZYNibbleArray _skyLight;
+ //private XZYByteArray _blocks;
+ //private XZYNibbleArray _data;
+ //private XZYNibbleArray _blockLight;
+ //private XZYNibbleArray _skyLight;
+ private IDataArray3 _blocks;
+ private IDataArray3 _data;
+ private IDataArray3 _blockLight;
+ private IDataArray3 _skyLight;
+
private ZXByteArray _heightMap;
private TagNodeList _tileEntities;
@@ -71,10 +76,10 @@ namespace Substrate
/// An array of height map values.
/// A list of tile entities corresponding to blocks in this collection.
public AlphaBlockCollection (
- XZYByteArray blocks,
- XZYNibbleArray data,
- XZYNibbleArray blockLight,
- XZYNibbleArray skyLight,
+ IDataArray3 blocks,
+ IDataArray3 data,
+ IDataArray3 blockLight,
+ IDataArray3 skyLight,
ZXByteArray heightMap,
TagNodeList tileEntities)
: this(blocks, data, blockLight, skyLight, heightMap, tileEntities, null)
@@ -92,10 +97,10 @@ namespace Substrate
/// 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,
+ IDataArray3 blocks,
+ IDataArray3 data,
+ IDataArray3 blockLight,
+ IDataArray3 skyLight,
ZXByteArray heightMap,
TagNodeList tileEntities,
TagNodeList tileTicks)
diff --git a/SubstrateCS/Source/AnvilChunk.cs b/SubstrateCS/Source/AnvilChunk.cs
new file mode 100644
index 0000000..292334b
--- /dev/null
+++ b/SubstrateCS/Source/AnvilChunk.cs
@@ -0,0 +1,774 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Substrate.Nbt;
+using Substrate.Core;
+using System.IO;
+
+namespace Substrate.Source
+{
+ public class AnvilSection : INbtObject, ICopyable
+ {
+ public static SchemaNodeCompound SectionSchema = new SchemaNodeCompound()
+ {
+ new SchemaNodeArray("Blocks", 4096),
+ new SchemaNodeArray("Data", 2048),
+ new SchemaNodeArray("SkyLight", 2048),
+ new SchemaNodeArray("BlockLight", 2048),
+ new SchemaNodeScaler("Y", TagType.TAG_INT),
+ new SchemaNodeArray("AddBlocks", 2048, SchemaOptions.OPTIONAL),
+ };
+
+ private const int XDIM = 16;
+ private const int YDIM = 16;
+ private const int ZDIM = 16;
+
+ private const int MIN_Y = 0;
+ private const int MAX_Y = 15;
+
+ private TagNodeCompound _tree;
+
+ private int _y;
+ private YZXByteArray _blocks;
+ private YZXNibbleArray _data;
+ private YZXNibbleArray _blockLight;
+ private YZXNibbleArray _skyLight;
+ private YZXNibbleArray _addBlocks;
+
+ private AnvilSection ()
+ {
+ }
+
+ public AnvilSection (int y)
+ {
+ if (y < MIN_Y || y > MAX_Y)
+ throw new ArgumentOutOfRangeException();
+
+ _y = y;
+ BuildNbtTree();
+ }
+
+ public AnvilSection (TagNodeCompound tree)
+ {
+ LoadTree(_tree);
+ }
+
+ public int Y
+ {
+ get { return _y; }
+ set
+ {
+ if (value < MIN_Y || value > MAX_Y)
+ throw new ArgumentOutOfRangeException();
+
+ _y = value;
+ _tree["Y"].ToTagInt().Data = _y;
+ }
+ }
+
+ public YZXByteArray Blocks
+ {
+ get { return _blocks; }
+ }
+
+ public YZXNibbleArray Data
+ {
+ get { return _data; }
+ }
+
+ public YZXNibbleArray BlockLight
+ {
+ get { return _blockLight; }
+ }
+
+ public YZXNibbleArray SkyLight
+ {
+ get { return _skyLight; }
+ }
+
+ public YZXNibbleArray AddBlocks
+ {
+ get { return _addBlocks; }
+ }
+
+ public bool CheckEmpty ()
+ {
+ return CheckBlocksEmpty() && CheckAddBlocksEmpty();
+ }
+
+ private bool CheckBlocksEmpty ()
+ {
+ for (int i = 0; i < _blocks.Length; i++)
+ if (_blocks[i] != 0)
+ return false;
+ return true;
+ }
+
+ private bool CheckAddBlocksEmpty ()
+ {
+ if (_addBlocks != null)
+ for (int i = 0; i < _addBlocks.Length; i++)
+ if (_addBlocks[i] != 0)
+ return false;
+ return true;
+ }
+
+ #region INbtObject Members
+
+ public AnvilSection LoadTree (TagNode tree)
+ {
+ TagNodeCompound ctree = tree as TagNodeCompound;
+ if (ctree == null) {
+ return null;
+ }
+
+ _y = ctree["Y"] as TagNodeInt;
+
+ _blocks = new YZXByteArray(XDIM, YDIM, ZDIM, ctree["Blocks"] as TagNodeByteArray);
+ _data = new YZXNibbleArray(XDIM, YDIM, ZDIM, ctree["Data"] as TagNodeByteArray);
+ _skyLight = new YZXNibbleArray(XDIM, YDIM, ZDIM, ctree["SkyLight"] as TagNodeByteArray);
+ _blockLight = new YZXNibbleArray(XDIM, YDIM, ZDIM, ctree["BlockLight"] as TagNodeByteArray);
+
+ if (!ctree.ContainsKey("AddBlocks"))
+ _tree["AddBlocks"] = new TagNodeByteArray(new byte[2048]);
+ _addBlocks = new YZXNibbleArray(XDIM, YDIM, ZDIM, ctree["AddBlocks"] as TagNodeByteArray);
+
+ return this;
+ }
+
+ public AnvilSection LoadTreeSafe (TagNode tree)
+ {
+ if (!ValidateTree(tree)) {
+ return null;
+ }
+
+ return LoadTree(tree);
+ }
+
+ public TagNode BuildTree ()
+ {
+ BuildConditional();
+
+ return _tree;
+ }
+
+ public bool ValidateTree (TagNode tree)
+ {
+ NbtVerifier v = new NbtVerifier(tree, SectionSchema);
+ return v.Verify();
+ }
+
+ #endregion
+
+ private void BuildConditional ()
+ {
+ if (CheckAddBlocksEmpty()) {
+ _tree.Remove("AddBlocks");
+ }
+ }
+
+ #region ICopyable Members
+
+ public AnvilSection Copy ()
+ {
+ return new AnvilSection().LoadTree(_tree.Copy());
+ }
+
+ #endregion
+
+ private void BuildNbtTree ()
+ {
+ int elements3 = XDIM * YDIM * ZDIM;
+
+ TagNodeByteArray blocks = new TagNodeByteArray(new byte[elements3]);
+ TagNodeByteArray data = new TagNodeByteArray(new byte[elements3 >> 1]);
+ TagNodeByteArray skyLight = new TagNodeByteArray(new byte[elements3 >> 1]);
+ TagNodeByteArray blockLight = new TagNodeByteArray(new byte[elements3 >> 1]);
+ TagNodeByteArray addBlocks = new TagNodeByteArray(new byte[elements3 >> 1]);
+
+ _blocks = new YZXByteArray(XDIM, YDIM, ZDIM, blocks);
+ _data = new YZXNibbleArray(XDIM, YDIM, ZDIM, data);
+ _skyLight = new YZXNibbleArray(XDIM, YDIM, ZDIM, skyLight);
+ _blockLight = new YZXNibbleArray(XDIM, YDIM, ZDIM, blockLight);
+ _addBlocks = new YZXNibbleArray(XDIM, YDIM, ZDIM, addBlocks);
+
+ TagNodeCompound tree = new TagNodeCompound();
+ tree.Add("Y", new TagNodeInt(_y));
+ tree.Add("Blocks", blocks);
+ tree.Add("Data", data);
+ tree.Add("SkyLight", skyLight);
+ tree.Add("BlockLight", blockLight);
+ tree.Add("AddBlocks", addBlocks);
+
+ _tree = tree;
+ }
+ }
+
+
+
+ public class CompositeYZXByteArray : IDataArray3
+ {
+ private YZXByteArray[] _sections;
+
+ public CompositeYZXByteArray (YZXByteArray[] sections)
+ {
+ for (int i = 0; i < sections.Length; i++)
+ if (sections[i] == null)
+ throw new ArgumentException("sections argument cannot have null entries.");
+
+ for (int i = 0; i < sections.Length; i++) {
+ if (sections[i].Length != sections[0].Length
+ || sections[i].XDim != sections[0].XDim
+ || sections[i].YDim != sections[0].YDim
+ || sections[i].ZDim != sections[0].ZDim)
+ throw new ArgumentException("All elements in sections argument must have same metrics.");
+ }
+
+ _sections = sections;
+ }
+
+ #region IByteArray3 Members
+
+ public byte this[int x, int y, int z]
+ {
+ get
+ {
+ int ydiv = y / _sections[0].YDim;
+ int yrem = y - (ydiv * _sections[0].YDim);
+ return _sections[ydiv][x, yrem, z];
+ }
+
+ set
+ {
+ int ydiv = y / _sections[0].YDim;
+ int yrem = y - (ydiv * _sections[0].YDim);
+ _sections[ydiv][x, yrem, z] = value;
+ }
+ }
+
+ public int XDim
+ {
+ get { return _sections[0].XDim; }
+ }
+
+ public int YDim
+ {
+ get { return _sections[0].YDim; }
+ }
+
+ public int ZDim
+ {
+ get { return _sections[0].ZDim; }
+ }
+
+ public int GetIndex (int x, int y, int z)
+ {
+ int ydiv = y / _sections[0].YDim;
+ int yrem = y - (ydiv * _sections[0].YDim);
+ return ydiv * _sections[ydiv].GetIndex(x, yrem, z);
+ }
+
+ public void GetMultiIndex (int index, out int x, out int y, out int z)
+ {
+ int idiv = index / _sections[0].Length;
+ int irem = index - (idiv * _sections[0].Length);
+ _sections[idiv].GetMultiIndex(irem, out x, out y, out z);
+ }
+
+ #endregion
+
+ #region IByteArray Members
+
+ public byte this[int i]
+ {
+ get
+ {
+ int idiv = i / _sections[0].Length;
+ int irem = i - (idiv * _sections[0].Length);
+ return _sections[idiv][irem];
+ }
+ set
+ {
+ int idiv = i / _sections[0].Length;
+ int irem = i - (idiv * _sections[0].Length);
+ _sections[idiv][irem] = value;
+ }
+ }
+
+ public int Length
+ {
+ get { return _sections[0].Length * _sections.Length; }
+ }
+
+ public void Clear ()
+ {
+ for (int i = 0; i < _sections.Length; i++)
+ _sections[i].Clear();
+ }
+
+ #endregion
+ }
+
+ public class CompositeYZXNibbleArray : IDataArray3
+ {
+ private YZXNibbleArray[] _sections;
+
+ public CompositeYZXNibbleArray (YZXNibbleArray[] sections)
+ {
+ for (int i = 0; i < sections.Length; i++)
+ if (sections[i] == null)
+ throw new ArgumentException("sections argument cannot have null entries.");
+
+ for (int i = 0; i < sections.Length; i++) {
+ if (sections[i].Length != sections[0].Length
+ || sections[i].XDim != sections[0].XDim
+ || sections[i].YDim != sections[0].YDim
+ || sections[i].ZDim != sections[0].ZDim)
+ throw new ArgumentException("All elements in sections argument must have same metrics.");
+ }
+
+ _sections = sections;
+ }
+
+ #region IByteArray3 Members
+
+ public byte this[int x, int y, int z]
+ {
+ get
+ {
+ int ydiv = y / _sections[0].YDim;
+ int yrem = y - (ydiv * _sections[0].YDim);
+ return _sections[ydiv][x, yrem, z];
+ }
+
+ set
+ {
+ int ydiv = y / _sections[0].YDim;
+ int yrem = y - (ydiv * _sections[0].YDim);
+ _sections[ydiv][x, yrem, z] = value;
+ }
+ }
+
+ public int XDim
+ {
+ get { return _sections[0].XDim; }
+ }
+
+ public int YDim
+ {
+ get { return _sections[0].YDim; }
+ }
+
+ public int ZDim
+ {
+ get { return _sections[0].ZDim; }
+ }
+
+ public int GetIndex (int x, int y, int z)
+ {
+ int ydiv = y / _sections[0].YDim;
+ int yrem = y - (ydiv * _sections[0].YDim);
+ return ydiv * _sections[ydiv].GetIndex(x, yrem, z);
+ }
+
+ public void GetMultiIndex (int index, out int x, out int y, out int z)
+ {
+ int idiv = index / _sections[0].Length;
+ int irem = index - (idiv * _sections[0].Length);
+ _sections[idiv].GetMultiIndex(irem, out x, out y, out z);
+ }
+
+ #endregion
+
+ #region IByteArray Members
+
+ public byte this[int i]
+ {
+ get
+ {
+ int idiv = i / _sections[0].Length;
+ int irem = i - (idiv * _sections[0].Length);
+ return _sections[idiv][irem];
+ }
+ set
+ {
+ int idiv = i / _sections[0].Length;
+ int irem = i - (idiv * _sections[0].Length);
+ _sections[idiv][irem] = value;
+ }
+ }
+
+ public int Length
+ {
+ get { return _sections[0].Length * _sections.Length; }
+ }
+
+ public void Clear ()
+ {
+ for (int i = 0; i < _sections.Length; i++)
+ _sections[i].Clear();
+ }
+
+ #endregion
+ }
+
+ public class AnvilChunk : IChunk, INbtObject, ICopyable
+ {
+ public static SchemaNodeCompound LevelSchema = new SchemaNodeCompound()
+ {
+ new SchemaNodeCompound("Level")
+ {
+ new SchemaNodeList("Sections", TagType.TAG_COMPOUND, new SchemaNodeCompound() {
+ new SchemaNodeArray("Blocks", 4096),
+ new SchemaNodeArray("Data", 2048),
+ new SchemaNodeArray("SkyLight", 2048),
+ new SchemaNodeArray("BlockLight", 2048),
+ new SchemaNodeScaler("Y", TagType.TAG_INT),
+ new SchemaNodeArray("AddBlocks", 2048, SchemaOptions.OPTIONAL),
+ }),
+ new SchemaNodeArray("Biomes", 256),
+ new SchemaNodeArray("HeightMap", 256),
+ new SchemaNodeList("Entities", TagType.TAG_COMPOUND, SchemaOptions.CREATE_ON_MISSING),
+ new SchemaNodeList("TileEntities", TagType.TAG_COMPOUND, TileEntity.Schema, SchemaOptions.CREATE_ON_MISSING),
+ new SchemaNodeList("TileTicks", TagType.TAG_COMPOUND, TileTick.Schema, SchemaOptions.OPTIONAL),
+ new SchemaNodeScaler("LastUpdate", TagType.TAG_LONG, SchemaOptions.CREATE_ON_MISSING),
+ new SchemaNodeScaler("xPos", TagType.TAG_INT),
+ new SchemaNodeScaler("zPos", TagType.TAG_INT),
+ new SchemaNodeScaler("TerrainPopulated", TagType.TAG_BYTE, SchemaOptions.CREATE_ON_MISSING),
+ },
+ };
+
+ private const int XDIM = 16;
+ private const int YDIM = 256;
+ private const int ZDIM = 16;
+
+ private NbtTree _tree;
+
+ private int _cx;
+ private int _cz;
+
+ private AnvilSection[] _sections;
+
+ private IDataArray3 _blocks;
+ private IDataArray3 _data;
+ private IDataArray3 _blockLight;
+ private IDataArray3 _skyLight;
+
+ private ZXByteArray _heightMap;
+
+ private TagNodeList _entities;
+ private TagNodeList _tileEntities;
+ private TagNodeList _tileTicks;
+
+ private AlphaBlockCollection _blockManager;
+ private EntityCollection _entityManager;
+
+
+ private AnvilChunk ()
+ {
+ _sections = new AnvilSection[16];
+ }
+
+ public int X
+ {
+ get { return _cx; }
+ }
+
+ public int Z
+ {
+ get { return _cz; }
+ }
+
+ public AlphaBlockCollection Blocks
+ {
+ get { return _blockManager; }
+ }
+
+ public EntityCollection Entities
+ {
+ get { return _entityManager; }
+ }
+
+ public NbtTree Tree
+ {
+ get { return _tree; }
+ }
+
+ public bool IsTerrainPopulated
+ {
+ get { return _tree.Root["Level"].ToTagCompound()["TerrainPopulated"].ToTagByte() == 1; }
+ set { _tree.Root["Level"].ToTagCompound()["TerrainPopulated"].ToTagByte().Data = (byte)(value ? 1 : 0); }
+ }
+
+ public static AnvilChunk Create (int x, int z)
+ {
+ AnvilChunk c = new AnvilChunk();
+
+ c._cx = x;
+ c._cz = z;
+
+ c.BuildNBTTree();
+ return c;
+ }
+
+ public static AnvilChunk Create (NbtTree tree)
+ {
+ AnvilChunk c = new AnvilChunk();
+
+ return c.LoadTree(tree.Root);
+ }
+
+ public static AnvilChunk CreateVerified (NbtTree tree)
+ {
+ AnvilChunk c = new AnvilChunk();
+
+ return c.LoadTreeSafe(tree.Root);
+ }
+
+ ///
+ /// Updates the chunk's global world coordinates.
+ ///
+ /// Global X-coordinate.
+ /// Global Z-coordinate.
+ public virtual void SetLocation (int x, int z)
+ {
+ int diffx = (x - _cx) * XDIM;
+ int diffz = (z - _cz) * ZDIM;
+
+ // Update chunk position
+
+ _cx = x;
+ _cz = z;
+
+ _tree.Root["Level"].ToTagCompound()["xPos"].ToTagInt().Data = x;
+ _tree.Root["Level"].ToTagCompound()["zPos"].ToTagInt().Data = z;
+
+ // Update tile entity coordinates
+
+ List tileEntites = new List();
+ foreach (TagNodeCompound tag in _tileEntities) {
+ TileEntity te = TileEntityFactory.Create(tag);
+ if (te == null) {
+ te = TileEntity.FromTreeSafe(tag);
+ }
+
+ if (te != null) {
+ te.MoveBy(diffx, 0, diffz);
+ tileEntites.Add(te);
+ }
+ }
+
+ _tileEntities.Clear();
+ foreach (TileEntity te in tileEntites) {
+ _tileEntities.Add(te.BuildTree());
+ }
+
+ // Update tile tick coordinates
+
+ if (_tileTicks != null) {
+ List tileTicks = new List();
+ foreach (TagNodeCompound tag in _tileTicks) {
+ TileTick tt = TileTick.FromTreeSafe(tag);
+
+ if (tt != null) {
+ tt.MoveBy(diffx, 0, diffz);
+ tileTicks.Add(tt);
+ }
+ }
+
+ _tileTicks.Clear();
+ foreach (TileTick tt in tileTicks) {
+ _tileTicks.Add(tt.BuildTree());
+ }
+ }
+
+ // Update entity coordinates
+
+ List entities = new List();
+ foreach (TypedEntity entity in _entityManager) {
+ entity.MoveBy(diffx, 0, diffz);
+ entities.Add(entity);
+ }
+
+ _entities.Clear();
+ foreach (TypedEntity entity in entities) {
+ _entityManager.Add(entity);
+ }
+ }
+
+ public bool Save (Stream outStream)
+ {
+ if (outStream == null || !outStream.CanWrite) {
+ return false;
+ }
+
+ BuildConditional();
+
+ _tree.WriteTo(outStream);
+ outStream.Close();
+
+ return true;
+ }
+
+ #region INbtObject Members
+
+ public AnvilChunk LoadTree (TagNode tree)
+ {
+ TagNodeCompound ctree = tree as TagNodeCompound;
+ if (ctree == null) {
+ return null;
+ }
+
+ _tree = new NbtTree(ctree);
+
+ TagNodeCompound level = _tree.Root["Level"] as TagNodeCompound;
+
+ TagNodeCompound sections = level["Sections"] as TagNodeCompound;
+ foreach (TagNodeCompound section in sections.Values) {
+ AnvilSection anvilSection = new AnvilSection(section);
+ if (anvilSection.Y < 0 || anvilSection.Y >= _sections.Length)
+ continue;
+ _sections[anvilSection.Y] = anvilSection;
+ }
+
+ YZXByteArray[] blocksBA = new YZXByteArray[_sections.Length];
+ YZXNibbleArray[] dataBA = new YZXNibbleArray[_sections.Length];
+ YZXNibbleArray[] skyLightBA = new YZXNibbleArray[_sections.Length];
+ YZXNibbleArray[] blockLightBA = new YZXNibbleArray[_sections.Length];
+
+ for (int i = 0; i < _sections.Length; i++) {
+ if (_sections[i] == null)
+ _sections[i] = new AnvilSection(i);
+
+ blocksBA[i] = _sections[i].Blocks;
+ dataBA[i] = _sections[i].Data;
+ skyLightBA[i] = _sections[i].SkyLight;
+ blockLightBA[i] = _sections[i].BlockLight;
+ }
+
+ _blocks = new CompositeYZXByteArray(blocksBA);
+ _data = new CompositeYZXNibbleArray(dataBA);
+ _skyLight = new CompositeYZXNibbleArray(skyLightBA);
+ _blockLight = new CompositeYZXNibbleArray(blockLightBA);
+
+ _heightMap = new ZXByteArray(XDIM, ZDIM, level["HeightMap"] as TagNodeByteArray);
+
+ _entities = level["Entities"] as TagNodeList;
+ _tileEntities = level["TileEntities"] as TagNodeList;
+
+ if (level.ContainsKey("TileTicks"))
+ _tileTicks = level["TileTicks"] as TagNodeList;
+ else
+ _tileTicks = new TagNodeList(TagType.TAG_COMPOUND);
+
+ // List-type patch up
+ if (_entities.Count == 0) {
+ level["Entities"] = new TagNodeList(TagType.TAG_COMPOUND);
+ _entities = level["Entities"] as TagNodeList;
+ }
+
+ if (_tileEntities.Count == 0) {
+ level["TileEntities"] = new TagNodeList(TagType.TAG_COMPOUND);
+ _tileEntities = level["TileEntities"] as TagNodeList;
+ }
+
+ if (_tileTicks.Count == 0) {
+ level["TileTicks"] = new TagNodeList(TagType.TAG_COMPOUND);
+ _tileTicks = level["TileTicks"] as TagNodeList;
+ }
+
+ _cx = level["xPos"].ToTagInt();
+ _cz = level["zPos"].ToTagInt();
+
+ _blockManager = new AlphaBlockCollection(_blocks, _data, _blockLight, _skyLight, _heightMap, _tileEntities, _tileTicks);
+ _entityManager = new EntityCollection(_entities);
+
+ return this;
+ }
+
+ public AnvilChunk LoadTreeSafe (TagNode tree)
+ {
+ if (!ValidateTree(tree)) {
+ return null;
+ }
+
+ return LoadTree(tree);
+ }
+
+ public TagNode BuildTree ()
+ {
+ BuildConditional();
+
+ return _tree.Root;
+ }
+
+ public bool ValidateTree (TagNode tree)
+ {
+ NbtVerifier v = new NbtVerifier(tree, LevelSchema);
+ return v.Verify();
+ }
+
+ #endregion
+
+ #region ICopyable Members
+
+ public AnvilChunk Copy ()
+ {
+ return AnvilChunk.Create(_tree.Copy());
+ }
+
+ #endregion
+
+ private void BuildConditional ()
+ {
+ TagNodeCompound level = _tree.Root["Level"] as TagNodeCompound;
+ if (_tileTicks != _blockManager.TileTicks && _blockManager.TileTicks.Count > 0) {
+ _tileTicks = _blockManager.TileTicks;
+ level["TileTicks"] = _tileTicks;
+ }
+ }
+
+ private void BuildNBTTree ()
+ {
+ int elements2 = XDIM * ZDIM;
+
+ _sections = new AnvilSection[16];
+ TagNodeList sections = new TagNodeList(TagType.TAG_COMPOUND);
+
+ for (int i = 0; i < _sections.Length; i++) {
+ _sections[i] = new AnvilSection(i);
+ sections.Add(_sections[i].BuildTree());
+ }
+
+ TagNodeByteArray heightMap = new TagNodeByteArray(new byte[elements2]);
+ _heightMap = new ZXByteArray(XDIM, ZDIM, heightMap);
+
+ _entities = new TagNodeList(TagType.TAG_COMPOUND);
+ _tileEntities = new TagNodeList(TagType.TAG_COMPOUND);
+ _tileTicks = new TagNodeList(TagType.TAG_COMPOUND);
+
+ TagNodeCompound level = new TagNodeCompound();
+ level.Add("Sections", sections);
+ level.Add("HeightMap", heightMap);
+ level.Add("Entities", _entities);
+ level.Add("TileEntities", _tileEntities);
+ level.Add("TileTicks", _tileTicks);
+ level.Add("LastUpdate", new TagNodeLong(Timestamp()));
+ level.Add("xPos", new TagNodeInt(_cx));
+ level.Add("zPos", new TagNodeInt(_cz));
+ level.Add("TerrainPopulated", new TagNodeByte());
+
+ _tree = new NbtTree();
+ _tree.Root.Add("Level", level);
+
+ _blockManager = new AlphaBlockCollection(_blocks, _data, _blockLight, _skyLight, _heightMap, _tileEntities);
+ _entityManager = new EntityCollection(_entities);
+ }
+
+ private int Timestamp ()
+ {
+ DateTime epoch = new DateTime(1970, 1, 1, 0, 0, 0, 0);
+ return (int)((DateTime.UtcNow - epoch).Ticks / (10000L * 1000L));
+ }
+ }
+}
diff --git a/SubstrateCS/Source/Core/BlockFluid.cs b/SubstrateCS/Source/Core/BlockFluid.cs
index ce14ca8..f8f721d 100644
--- a/SubstrateCS/Source/Core/BlockFluid.cs
+++ b/SubstrateCS/Source/Core/BlockFluid.cs
@@ -62,7 +62,7 @@ namespace Substrate.Core
_chunks = new Dictionary();
}
- public void ResetWater (ByteArray blocks, NibbleArray data)
+ public void ResetWater (IDataArray blocks, IDataArray data)
{
for (int i = 0; i < blocks.Length; i++) {
if ((blocks[i] == BlockInfo.StationaryWater.ID || blocks[i] == BlockInfo.Water.ID) && data[i] != 0) {
@@ -75,7 +75,7 @@ namespace Substrate.Core
}
}
- public void ResetLava (ByteArray blocks, NibbleArray data)
+ public void ResetLava (IDataArray blocks, IDataArray data)
{
for (int i = 0; i < blocks.Length; i++) {
if ((blocks[i] == BlockInfo.StationaryLava.ID || blocks[i] == BlockInfo.Lava.ID) && data[i] != 0) {
diff --git a/SubstrateCS/Source/Core/BlockTileEntities.cs b/SubstrateCS/Source/Core/BlockTileEntities.cs
index 4bdb7f2..4876da6 100644
--- a/SubstrateCS/Source/Core/BlockTileEntities.cs
+++ b/SubstrateCS/Source/Core/BlockTileEntities.cs
@@ -8,14 +8,14 @@ namespace Substrate.Core
public class BlockTileEntities
{
- private XZYByteArray _blocks;
+ private IDataArray3 _blocks;
private TagNodeList _tileEntities;
private Dictionary _tileEntityTable;
public event BlockCoordinateHandler TranslateCoordinates;
- public BlockTileEntities (XZYByteArray blocks, TagNodeList tileEntities)
+ public BlockTileEntities (IDataArray3 blocks, TagNodeList tileEntities)
{
_blocks = blocks;
_tileEntities = tileEntities;
diff --git a/SubstrateCS/Source/Core/BlockTileTicks.cs b/SubstrateCS/Source/Core/BlockTileTicks.cs
index b592d56..7102c62 100644
--- a/SubstrateCS/Source/Core/BlockTileTicks.cs
+++ b/SubstrateCS/Source/Core/BlockTileTicks.cs
@@ -6,14 +6,14 @@ namespace Substrate.Core
{
public class BlockTileTicks
{
- private XZYByteArray _blocks;
+ private IDataArray3 _blocks;
private TagNodeList _tileTicks;
private Dictionary _tileTickTable;
public event BlockCoordinateHandler TranslateCoordinates;
- public BlockTileTicks (XZYByteArray blocks, TagNodeList tileTicks)
+ public BlockTileTicks (IDataArray3 blocks, TagNodeList tileTicks)
{
_blocks = blocks;
_tileTicks = tileTicks;
diff --git a/SubstrateCS/Source/Core/ByteArray.cs b/SubstrateCS/Source/Core/ByteArray.cs
index fc47e13..7bccd17 100644
--- a/SubstrateCS/Source/Core/ByteArray.cs
+++ b/SubstrateCS/Source/Core/ByteArray.cs
@@ -4,7 +4,27 @@ using System.Collections.Generic;
namespace Substrate.Core
{
- public class ByteArray : ICopyable
+ public interface IDataArray
+ {
+ byte this[int i] { get; set; }
+ int Length { get; }
+
+ void Clear ();
+ }
+
+ public interface IDataArray3 : IDataArray
+ {
+ byte this[int x, int y, int z] { get; set; }
+
+ int XDim { get; }
+ int YDim { get; }
+ int ZDim { get; }
+
+ int GetIndex (int x, int y, int z);
+ void GetMultiIndex (int index, out int x, out int y, out int z);
+ }
+
+ public class ByteArray : IDataArray, ICopyable
{
protected readonly byte[] dataArray;
@@ -37,7 +57,7 @@ namespace Substrate.Core
}
}
- #region ICopyable Members
+ #region ICopyable Members
public virtual ByteArray Copy ()
{
@@ -50,7 +70,7 @@ namespace Substrate.Core
#endregion
}
- public sealed class XZYByteArray : ByteArray
+ public sealed class XZYByteArray : ByteArray, IDataArray3
{
private readonly int _xdim;
private readonly int _ydim;
@@ -135,7 +155,7 @@ namespace Substrate.Core
#endregion
}
- public sealed class YZXByteArray : ByteArray
+ public sealed class YZXByteArray : ByteArray, IDataArray3
{
private readonly int _xdim;
private readonly int _ydim;
diff --git a/SubstrateCS/Source/Core/NibbleArray.cs b/SubstrateCS/Source/Core/NibbleArray.cs
index 4f41f22..14a7af7 100644
--- a/SubstrateCS/Source/Core/NibbleArray.cs
+++ b/SubstrateCS/Source/Core/NibbleArray.cs
@@ -5,7 +5,7 @@ using System.Collections.Generic;
namespace Substrate.Core
{
- public class NibbleArray : ICopyable
+ public class NibbleArray : IDataArray, ICopyable
{
private readonly byte[] _data = null;
@@ -82,7 +82,7 @@ namespace Substrate.Core
#endregion
}
- public sealed class XZYNibbleArray : NibbleArray
+ public sealed class XZYNibbleArray : NibbleArray, IDataArray3
{
private readonly int _xdim;
private readonly int _ydim;
@@ -139,6 +139,21 @@ namespace Substrate.Core
get { return _zdim; }
}
+ public int GetIndex (int x, int y, int z)
+ {
+ return _ydim * (x * _zdim + z) + y;
+ }
+
+ public void GetMultiIndex (int index, out int x, out int y, out int z)
+ {
+ int yzdim = _ydim * _zdim;
+ x = index / yzdim;
+
+ int zy = index - (x * yzdim);
+ z = zy / _ydim;
+ y = zy - (z * _ydim);
+ }
+
#region ICopyable Members
public override NibbleArray Copy ()
@@ -152,7 +167,7 @@ namespace Substrate.Core
#endregion
}
- public sealed class YZXNibbleArray : NibbleArray
+ public sealed class YZXNibbleArray : NibbleArray, IDataArray3
{
private readonly int _xdim;
private readonly int _ydim;
@@ -208,6 +223,21 @@ namespace Substrate.Core
get { return _zdim; }
}
+ public int GetIndex (int x, int y, int z)
+ {
+ return _xdim * (y * _zdim + z) + x;
+ }
+
+ public void GetMultiIndex (int index, out int x, out int y, out int z)
+ {
+ int xzdim = _xdim * _zdim;
+ y = index / xzdim;
+
+ int zx = index - (y * xzdim);
+ z = zx / _xdim;
+ x = zx - (z * _xdim);
+ }
+
#region ICopyable Members
public override NibbleArray Copy ()