2011-05-13 03:09:57 +00:00
using System ;
using System.Collections.Generic ;
using System.Text ;
2011-07-02 03:51:48 +00:00
using Substrate.Nbt ;
2011-05-13 03:09:57 +00:00
namespace Substrate
{
2011-07-02 03:51:48 +00:00
/// <summary>
/// Functions to query and manage a collection of entities.
/// </summary>
2011-08-14 19:34:49 +00:00
public class EntityCollection : IEnumerable < TypedEntity >
2011-05-13 03:09:57 +00:00
{
2011-06-20 03:51:40 +00:00
private TagNodeList _entities ;
2011-05-13 03:09:57 +00:00
private bool _dirty ;
2011-07-02 03:51:48 +00:00
/// <summary>
/// Gets or sets a value indicating whether this collection contains unsaved changes.
/// </summary>
2011-05-13 03:09:57 +00:00
public bool IsDirty
{
get { return _dirty ; }
set { _dirty = value ; }
}
2011-07-02 03:51:48 +00:00
/// <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>
2011-06-20 03:51:40 +00:00
public EntityCollection ( TagNodeList entities )
2011-05-13 03:09:57 +00:00
{
_entities = entities ;
}
2011-07-02 03:51:48 +00:00
/// <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>
2011-08-14 19:34:49 +00:00
/// <returns>A list of <see cref="TypedEntity"/> objects matching the given id (type).</returns>
public List < TypedEntity > FindAll ( string id )
2011-05-13 03:09:57 +00:00
{
2011-08-14 19:34:49 +00:00
List < TypedEntity > set = new List < TypedEntity > ( ) ;
2011-05-13 03:09:57 +00:00
2011-06-20 03:51:40 +00:00
foreach ( TagNodeCompound ent in _entities ) {
TagNode eid ;
2011-05-13 03:09:57 +00:00
if ( ! ent . TryGetValue ( "id" , out eid ) ) {
continue ;
}
if ( eid . ToTagString ( ) . Data ! = id ) {
continue ;
}
2011-08-14 19:34:49 +00:00
TypedEntity obj = EntityFactory . Create ( ent ) ;
2011-05-13 03:09:57 +00:00
if ( obj ! = null ) {
set . Add ( obj ) ;
}
}
return set ;
}
2011-07-02 03:51:48 +00:00
/// <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>
2011-08-14 19:34:49 +00:00
/// <returns>A list of <see cref="TypedEntity"/> objects matching the given condition.</returns>
public List < TypedEntity > FindAll ( Predicate < TypedEntity > match )
2011-05-13 03:09:57 +00:00
{
2011-08-14 19:34:49 +00:00
List < TypedEntity > set = new List < TypedEntity > ( ) ;
2011-05-13 03:09:57 +00:00
2011-06-20 03:51:40 +00:00
foreach ( TagNodeCompound ent in _entities ) {
2011-08-14 19:34:49 +00:00
TypedEntity obj = EntityFactory . Create ( ent ) ;
2011-05-13 03:09:57 +00:00
if ( obj = = null ) {
continue ;
}
if ( match ( obj ) ) {
set . Add ( obj ) ;
}
}
return set ;
}
2011-07-02 03:51:48 +00:00
/// <summary>
2011-08-14 19:34:49 +00:00
/// Adds a <see cref="TypedEntity"/> to the collection.
2011-07-02 03:51:48 +00:00
/// </summary>
2011-08-14 19:34:49 +00:00
/// <param name="ent">The <see cref="TypedEntity"/> object to add.</param>
/// <remarks>It is up to the developer to ensure that the <see cref="TypedEntity"/> being added to the collection has a position that
2011-07-02 03:51:48 +00:00
/// is within acceptable range of the collection. <see cref="EntityCollection"/> transparently back other objects such as
2012-04-28 19:52:40 +00:00
/// <see cref="IChunk"/> objects, which have a well-defined position in global space. The <see cref="EntityCollection"/> itself has
2011-08-14 19:34:49 +00:00
/// no concept of position and will not enforce constraints on the positions of <see cref="TypedEntity"/> objects being added.</remarks>
public void Add ( TypedEntity ent )
2011-05-13 03:09:57 +00:00
{
_entities . Add ( ent . BuildTree ( ) ) ;
_dirty = true ;
}
2011-07-02 03:51:48 +00:00
/// <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>
2011-06-01 06:11:50 +00:00
public int RemoveAll ( string id )
2011-05-13 03:09:57 +00:00
{
int rem = _entities . RemoveAll ( val = >
{
2011-06-20 03:51:40 +00:00
TagNodeCompound cval = val as TagNodeCompound ;
2011-05-13 03:09:57 +00:00
if ( cval = = null ) {
return false ;
}
2011-06-20 03:51:40 +00:00
TagNode sval ;
2011-05-13 03:09:57 +00:00
if ( ! cval . TryGetValue ( "id" , out sval ) ) {
return false ;
}
return ( sval . ToTagString ( ) . Data = = id ) ;
} ) ;
if ( rem > 0 ) {
_dirty = true ;
}
2011-06-01 06:11:50 +00:00
2011-05-13 03:09:57 +00:00
return rem ;
}
2011-07-02 03:51:48 +00:00
/// <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>
2011-08-14 19:34:49 +00:00
public int RemoveAll ( Predicate < TypedEntity > match )
2011-05-13 03:09:57 +00:00
{
int rem = _entities . RemoveAll ( val = >
{
2011-06-20 03:51:40 +00:00
TagNodeCompound cval = val as TagNodeCompound ;
2011-05-13 03:09:57 +00:00
if ( cval = = null ) {
return false ;
}
2011-08-14 19:34:49 +00:00
TypedEntity obj = EntityFactory . Create ( cval ) ;
2011-05-13 03:09:57 +00:00
if ( obj = = null ) {
return false ;
}
return match ( obj ) ;
} ) ;
if ( rem > 0 ) {
_dirty = true ;
}
return rem ;
}
2011-06-01 06:11:50 +00:00
#region IEnumerable < Entity > Members
2011-07-02 03:51:48 +00:00
/// <summary>
/// Returns an enumerator that iterates through all entities.
/// </summary>
/// <returns>An <see cref="Enumerator"/> for this object.</returns>
2011-08-14 19:34:49 +00:00
public IEnumerator < TypedEntity > GetEnumerator ( )
2011-06-01 06:11:50 +00:00
{
2011-07-02 03:51:48 +00:00
return new Enumerator ( _entities ) ;
2011-06-01 06:11:50 +00:00
}
#endregion
#region IEnumerable Members
2011-07-02 03:51:48 +00:00
/// <summary>
/// Returns an enumerator that iterates through all entities.
/// </summary>
/// <returns>An <see cref="Enumerator"/> for this object.</returns>
2011-06-01 06:11:50 +00:00
System . Collections . IEnumerator System . Collections . IEnumerable . GetEnumerator ( )
{
2011-07-02 03:51:48 +00:00
return new Enumerator ( _entities ) ;
2011-06-01 06:11:50 +00:00
}
#endregion
2011-07-02 03:51:48 +00:00
/// <summary>
/// Enumerates the entities within an <see cref="EntityCollection"/>.
/// </summary>
2011-08-14 19:34:49 +00:00
private struct Enumerator : IEnumerator < TypedEntity >
2011-06-01 06:11:50 +00:00
{
2011-06-20 03:51:40 +00:00
private IEnumerator < TagNode > _enum ;
2011-06-01 06:11:50 +00:00
2012-01-05 00:23:37 +00:00
private bool _next ;
2011-08-14 19:34:49 +00:00
private TypedEntity _cur ;
2011-06-01 06:11:50 +00:00
2011-07-02 03:51:48 +00:00
internal Enumerator ( TagNodeList entities )
2011-06-01 06:11:50 +00:00
{
_enum = entities . GetEnumerator ( ) ;
2011-07-02 03:51:48 +00:00
_cur = null ;
2012-01-05 00:23:37 +00:00
_next = false ;
2011-06-01 06:11:50 +00:00
}
#region IEnumerator < Entity > Members
2011-07-02 03:51:48 +00:00
/// <summary>
2011-08-14 19:34:49 +00:00
/// Gets the <see cref="TypedEntity"/> at the current position of the enumerator.
2011-07-02 03:51:48 +00:00
/// </summary>
2011-08-14 19:34:49 +00:00
public TypedEntity Current
2011-06-01 06:11:50 +00:00
{
get
{
2012-01-05 00:23:37 +00:00
if ( _next = = false ) {
2011-06-01 06:11:50 +00:00
throw new InvalidOperationException ( ) ;
}
return _cur ;
}
}
#endregion
#region IDisposable Members
2011-07-02 03:51:48 +00:00
/// <summary>
/// Releases all resources used by the <see cref="Enumerator"/>.
/// </summary>
2011-06-01 06:11:50 +00:00
public void Dispose ( ) { }
#endregion
#region IEnumerator Members
2011-07-02 03:51:48 +00:00
/// <summary>
2011-08-14 19:34:49 +00:00
/// Gets the <see cref="TypedEntity"/> at the current position of the enumerator.
2011-07-02 03:51:48 +00:00
/// </summary>
2011-06-01 06:11:50 +00:00
object System . Collections . IEnumerator . Current
{
get { return Current ; }
}
2011-07-02 03:51:48 +00:00
/// <summary>
2011-08-14 19:34:49 +00:00
/// Advances the enumerator to the next <see cref="TypedEntity"/> in the <see cref="EntityCollection"/>.
2011-07-02 03:51:48 +00:00
/// </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>
2011-06-01 06:11:50 +00:00
public bool MoveNext ( )
{
if ( ! _enum . MoveNext ( ) ) {
2012-01-05 00:23:37 +00:00
_next = false ;
2011-06-01 06:11:50 +00:00
return false ;
}
_cur = EntityFactory . Create ( _enum . Current . ToTagCompound ( ) ) ;
2012-01-05 00:23:37 +00:00
if ( _cur = = null )
_cur = EntityFactory . CreateGeneric ( _enum . Current . ToTagCompound ( ) ) ;
_next = true ;
2011-06-01 06:11:50 +00:00
return true ;
}
2011-07-02 03:51:48 +00:00
/// <summary>
2011-08-14 19:34:49 +00:00
/// Sets the enumerator to its initial position, which is before the first <see cref="TypedEntity"/> in the collection.
2011-07-02 03:51:48 +00:00
/// </summary>
void System . Collections . IEnumerator . Reset ( )
2011-06-01 06:11:50 +00:00
{
_cur = null ;
2012-01-05 00:23:37 +00:00
_next = false ;
2011-06-01 06:11:50 +00:00
_enum . Reset ( ) ;
}
#endregion
}
2011-05-13 03:09:57 +00:00
}
}