Updated Info classes, updated and documented Player classes.

This commit is contained in:
Justin Aquadro 2011-07-02 03:51:48 +00:00
parent ace319793a
commit 3387386295
18 changed files with 711 additions and 111 deletions

View file

@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
// Build Number // Build Number
// Revision // Revision
// //
[assembly: AssemblyVersion("0.6.1.0")] [assembly: AssemblyVersion("0.7.0.0")]
[assembly: AssemblyFileVersion("0.6.1.0")] [assembly: AssemblyFileVersion("0.7.0.0")]

View file

@ -122,11 +122,11 @@ namespace Substrate
public const int MAX_LUMINANCE = 15; public const int MAX_LUMINANCE = 15;
public const int MIN_LUMINANCE = 0; public const int MIN_LUMINANCE = 0;
private static BlockInfo[] _blockTable; private static readonly BlockInfo[] _blockTable;
private static int[] _opacityTable; private static readonly int[] _opacityTable;
private static int[] _luminanceTable; private static readonly int[] _luminanceTable;
public class ItemCache<T> private class CacheTableArray<T> : ICacheTable<T>
{ {
private T[] _cache; private T[] _cache;
@ -135,7 +135,7 @@ namespace Substrate
get { return _cache[index]; } get { return _cache[index]; }
} }
public ItemCache (T[] cache) public CacheTableArray (T[] cache)
{ {
_cache = cache; _cache = cache;
} }
@ -182,18 +182,30 @@ namespace Substrate
private int _luminance = MIN_LUMINANCE; private int _luminance = MIN_LUMINANCE;
private bool _transmitLight = false; private bool _transmitLight = false;
private bool _blocksFluid = true; private bool _blocksFluid = true;
private bool _registered = false;
private BlockState _state = BlockState.SOLID; private BlockState _state = BlockState.SOLID;
private DataLimits _dataLimits; private DataLimits _dataLimits;
public static ItemCache<BlockInfo> BlockTable; private static readonly CacheTableArray<BlockInfo> _blockTableCache;
private static readonly CacheTableArray<int> _opacityTableCache;
private static readonly CacheTableArray<int> _luminanceTableCache;
public static ItemCache<int> OpacityTable; public static ICacheTable<BlockInfo> BlockTable
{
get { return _blockTableCache; }
}
public static ItemCache<int> LuminanceTable; public static ICacheTable<int> OpacityTable
{
get { return _opacityTableCache; }
}
//public static ItemCache<NBTCompoundNode> SchemaTable; public static ICacheTable<int> LuminanceTable
{
get { return _luminanceTableCache; }
}
public int ID public int ID
{ {
@ -235,9 +247,15 @@ namespace Substrate
get { return _state; } get { return _state; }
} }
public BlockInfo (int id) public bool Registered
{
get { return _registered; }
}
internal BlockInfo (int id)
{ {
_id = id; _id = id;
_name = "Unknown Block";
_blockTable[_id] = this; _blockTable[_id] = this;
} }
@ -246,6 +264,7 @@ namespace Substrate
_id = id; _id = id;
_name = name; _name = name;
_blockTable[_id] = this; _blockTable[_id] = this;
_registered = true;
} }
public BlockInfo SetOpacity (int opacity) public BlockInfo SetOpacity (int opacity)
@ -413,9 +432,9 @@ namespace Substrate
_opacityTable = new int[MAX_BLOCKS]; _opacityTable = new int[MAX_BLOCKS];
_luminanceTable = new int[MAX_BLOCKS]; _luminanceTable = new int[MAX_BLOCKS];
BlockTable = new ItemCache<BlockInfo>(_blockTable); _blockTableCache = new CacheTableArray<BlockInfo>(_blockTable);
OpacityTable = new ItemCache<int>(_opacityTable); _opacityTableCache = new CacheTableArray<int>(_opacityTable);
LuminanceTable = new ItemCache<int>(_luminanceTable); _luminanceTableCache = new CacheTableArray<int>(_luminanceTable);
Air = new BlockInfo(0, "Air").SetOpacity(0).SetState(BlockState.NONSOLID); Air = new BlockInfo(0, "Air").SetOpacity(0).SetState(BlockState.NONSOLID);
Stone = new BlockInfo(1, "Stone"); Stone = new BlockInfo(1, "Stone");
@ -516,7 +535,7 @@ namespace Substrate
for (int i = 0; i < MAX_BLOCKS; i++) { for (int i = 0; i < MAX_BLOCKS; i++) {
if (_blockTable[i] == null) { if (_blockTable[i] == null) {
_blockTable[i] = new BlockInfo(i, "Uknown Block"); _blockTable[i] = new BlockInfo(i);
} }
} }

View file

@ -25,6 +25,7 @@ namespace Substrate
protected IChunkManager _chunkMan; protected IChunkManager _chunkMan;
protected ChunkRef _cache; protected ChunkRef _cache;
protected AlphaBlockCollection _blocks;
private bool _autoLight = true; private bool _autoLight = true;
private bool _autoFluid = false; private bool _autoFluid = false;

View file

@ -0,0 +1,84 @@
using System;
using System.Collections.Generic;
namespace Substrate
{
/// <summary>
/// Provides read-only indexed access to an underlying resource.
/// </summary>
/// <typeparam name="T">The type of the underlying resource.</typeparam>
public interface ICacheTable<T>
{
/// <summary>
/// Gets the value at the given index.
/// </summary>
/// <param name="index">The index to fetch.</param>
T this[int index] { get; }
}
/*internal class CacheTableArray<T> : ICacheTable<T>
{
private T[] _cache;
public T this[int index]
{
get { return _cache[index]; }
}
public CacheTableArray (T[] cache)
{
_cache = cache;
}
}
internal class CacheTableDictionary<T> : ICacheTable<T>
{
private Dictionary<int, T> _cache;
private static Random _rand = new Random();
public T this[int index]
{
get
{
T val;
if (_cache.TryGetValue(index, out val)) {
return val;
}
return default(T);
}
}
public CacheTableDictionary (Dictionary<int, T> cache)
{
_cache = cache;
}
}
/// <summary>
/// Provides read-only indexed access to an underlying resource.
/// </summary>
/// <typeparam name="T">The type of the underlying resource.</typeparam>
public class CacheTable<T>
{
ICacheTable<T> _cache;
/// <summary>
/// Gets the value at the given index.
/// </summary>
/// <param name="index"></param>
public T this[int index]
{
get { return _cache[index]; }
}
internal CacheTable (T[] cache)
{
_cache = new CacheTableArray<T>(cache);
}
internal CacheTable (Dictionary<int, T> cache)
{
_cache = new CacheTableDictionary<T>(cache);
}
}*/
}

