#region Copyright & License Information
/*
* Copyright (c) The OpenRA Developers and Contributors
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version. For more
* information, see COPYING.
*/
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using OpenRA.Traits;
namespace OpenRA.Mods.Common
{
///
/// Maintains an index of actors in the world.
///
public abstract class ActorIndex : IDisposable
{
readonly World world;
readonly HashSet actors = new();
public IReadOnlyCollection Actors => actors;
ActorIndex(World world, IEnumerable initialActorsToIndex)
{
this.world = world;
world.ActorAdded += AddActor;
world.ActorRemoved += RemoveActor;
actors.UnionWith(initialActorsToIndex);
}
protected abstract bool ShouldIndexActor(Actor actor);
void AddActor(Actor actor)
{
if (ShouldIndexActor(actor))
actors.Add(actor);
}
void RemoveActor(Actor actor)
{
actors.Remove(actor);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
world.ActorAdded -= AddActor;
world.ActorRemoved -= RemoveActor;
}
}
// No OwnerAndTrait class is provided. As the world can provide actors by trait anyway,
// an additional filter on owner isn't sufficiently selective to justify the overhead of manging the index.
// Whereas a filter with actor names is much more selective, so OwnerAndNames is worthwhile.
///
/// Maintains an index of actors in the world that
/// are owned by a given
/// and have one of the given .
///
public sealed class OwnerAndNames : ActorIndex
{
readonly HashSet names;
readonly Player owner;
public OwnerAndNames(World world, IReadOnlyCollection names, Player owner)
: base(world, ActorsToIndex(world, names.ToHashSet(), owner))
{
this.names = names.ToHashSet();
this.owner = owner;
}
static IEnumerable ActorsToIndex(World world, HashSet names, Player owner)
{
return world.Actors.Where(a => a.Owner == owner && names.Contains(a.Info.Name));
}
protected override bool ShouldIndexActor(Actor actor)
{
return actor.Owner == owner && names.Contains(actor.Info.Name);
}
}
///
/// Maintains an index of actors in the world that
/// have one of the given
/// and have the trait with info of type .
///
public sealed class NamesAndTrait : ActorIndex where TTraitInfo : ITraitInfoInterface
{
readonly HashSet names;
public NamesAndTrait(World world, IReadOnlyCollection names)
: base(world, ActorsToIndex(world, names.ToHashSet()))
{
this.names = names.ToHashSet();
}
static IEnumerable ActorsToIndex(World world, HashSet names)
{
return world.Actors.Where(a => names.Contains(a.Info.Name) && a.Info.HasTraitInfo());
}
protected override bool ShouldIndexActor(Actor actor)
{
return names.Contains(actor.Info.Name) && actor.Info.HasTraitInfo();
}
}
///
/// Maintains an index of actors in the world that
/// are owned by a given ,
/// have one of the given
/// and have the trait with info of type .
///
public sealed class OwnerAndNamesAndTrait : ActorIndex where TTraitInfo : ITraitInfoInterface
{
readonly HashSet names;
readonly Player owner;
public OwnerAndNamesAndTrait(World world, IReadOnlyCollection names, Player owner)
: base(world, ActorsToIndex(world, names.ToHashSet(), owner))
{
this.names = names.ToHashSet();
this.owner = owner;
}
static IEnumerable ActorsToIndex(World world, HashSet names, Player owner)
{
return world.Actors.Where(a => a.Owner == owner && names.Contains(a.Info.Name) && a.Info.HasTraitInfo());
}
protected override bool ShouldIndexActor(Actor actor)
{
return actor.Owner == owner && names.Contains(actor.Info.Name) && actor.Info.HasTraitInfo();
}
}
}
}