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-06-30 03:59:20 +00:00
public class EntityCollection : IEnumerable < EntityTyped >
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>
/// <returns>A list of <see cref="EntityTyped"/> objects matching the given id (type).</returns>
2011-06-30 03:59:20 +00:00
public List < EntityTyped > FindAll ( string id )
2011-05-13 03:09:57 +00:00
{
2011-06-30 03:59:20 +00:00
List < EntityTyped > set = new List < EntityTyped > ( ) ;
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-06-30 03:59:20 +00:00
EntityTyped 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>
/// <returns>A list of <see cref="EntityTyped"/> objects matching the given condition.</returns>
2011-06-30 03:59:20 +00:00
public List < EntityTyped > FindAll ( Predicate < EntityTyped > match )
2011-05-13 03:09:57 +00:00
{
2011-06-30 03:59:20 +00:00
List < EntityTyped > set = new List < EntityTyped > ( ) ;
2011-05-13 03:09:57 +00:00
2011-06-20 03:51:40 +00:00
foreach ( TagNodeCompound ent in _entities ) {
2011-06-30 03:59:20 +00:00
EntityTyped 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>
/// 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 )
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-06-30 03:59:20 +00:00
public int RemoveAll ( Predicate < EntityTyped > 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-06-30 03:59:20 +00:00
EntityTyped 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-06-30 03:59:20 +00:00
public IEnumerator < EntityTyped > 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>
private struct Enumerator : IEnumerator < EntityTyped >
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
2011-06-30 03:59:20 +00:00
private EntityTyped _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 ;
2011-06-01 06:11:50 +00:00
}
#region IEnumerator < Entity > Members
2011-07-02 03:51:48 +00:00
/// <summary>
/// Gets the <see cref="EntityTyped"/> at the current position of the enumerator.
/// </summary>
2011-06-30 03:59:20 +00:00
public EntityTyped Current
2011-06-01 06:11:50 +00:00
{
get
{
if ( _cur = = null ) {
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>
/// Gets the <see cref="EntityTyped"/> at the current position of the enumerator.
/// </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>
/// 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>
2011-06-01 06:11:50 +00:00
public bool MoveNext ( )
{
if ( ! _enum . MoveNext ( ) ) {
return false ;
}
_cur = EntityFactory . Create ( _enum . Current . ToTagCompound ( ) ) ;
return true ;
}
2011-07-02 03:51:48 +00:00
/// <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 ( )
2011-06-01 06:11:50 +00:00
{
_cur = null ;
_enum . Reset ( ) ;
}
#endregion
}
2011-05-13 03:09:57 +00:00
}
}