View file

@ -262,7 +262,7 @@ namespace Substrate
public IEnumerator<ChunkRef> GetEnumerator () public IEnumerator<ChunkRef> GetEnumerator ()
{ {
return new ChunkEnumerator(this); return new Enumerator(this);
} }
#endregion #endregion
@ -272,13 +272,13 @@ namespace Substrate
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator () System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator ()
{ {
return new ChunkEnumerator(this); return new Enumerator(this);
} }
#endregion #endregion
public class ChunkEnumerator : IEnumerator<ChunkRef> private class Enumerator : IEnumerator<ChunkRef>
{ {
private ChunkManager _cm; private ChunkManager _cm;
@ -289,7 +289,7 @@ namespace Substrate
private int _x = 0; private int _x = 0;
private int _z = -1; private int _z = -1;
public ChunkEnumerator (ChunkManager cm) public Enumerator (ChunkManager cm)
{ {
_cm = cm; _cm = cm;
_enum = _cm.GetRegionManager().GetEnumerator(); _enum = _cm.GetRegionManager().GetEnumerator();

View file

@ -21,30 +21,39 @@ namespace Substrate.Core
return File.Exists(_filename); return File.Exists(_filename);
} }
public bool Delete () public void Delete ()
{ {
File.Delete(_filename); File.Delete(_filename);
return true;
} }
public virtual Stream GetDataInputStream () public virtual Stream GetDataInputStream ()
{ {
FileStream fstr = new FileStream(_filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); try {
FileStream fstr = new FileStream(_filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
long length = fstr.Seek(0, SeekOrigin.End); long length = fstr.Seek(0, SeekOrigin.End);
fstr.Seek(0, SeekOrigin.Begin); fstr.Seek(0, SeekOrigin.Begin);
byte[] data = new byte[length]; byte[] data = new byte[length];
fstr.Read(data, 0, data.Length); fstr.Read(data, 0, data.Length);
fstr.Close(); fstr.Close();
return new GZipStream(new MemoryStream(data), CompressionMode.Decompress); return new GZipStream(new MemoryStream(data), CompressionMode.Decompress);
}
catch (Exception ex) {
throw new NbtIOException("Failed to open compressed NBT data stream for input.", ex);
}
} }
public virtual Stream GetDataOutputStream () public virtual Stream GetDataOutputStream ()
{ {
return new GZipStream(new NBTBuffer(this), CompressionMode.Compress); try {
return new GZipStream(new NBTBuffer(this), CompressionMode.Compress);
}
catch (Exception ex) {
throw new NbtIOException("Failed to initialize compressed NBT data stream for output.", ex);
}
} }
class NBTBuffer : MemoryStream class NBTBuffer : MemoryStream
@ -59,9 +68,21 @@ namespace Substrate.Core
public override void Close () public override void Close ()
{ {
FileStream fstr = new FileStream(file._filename, FileMode.Create, FileAccess.Write, FileShare.ReadWrite); FileStream fstr;
fstr.Write(this.GetBuffer(), 0, (int)this.Length); try {
fstr.Close(); fstr = new FileStream(file._filename, FileMode.Create, FileAccess.Write, FileShare.ReadWrite);
}
catch (Exception ex) {
throw new NbtIOException("Failed to open NBT data stream for output.", ex);
}
try {
fstr.Write(this.GetBuffer(), 0, (int)this.Length);
fstr.Close();
}
catch (Exception ex) {
throw new NbtIOException("Failed to write out NBT data stream.", ex);
}
} }
} }

View file

@ -0,0 +1,39 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Substrate.Core
{
/// <summary>
/// An interface of basic manipulations on an abstract data store for player data.
/// </summary>
public interface IPlayerManager
{
/// <summary>
/// Gets a <see cref="Player"/> object for the given player from the underlying data store.
/// </summary>
/// <param name="name">The name of the player to fetch.</param>
/// <returns>A <see cref="Player"/> object for the given player, or null if the player could not be found.</returns>
Player GetPlayer (string name);
/// <summary>
/// Saves a <see cref="Player"/> object's data back to the underlying data store for the given player.
/// </summary>
/// <param name="name">The name of the player to write back data for.</param>
/// <param name="player">The <see cref="Player"/> object containing data to write back.</param>
void SetPlayer (string name, Player player);
/// <summary>
/// Checks if a player exists in the underlying data store.
/// </summary>
/// <param name="name">The name of the player to look up.</param>
/// <returns>True if player data was found; false otherwise.</returns>
bool PlayerExists (string name);
/// <summary>
/// Deletes a player with the given name from the underlying data store.
/// </summary>
/// <param name="name">The name of the player to delete.</param>
void DeletePlayer (string name);
}
}

View file

@ -77,7 +77,7 @@ namespace Substrate
} }
/// <summary> /// <summary>
/// Gets or sets the reamining air availale to the entity. /// Gets or sets the remaining air availale to the entity.
/// </summary> /// </summary>
public int Air public int Air
{ {
@ -108,7 +108,7 @@ namespace Substrate
/// Constructs a new generic <see cref="Entity"/> by copying fields from another <see cref="Entity"/> object. /// Constructs a new generic <see cref="Entity"/> by copying fields from another <see cref="Entity"/> object.
/// </summary> /// </summary>
/// <param name="e">An <see cref="Entity"/> to copy fields from.</param> /// <param name="e">An <see cref="Entity"/> to copy fields from.</param>
public Entity (Entity e) protected Entity (Entity e)
{ {
_pos = new Vector3(); _pos = new Vector3();
_pos.X = e._pos.X; _pos.X = e._pos.X;
@ -288,7 +288,7 @@ namespace Substrate
/// Constructs a new <see cref="EntityTyped"/> by copying an existing one. /// Constructs a new <see cref="EntityTyped"/> by copying an existing one.
/// </summary> /// </summary>
/// <param name="e">The <see cref="EntityTyped"/> to copy.</param> /// <param name="e">The <see cref="EntityTyped"/> to copy.</param>
public EntityTyped (EntityTyped e) protected EntityTyped (EntityTyped e)
: base(e) : base(e)
{ {
_id = e._id; _id = e._id;

View file

@ -1,28 +1,42 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.Text;
using Substrate.Nbt;
namespace Substrate namespace Substrate
{ {
using Nbt; /// <summary>
/// Functions to query and manage a collection of entities.
/// </summary>
public class EntityCollection : IEnumerable<EntityTyped> public class EntityCollection : IEnumerable<EntityTyped>
{ {
private TagNodeList _entities; private TagNodeList _entities;
private bool _dirty; private bool _dirty;
/// <summary>
/// Gets or sets a value indicating whether this collection contains unsaved changes.
/// </summary>
public bool IsDirty public bool IsDirty
{ {
get { return _dirty; } get { return _dirty; }
set { _dirty = value; } set { _dirty = value; }
} }
/// <summary>
/// Creates a new <see cref="EntityCollection"/> around a <see cref="TagNodeList"/> containing Entity nodes.
/// </summary>
/// <param name="entities">A <see cref="TagNodeList"/> containing Entity nodes.</param>
public EntityCollection (TagNodeList entities) public EntityCollection (TagNodeList entities)
{ {
_entities = entities; _entities = entities;
} }
/// <summary>
/// Gets a list of all entities in the collection that match a given id (type).
/// </summary>
/// <param name="id">The id (type) of entities that should be returned.</param>
/// <returns>A list of <see cref="EntityTyped"/> objects matching the given id (type).</returns>
public List<EntityTyped> FindAll (string id) public List<EntityTyped> FindAll (string id)
{ {
List<EntityTyped> set = new List<EntityTyped>(); List<EntityTyped> set = new List<EntityTyped>();
@ -46,6 +60,11 @@ namespace Substrate
return set; return set;
} }
/// <summary>
/// Gets a list of all entities in the collection that match a given condition.
/// </summary>
/// <param name="match">A <see cref="Predicate{T}"/> defining the matching condition.</param>
/// <returns>A list of <see cref="EntityTyped"/> objects matching the given condition.</returns>
public List<EntityTyped> FindAll (Predicate<EntityTyped> match) public List<EntityTyped> FindAll (Predicate<EntityTyped> match)
{ {
List<EntityTyped> set = new List<EntityTyped>(); List<EntityTyped> set = new List<EntityTyped>();
@ -64,24 +83,25 @@ namespace Substrate
return set; return set;
} }
public bool Add (EntityTyped ent) /// <summary>
/// Adds a <see cref="EntityTyped"/> to the collection.
/// </summary>
/// <param name="ent">The <see cref="EntityTyped"/> object to add.</param>
/// <remarks>It is up to the developer to ensure that the <see cref="EntityTyped"/> being added to the collection has a position that
/// is within acceptable range of the collection. <see cref="EntityCollection"/> transparently back other objects such as
/// <see cref="Chunk"/> objects, which have a well-defined position in global space. The <see cref="EntityCollection"/> itself has
/// no concept of position and will not enforce constraints on the positions of <see cref="EntityTyped"/> objects being added.</remarks>
public void Add (EntityTyped ent)
{ {
/*double xlow = _cx * XDim;
double xhigh = xlow + XDim;
double zlow = _cz * ZDim;
double zhigh = zlow + ZDim;
Entity.Vector3 pos = ent.Position;
if (!(pos.X >= xlow && pos.X < xhigh && pos.Z >= zlow && pos.Z < zhigh)) {
return false;
}*/
_entities.Add(ent.BuildTree()); _entities.Add(ent.BuildTree());
_dirty = true; _dirty = true;
return true;
} }
/// <summary>
/// Removes all entities matching the given id (type) from the collection.
/// </summary>
/// <param name="id">The id (type) of entities that should be removed.</param>
/// <returns>A count of the number of entities that were removed.</returns>
public int RemoveAll (string id) public int RemoveAll (string id)
{ {
int rem = _entities.RemoveAll(val => int rem = _entities.RemoveAll(val =>
@ -106,6 +126,11 @@ namespace Substrate
return rem; return rem;
} }
/// <summary>
/// Removes all entities matching the given condition from the collection.
/// </summary>
/// <param name="match">A <see cref="Predicate{T}"/> defining the matching condition.</param>
/// <returns>A count of the number of entities that were removed.</returns>
public int RemoveAll (Predicate<EntityTyped> match) public int RemoveAll (Predicate<EntityTyped> match)
{ {
int rem = _entities.RemoveAll(val => int rem = _entities.RemoveAll(val =>
@ -132,35 +157,50 @@ namespace Substrate
#region IEnumerable<Entity> Members #region IEnumerable<Entity> Members
/// <summary>
/// Returns an enumerator that iterates through all entities.
/// </summary>
/// <returns>An <see cref="Enumerator"/> for this object.</returns>
public IEnumerator<EntityTyped> GetEnumerator () public IEnumerator<EntityTyped> GetEnumerator ()
{ {
return new EntityEnumerator(_entities); return new Enumerator(_entities);
} }
#endregion #endregion
#region IEnumerable Members #region IEnumerable Members
/// <summary>
/// Returns an enumerator that iterates through all entities.
/// </summary>
/// <returns>An <see cref="Enumerator"/> for this object.</returns>
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator () System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator ()
{ {
return new EntityEnumerator(_entities); return new Enumerator(_entities);
} }
#endregion #endregion
public class EntityEnumerator : IEnumerator<EntityTyped> /// <summary>
/// Enumerates the entities within an <see cref="EntityCollection"/>.
/// </summary>
private struct Enumerator : IEnumerator<EntityTyped>
{ {
private IEnumerator<TagNode> _enum; private IEnumerator<TagNode> _enum;
private EntityTyped _cur; private EntityTyped _cur;
public EntityEnumerator (TagNodeList entities) internal Enumerator (TagNodeList entities)
{ {
_enum = entities.GetEnumerator(); _enum = entities.GetEnumerator();
_cur = null;
} }
#region IEnumerator<Entity> Members #region IEnumerator<Entity> Members
/// <summary>
/// Gets the <see cref="EntityTyped"/> at the current position of the enumerator.
/// </summary>
public EntityTyped Current public EntityTyped Current
{ {
get get
@ -176,17 +216,27 @@ namespace Substrate
#region IDisposable Members #region IDisposable Members
/// <summary>
/// Releases all resources used by the <see cref="Enumerator"/>.
/// </summary>
public void Dispose () { } public void Dispose () { }
#endregion #endregion
#region IEnumerator Members #region IEnumerator Members
/// <summary>
/// Gets the <see cref="EntityTyped"/> at the current position of the enumerator.
/// </summary>
object System.Collections.IEnumerator.Current object System.Collections.IEnumerator.Current
{ {
get { return Current; } get { return Current; }
} }
/// <summary>
/// Advances the enumerator to the next <see cref="EntityTyped"/> in the <see cref="EntityCollection"/>.
/// </summary>
/// <returns>True if the enumerator was successfully advanced to the next position; false if the enumerator advanced past the end of the collection.</returns>
public bool MoveNext () public bool MoveNext ()
{ {
if (!_enum.MoveNext()) { if (!_enum.MoveNext()) {
@ -197,7 +247,10 @@ namespace Substrate
return true; return true;
} }
public void Reset () /// <summary>
/// Sets the enumerator to its initial position, which is before the first <see cref="EntityTyped"/> in the collection.
/// </summary>
void System.Collections.IEnumerator.Reset ()
{ {
_cur = null; _cur = null;
_enum.Reset(); _enum.Reset();

View file

@ -118,10 +118,11 @@ namespace Substrate
public class ItemInfo public class ItemInfo
{ {
public class ItemCache<T> private static Random _rand = new Random();
private class CacheTableDict<T> : ICacheTable<T>
{ {
private Dictionary<int, T> _cache; private Dictionary<int, T> _cache;
private static Random _rand = new Random();
public T this[int index] public T this[int index]
{ {
@ -135,25 +136,24 @@ namespace Substrate
} }
} }
public ItemCache (Dictionary<int, T> cache) public CacheTableDict (Dictionary<int, T> cache)
{ {
_cache = cache; _cache = cache;
} }
public T Random ()
{
List<T> list = new List<T>(_cache.Values);
return list[_rand.Next(list.Count)];
}
} }
private static Dictionary<int, ItemInfo> _itemTable; private static readonly Dictionary<int, ItemInfo> _itemTable;
private int _id = 0; private int _id = 0;
private string _name = ""; private string _name = "";
private int _stack = 1; private int _stack = 1;
public static ItemCache<ItemInfo> ItemTable; private static readonly CacheTableDict<ItemInfo> _itemTableCache;
public static ICacheTable<ItemInfo> ItemTable
{
get { return _itemTableCache; }
}
public int ID public int ID
{ {
@ -189,6 +189,11 @@ namespace Substrate
return this; return this;
} }
public static ItemInfo GetRandomItem ()
{
List<ItemInfo> list = new List<ItemInfo>(_itemTable.Values);
return list[_rand.Next(list.Count)];
}
public static ItemInfo IronShovel; public static ItemInfo IronShovel;
public static ItemInfo IronPickaxe; public static ItemInfo IronPickaxe;
@ -300,8 +305,7 @@ namespace Substrate
static ItemInfo () static ItemInfo ()
{ {
_itemTable = new Dictionary<int, ItemInfo>(); _itemTable = new Dictionary<int, ItemInfo>();
_itemTableCache = new CacheTableDict<ItemInfo>(_itemTable);
ItemTable = new ItemCache<ItemInfo>(_itemTable);
IronShovel = new ItemInfo(256, "Iron Shovel"); IronShovel = new ItemInfo(256, "Iron Shovel");
IronPickaxe = new ItemInfo(257, "Iron Pickaxe"); IronPickaxe = new ItemInfo(257, "Iron Pickaxe");

View file

@ -13,7 +13,7 @@ namespace Substrate
{ {
new SchemaNodeScaler("Time", TagType.TAG_LONG), new SchemaNodeScaler("Time", TagType.TAG_LONG),
new SchemaNodeScaler("LastPlayed", TagType.TAG_LONG, SchemaOptions.CREATE_ON_MISSING), new SchemaNodeScaler("LastPlayed", TagType.TAG_LONG, SchemaOptions.CREATE_ON_MISSING),
new SchemaNodeCompound("Player", Player.PlayerSchema, SchemaOptions.OPTIONAL), new SchemaNodeCompound("Player", Player.Schema, SchemaOptions.OPTIONAL),
new SchemaNodeScaler("SpawnX", TagType.TAG_INT), new SchemaNodeScaler("SpawnX", TagType.TAG_INT),
new SchemaNodeScaler("SpawnY", TagType.TAG_INT), new SchemaNodeScaler("SpawnY", TagType.TAG_INT),
new SchemaNodeScaler("SpawnZ", TagType.TAG_INT), new SchemaNodeScaler("SpawnZ", TagType.TAG_INT),

View file

@ -0,0 +1,48 @@
using System;
using System.Runtime.Serialization;
namespace Substrate.Nbt
{
/// <summary>
/// The exception that is thrown when errors occur during Nbt IO operations.
/// </summary>
/// <remarks>In most cases, the <see cref="InnerException"/> property will contain more detailed information on the
/// error that occurred.</remarks>
[Serializable]
public class NbtIOException : Exception
{
/// <summary>
/// Initializes a new instance of the <see cref="NbtIOException"/> class.
/// </summary>
public NbtIOException ()
: base()
{ }
/// <summary>
/// Initializes a new instance of the <see cref="NbtIOException"/> class with a custom error message.
/// </summary>
/// <param name="message">A custom error message.</param>
public NbtIOException (string message)
: base(message)
{ }
/// <summary>
/// Initializes a new instance of the <see cref="NbtIOException"/> class with a custom error message and a reference to
/// an InnerException representing the original cause of the exception.
/// </summary>
/// <param name="message">A custom error message.</param>
/// <param name="innerException">A reference to the original exception that caused the error.</param>
public NbtIOException (string message, Exception innerException)
: base(message, innerException)
{ }
/// <summary>
/// Initializes a new instance of the <see cref="NbtIOException"/> class with serialized data.
/// </summary>
/// <param name="info">The object that holds the serialized object data.</param>
/// <param name="context">The contextual information about the source or destination.</param>
protected NbtIOException (SerializationInfo info, StreamingContext context)
: base(info, context)
{ }
}
}

View file

@ -6,9 +6,14 @@ using Substrate.Nbt;
namespace Substrate namespace Substrate
{ {
/// <summary>
/// Represents a Player from either single- or multi-player Minecraft.
/// </summary>
/// <remarks>Unlike <see cref="EntityTyped"/> objects, <see cref="Player"/> objects do not need to be added to chunks. They
/// are stored individually or within level data.</remarks>
public class Player : Entity, INbtObject<Player>, ICopyable<Player>, IItemContainer public class Player : Entity, INbtObject<Player>, ICopyable<Player>, IItemContainer
{ {
public static readonly SchemaNodeCompound PlayerSchema = Entity.Schema.MergeInto(new SchemaNodeCompound("") private static readonly SchemaNodeCompound _schema = Entity.Schema.MergeInto(new SchemaNodeCompound("")
{ {
new SchemaNodeScaler("AttackTime", TagType.TAG_SHORT), new SchemaNodeScaler("AttackTime", TagType.TAG_SHORT),
new SchemaNodeScaler("DeathTime", TagType.TAG_SHORT), new SchemaNodeScaler("DeathTime", TagType.TAG_SHORT),
@ -42,72 +47,103 @@ namespace Substrate
private ItemCollection _inventory; private ItemCollection _inventory;
/// <summary>
/// Gets or sets the number of ticks left in the player's "invincibility shield" after last struck.
/// </summary>
public int AttackTime public int AttackTime
{ {
get { return _attackTime; } get { return _attackTime; }
set { _attackTime = (short)value; } set { _attackTime = (short)value; }
} }
/// <summary>
/// Gets or sets the number of ticks that the player has been dead for.
/// </summary>
public int DeathTime public int DeathTime
{ {
get { return _deathTime; } get { return _deathTime; }
set { _deathTime = (short)value; } set { _deathTime = (short)value; }
} }
/// <summary>
/// Gets or sets the amount of the player's health.
/// </summary>
public int Health public int Health
{ {
get { return _health; } get { return _health; }
set { _health = (short)value; } set { _health = (short)value; }
} }
/// <summary>
/// Gets or sets the player's Hurt Time value.
/// </summary>
public int HurtTime public int HurtTime
{ {
get { return _hurtTime; } get { return _hurtTime; }
set { _hurtTime = (short)value; } set { _hurtTime = (short)value; }
} }
/// <summary>
/// Gets or sets the dimension that the player is currently in.
/// </summary>
public int Dimension public int Dimension
{ {
get { return _dimension; } get { return _dimension; }
set { _dimension = value; } set { _dimension = value; }
} }
/// <summary>
/// Gets or sets a value indicating whether the player is sleeping in a bed.
/// </summary>
public bool IsSleeping public bool IsSleeping
{ {
get { return _sleeping == 1; } get { return _sleeping == 1; }
set { _sleeping = (byte)(value ? 1 : 0); } set { _sleeping = (byte)(value ? 1 : 0); }
} }
/// <summary>
/// Gets or sets the player's Sleep Timer value.
/// </summary>
public int SleepTimer public int SleepTimer
{ {
get { return _sleepTimer; } get { return _sleepTimer; }
set { _sleepTimer = (short)value; } set { _sleepTimer = (short)value; }
} }
public int SpawnX /// <summary>
/// Gets or sets the player's personal spawn point, set by sleeping in beds.
/// </summary>
public SpawnPoint Spawn
{ {
get { return _spawnX ?? 0; } get { return new SpawnPoint(_spawnX ?? 0, _spawnY ?? 0, _spawnZ ?? 0); }
set { _spawnX = value; } set
{
_spawnX = value.X;
_spawnY = value.Y;
_spawnZ = value.Z;
}
} }
public int SpawnY /// <summary>
/// Tests if the player currently has a personal spawn point.
/// </summary>
public bool HasSpawn
{ {
get { return _spawnY ?? 0; } get { return _spawnX != null && _spawnY != null && _spawnZ != null; }
set { _spawnY = value; }
}
public int SpawnZ
{
get { return _spawnZ ?? 0; }
set { _spawnZ = value; }
} }
/// <summary>
/// Gets or sets the name of the world that the player is currently within.
/// </summary>
public string World public string World
{ {
get { return _world; } get { return _world; }
set { _world = value; } set { _world = value; }
} }
/// <summary>
/// Creates a new <see cref="Player"/> object with reasonable default values.
/// </summary>
public Player () public Player ()
: base() : base()
{ {
@ -123,7 +159,11 @@ namespace Substrate
Fire = -20; Fire = -20;
} }
public Player (Player p) /// <summary>
/// Creates a copy of a <see cref="Player"/> object.
/// </summary>
/// <param name="p">The <see cref="Player"/> to copy fields from.</param>
protected Player (Player p)
: base(p) : base(p)
{ {
_attackTime = p._attackTime; _attackTime = p._attackTime;
@ -141,9 +181,32 @@ namespace Substrate
_inventory = p._inventory.Copy(); _inventory = p._inventory.Copy();
} }
/// <summary>
/// Clears the player's personal spawn point.
/// </summary>
public void ClearSpawn ()
{
_spawnX = null;
_spawnY = null;
_spawnZ = null;
}
#region INBTObject<Player> Members #region INBTObject<Player> Members
/// <summary>
/// Gets a <see cref="SchemaNode"/> representing the schema of a Player.
/// </summary>
public static SchemaNodeCompound Schema
{
get { return _schema; }
}
/// <summary>
/// Attempt to load a Player subtree into the <see cref="Player"/> without validation.
/// </summary>
/// <param name="tree">The root node of a Player subtree.</param>
/// <returns>The <see cref="Player"/> returns itself on success, or null if the tree was unparsable.</returns>
public virtual new Player LoadTree (TagNode tree) public virtual new Player LoadTree (TagNode tree)
{ {
TagNodeCompound ctree = tree as TagNodeCompound; TagNodeCompound ctree = tree as TagNodeCompound;
@ -179,6 +242,11 @@ namespace Substrate
return this; return this;
} }
/// <summary>
/// Attempt to load a Player subtree into the <see cref="Player"/> with validation.
/// </summary>
/// <param name="tree">The root node of a Player subtree.</param>
/// <returns>The <see cref="Player"/> returns itself on success, or null if the tree failed validation.</returns>
public virtual new Player LoadTreeSafe (TagNode tree) public virtual new Player LoadTreeSafe (TagNode tree)
{ {
if (!ValidateTree(tree)) { if (!ValidateTree(tree)) {
@ -188,6 +256,10 @@ namespace Substrate
return LoadTree(tree); return LoadTree(tree);
} }
/// <summary>
/// Builds a Player subtree from the current data.
/// </summary>
/// <returns>The root node of a Player subtree representing the current data.</returns>
public virtual new TagNode BuildTree () public virtual new TagNode BuildTree ()
{ {
TagNodeCompound tree = base.BuildTree() as TagNodeCompound; TagNodeCompound tree = base.BuildTree() as TagNodeCompound;
@ -215,9 +287,14 @@ namespace Substrate
return tree; return tree;
} }
/// <summary>
/// Validate a Player subtree against a schema defintion.
/// </summary>
/// <param name="tree">The root node of a Player subtree.</param>
/// <returns>Status indicating whether the tree was valid against the internal schema.</returns>
public virtual new bool ValidateTree (TagNode tree) public virtual new bool ValidateTree (TagNode tree)
{ {
return new NbtVerifier(tree, PlayerSchema).Verify(); return new NbtVerifier(tree, _schema).Verify();
} }
#endregion #endregion
@ -225,6 +302,10 @@ namespace Substrate
#region ICopyable<Entity> Members #region ICopyable<Entity> Members
/// <summary>
/// Creates a deep-copy of the <see cref="Player"/>.
/// </summary>
/// <returns>A deep-copy of the <see cref="Player"/>.</returns>
public virtual new Player Copy () public virtual new Player Copy ()
{ {
return new Player(this); return new Player(this);
@ -235,6 +316,9 @@ namespace Substrate
#region IItemContainer Members #region IItemContainer Members
/// <summary>
/// Gets access to an <see cref="ItemCollection"/> representing the player's equipment and inventory.
/// </summary>
public ItemCollection Items public ItemCollection Items
{ {
get { return _inventory; } get { return _inventory; }

View file

@ -0,0 +1,46 @@
using System;
using System.Runtime.Serialization;
namespace Substrate
{
/// <summary>
/// The exception that is thrown when IO errors occur during high-level player management operations.
/// </summary>
[Serializable]
public class PlayerIOException : Exception
{
/// <summary>
/// Initializes a new instance of the <see cref="PlayerIOException"/> class.
/// </summary>
public PlayerIOException ()
: base()
{ }
/// <summary>
/// Initializes a new instance of the <see cref="PlayerIOException"/> class with a custom error message.
/// </summary>
/// <param name="message">A custom error message.</param>
public PlayerIOException (string message)
: base(message)
{ }
/// <summary>
/// Initializes a new instance of the <see cref="PlayerIOException"/> class with a custom error message and a reference to
/// an InnerException representing the original cause of the exception.
/// </summary>
/// <param name="message">A custom error message.</param>
/// <param name="innerException">A reference to the original exception that caused the error.</param>
public PlayerIOException (string message, Exception innerException)
: base(message, innerException)
{ }
/// <summary>
/// Initializes a new instance of the <see cref="PlayerIOException"/> class with serialized data.
/// </summary>
/// <param name="info">The object that holds the serialized object data.</param>
/// <param name="context">The contextual information about the source or destination.</param>
protected PlayerIOException (SerializationInfo info, StreamingContext context)
: base(info, context)
{ }
}
}

View file

@ -7,69 +7,133 @@ using Substrate.Nbt;
namespace Substrate namespace Substrate
{ {
public class PlayerManager /// <summary>
/// Functions to manage multiple <see cref="Player"/> entities and files in multiplayer settings.
/// </summary>
/// <remarks>This manager is intended for player files stored in standard compressed NBT format.</remarks>
public class PlayerManager : IPlayerManager
{ {
protected string _playerPath; private string _playerPath;
/// <summary>
/// Create a new <see cref="PlayerManager"/> for a given file path.
/// </summary>
/// <param name="playerDir">Path to a directory containing player data files.</param>
public PlayerManager (string playerDir) public PlayerManager (string playerDir)
{ {
_playerPath = playerDir; _playerPath = playerDir;
} }
/// <summary>
/// Gets a <see cref="PlayerFile"/> representing the backing NBT data stream.
/// </summary>
/// <param name="name">The name of the player to fetch.</param>
/// <returns>A <see cref="PlayerFile"/> for the given player.</returns>
protected PlayerFile GetPlayerFile (string name) protected PlayerFile GetPlayerFile (string name)
{ {
return new PlayerFile(_playerPath, name); return new PlayerFile(_playerPath, name);
} }
protected NbtTree GetPlayerTree (string name) /// <summary>
/// Gets a raw <see cref="NbtTree"/> of data for the given player.
/// </summary>
/// <param name="name">The name of the player to fetch.</param>
/// <returns>An <see cref="NbtTree"/> containing the given player's raw data.</returns>
/// <exception cref="NbtIOException">Thrown when the manager cannot read in an NBT data stream.</exception>
public NbtTree GetPlayerTree (string name)
{ {
PlayerFile pf = GetPlayerFile(name); PlayerFile pf = GetPlayerFile(name);
Stream nbtstr = pf.GetDataInputStream(); Stream nbtstr = pf.GetDataInputStream();
if (nbtstr == null) { if (nbtstr == null) {
return null; throw new NbtIOException("Failed to initialize NBT data stream for input.");
} }
return new NbtTree(nbtstr); return new NbtTree(nbtstr);
} }
protected bool SavePlayerTree (string name, NbtTree tree) /// <summary>
/// Saves a raw <see cref="NbtTree"/> representing a player to the given player's file.
/// </summary>
/// <param name="name">The name of the player to write data to.</param>
/// <param name="tree">The player's data as an <see cref="NbtTree"/>.</param>
/// <exception cref="NbtIOException">Thrown when the manager cannot initialize an NBT data stream for output.</exception>
public void SetPlayerTree (string name, NbtTree tree)
{ {
PlayerFile pf = GetPlayerFile(name); PlayerFile pf = GetPlayerFile(name);
Stream zipstr = pf.GetDataOutputStream(); Stream zipstr = pf.GetDataOutputStream();
if (zipstr == null) { if (zipstr == null) {
return false; throw new NbtIOException("Failed to initialize NBT data stream for output.");
} }
tree.WriteTo(zipstr); tree.WriteTo(zipstr);
zipstr.Close(); zipstr.Close();
return true;
} }
/// <summary>
/// Gets a <see cref="Player"/> object for the given player.
/// </summary>
/// <param name="name">The name of the player to fetch.</param>
/// <returns>A <see cref="Player"/> object for the given player, or null if the player could not be found.</returns>
/// <exception cref="PlayerIOException">Thrown when the manager cannot read in a player that should exist.</exception>
public Player GetPlayer (string name) public Player GetPlayer (string name)
{ {
if (!PlayerExists(name)) { if (!PlayerExists(name)) {
return null; return null;
} }
return new Player().LoadTreeSafe(GetPlayerTree(name).Root); try {
return new Player().LoadTreeSafe(GetPlayerTree(name).Root);
}
catch (Exception ex) {
PlayerIOException pex = new PlayerIOException("Could not load player", ex);
pex.Data["PlayerName"] = name;
throw pex;
}
} }
public bool SetPlayer (string name, Player player) /// <summary>
/// Saves a <see cref="Player"/> object's data back to the given player's file.
/// </summary>
/// <param name="name">The name of the player to write back to.</param>
/// <param name="player">The <see cref="Player"/> object containing data to write back.</param>
/// <exception cref="PlayerIOException">Thrown when the manager cannot write out the player.</exception>
public void SetPlayer (string name, Player player)
{ {
return SavePlayerTree(name, new NbtTree(player.BuildTree() as TagNodeCompound)); try {
SetPlayerTree(name, new NbtTree(player.BuildTree() as TagNodeCompound));
}
catch (Exception ex) {
PlayerIOException pex = new PlayerIOException("Could not save player", ex);
pex.Data["PlayerName"] = name;
throw pex;
}
} }
/// <summary>
/// Checks if data for a player with the given name exists.
/// </summary>
/// <param name="name">The name of the player to look up.</param>
/// <returns>True if player data was found; false otherwise.</returns>
public bool PlayerExists (string name) public bool PlayerExists (string name)
{ {
return new PlayerFile(_playerPath, name).Exists(); return new PlayerFile(_playerPath, name).Exists();
} }
public bool DeletePlayer (string name) /// <summary>
/// Deletes a player with the given name from the underlying data store.
/// </summary>
/// <param name="name">The name of the player to delete.</param>
/// <exception cref="PlayerIOException">Thrown when the manager cannot delete the player.</exception>
public void DeletePlayer (string name)
{ {
new PlayerFile(_playerPath, name).Delete(); try {
new PlayerFile(_playerPath, name).Delete();
return true; }
catch (Exception ex) {
PlayerIOException pex = new PlayerIOException("Could not save player", ex);
pex.Data["PlayerName"] = name;
throw pex;
}
} }
} }
} }

View file

@ -132,7 +132,7 @@ namespace Substrate
public IEnumerator<Region> GetEnumerator () public IEnumerator<Region> GetEnumerator ()
{ {
return new RegionEnumerator(this); return new Enumerator(this);
} }
#endregion #endregion
@ -141,26 +141,27 @@ namespace Substrate
IEnumerator IEnumerable.GetEnumerator () IEnumerator IEnumerable.GetEnumerator ()
{ {
return new RegionEnumerator(this); return new Enumerator(this);
} }
#endregion #endregion
public class RegionEnumerator : IEnumerator<Region> private struct Enumerator : IEnumerator<Region>
{ {
protected List<Region> _regions; private List<Region> _regions;
private int _pos;
protected int _pos = -1; public Enumerator (List<Region> regs)
public RegionEnumerator (List<Region> regs)
{ {
_regions = regs; _regions = regs;
_pos = -1;
} }
public RegionEnumerator (RegionManager rm) public Enumerator (RegionManager rm)
{ {
_regions = new List<Region>(); _regions = new List<Region>();
_pos = -1;
if (!Directory.Exists(rm.GetRegionPath())) { if (!Directory.Exists(rm.GetRegionPath())) {
throw new DirectoryNotFoundException(); throw new DirectoryNotFoundException();

View file

@ -0,0 +1,125 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Substrate
{
/// <summary>
/// Represents the spawn point of a player or world.
/// </summary>
/// <remarks><see cref="SpawnPoint"/> values are immutable. To change an existing spawn point, create a new instance with
/// the new coordinate(s). Since some spawn points are optional in Minecraft, this helps safegaurd against saving a partial
/// spawn point.</remarks>
public struct SpawnPoint : IEquatable<SpawnPoint>
{
private readonly int _x;
private readonly int _y;
private readonly int _z;
/// <summary>
/// Gets the global X-coordinate of the spawn point (in blocks).
/// </summary>
public int X
{
get { return _x; }
}
/// <summary>
/// Gets the global Y-coordinate of the spawn point (in blocks).
/// </summary>
public int Y
{
get { return _y; }
}
/// <summary>
/// Gets the global Z-coordinate of the spawn point (in blocks).
/// </summary>
public int Z
{
get { return _z; }
}
/// <summary>
/// Creates a new spawn point.
/// </summary>
/// <param name="x">The global X-coordinate of the spawn point.</param>
/// <param name="y">The global Y-coordinate of the spawn point.</param>
/// <param name="z">The global Z-coordinate of the spawn point.</param>
public SpawnPoint (int x, int y, int z)
{
_x = x;
_y = y;
_z = z;
}
/// <summary>
/// Checks if two <see cref="SpawnPoint"/> objects are considered equal.
/// </summary>
/// <param name="spawn">A <see cref="SpawnPoint"/> to compare against.</param>
/// <returns>True if the two <see cref="SpawnPoint"/> objects are equal; false otherwise.</returns>
public bool Equals (SpawnPoint spawn)
{
return this._x == spawn._x && this._y == spawn._y && this._z == spawn._z;
}
/// <summary>
/// Checks if two <see cref="SpawnPoint"/> objects are considered equal.
/// </summary>
/// <param name="o">An to compare against.</param>
/// <returns>True if the two <see cref="SpawnPoint"/> objects are equal; false otherwise.</returns>
public override bool Equals (Object o)
{
if (o is SpawnPoint) {
return this == (SpawnPoint)o;
}
else {
return false;
}
}
/// <summary>
/// Returns the hash code for this instance.
/// </summary>
/// <returns>A hash code for this instance.</returns>
public override int GetHashCode ()
{
int hash = 23;
hash = hash * 37 + _x;
hash = hash * 37 + _y;
hash = hash * 37 + _z;
return hash;
}
/// <summary>
/// Checks if two <see cref="SpawnPoint"/> objects are considered equal.
/// </summary>
/// <param name="k1">The first <see cref="SpawnPoint"/> in the comparison.</param>
/// <param name="k2">The second <see cref="SpawnPoint"/> in the comparison.</param>
/// <returns>True if the two <see cref="SpawnPoint"/> objects are equal; false otherwise.</returns>
public static bool operator == (SpawnPoint k1, SpawnPoint k2)
{
return k1._x == k2._x && k1._y == k2._y && k1._z == k2._z;
}
/// <summary>
/// Checks if two <see cref="SpawnPoint"/> objects are considered unequal.
/// </summary>
/// <param name="k1">The first <see cref="SpawnPoint"/> in the comparison.</param>
/// <param name="k2">The second <see cref="SpawnPoint"/> in the comparison.</param>
/// <returns>True if the two <see cref="SpawnPoint"/> objects are not equal; false otherwise.</returns>
public static bool operator != (SpawnPoint k1, SpawnPoint k2)
{
return k1._x != k2._x || k1._y != k2._y || k1._z != k2._z;
}
/// <summary>
/// Returns a string representation of the <see cref="SpawnPoint"/>.
/// </summary>
/// <returns>A string representing this <see cref="SpawnPoint"/>.</returns>
public override string ToString ()
{
return "(" + _x + ", " + _y + ", " + _z + ")";
}
}
}

View file

@ -64,7 +64,9 @@
<ItemGroup> <ItemGroup>
<Compile Include="Source\AlphaBlock.cs" /> <Compile Include="Source\AlphaBlock.cs" />
<Compile Include="Source\AlphaBlockRef.cs" /> <Compile Include="Source\AlphaBlockRef.cs" />
<Compile Include="Source\CacheTable.cs" />
<Compile Include="Source\Core\BlockFluid.cs" /> <Compile Include="Source\Core\BlockFluid.cs" />
<Compile Include="Source\Core\PlayerManagerInterface.cs" />
<Compile Include="Source\Data.cs" /> <Compile Include="Source\Data.cs" />
<Compile Include="Source\ItemInfo.cs" /> <Compile Include="Source\ItemInfo.cs" />
<Compile Include="Source\Core\ChunkCache.cs" /> <Compile Include="Source\Core\ChunkCache.cs" />
@ -74,7 +76,14 @@
<Compile Include="Source\Core\BlockLight.cs" /> <Compile Include="Source\Core\BlockLight.cs" />
<Compile Include="Source\Core\BlockTileEntities.cs" /> <Compile Include="Source\Core\BlockTileEntities.cs" />
<Compile Include="Source\Level.cs" /> <Compile Include="Source\Level.cs" />
<Compile Include="Source\NBT\INBTObject.cs" /> <Compile Include="Source\NBT\INBTObject.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Source\NBT\NbtIOException.cs" />
<Compile Include="Source\NBT\NbtTree.cs" />
<Compile Include="Source\NBT\NBTVerifier.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Source\NBT\SchemaNode.cs" /> <Compile Include="Source\NBT\SchemaNode.cs" />
<Compile Include="Source\NBT\SchemaNodeArray.cs" /> <Compile Include="Source\NBT\SchemaNodeArray.cs" />
<Compile Include="Source\NBT\SchemaNodeCompound.cs" /> <Compile Include="Source\NBT\SchemaNodeCompound.cs" />
@ -96,6 +105,8 @@
<Compile Include="Source\NBT\TagNodeByte.cs" /> <Compile Include="Source\NBT\TagNodeByte.cs" />
<Compile Include="Source\NBT\TagNodeNull.cs" /> <Compile Include="Source\NBT\TagNodeNull.cs" />
<Compile Include="Source\NBT\VerifierLogger.cs" /> <Compile Include="Source\NBT\VerifierLogger.cs" />
<Compile Include="Source\Orientation.cs" />
<Compile Include="Source\PlayerIOException.cs" />
<Compile Include="Source\PlayerManager.cs" /> <Compile Include="Source\PlayerManager.cs" />
<Compile Include="Source\Core\PlayerFile.cs" /> <Compile Include="Source\Core\PlayerFile.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
@ -142,13 +153,12 @@
<Compile Include="Source\Item.cs" /> <Compile Include="Source\Item.cs" />
<Compile Include="Source\Core\NBTFile.cs" /> <Compile Include="Source\Core\NBTFile.cs" />
<Compile Include="Source\NBT\JSONSerializer.cs" /> <Compile Include="Source\NBT\JSONSerializer.cs" />
<Compile Include="Source\NBT\NBT.cs" />
<Compile Include="Source\NBT\NBTVerifier.cs" />
<Compile Include="Source\Player.cs" /> <Compile Include="Source\Player.cs" />
<Compile Include="Source\Region.cs" /> <Compile Include="Source\Region.cs" />
<Compile Include="Source\Core\RegionFile.cs" /> <Compile Include="Source\Core\RegionFile.cs" />
<Compile Include="Source\Core\RegionKey.cs" /> <Compile Include="Source\Core\RegionKey.cs" />
<Compile Include="Source\RegionManager.cs" /> <Compile Include="Source\RegionManager.cs" />
<Compile Include="Source\SpawnPoint.cs" />
<Compile Include="Source\TileEntities\TileEntityChest.cs" /> <Compile Include="Source\TileEntities\TileEntityChest.cs" />
<Compile Include="Source\TileEntities\TileEntityFurnace.cs" /> <Compile Include="Source\TileEntities\TileEntityFurnace.cs" />
<Compile Include="Source\TileEntities\TileEntityMobSpawner.cs" /> <Compile Include="Source\TileEntities\TileEntityMobSpawner.cs" />
@ -164,6 +174,7 @@
<Compile Include="Source\Core\Interface.cs" /> <Compile Include="Source\Core\Interface.cs" />
<Compile Include="Source\Core\LRUCache.cs" /> <Compile Include="Source\Core\LRUCache.cs" />
<Compile Include="Source\Core\NibbleArray.cs" /> <Compile Include="Source\Core\NibbleArray.cs" />
<Compile Include="Source\Vector.cs" />
<Compile Include="Source\World.cs" /> <Compile Include="Source\World.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>