diff --git a/OpenRA.Game/Actor.cs b/OpenRA.Game/Actor.cs index f46cc7e7a5..06abd3f4c6 100755 --- a/OpenRA.Game/Actor.cs +++ b/OpenRA.Game/Actor.cs @@ -31,8 +31,8 @@ namespace OpenRA public Player Owner; IActivity currentActivity; - public Group Group; - + public Group Group; + internal Actor(World world, string name, TypeDictionary initDict ) { var init = new ActorInitializer( this, initDict ); @@ -69,7 +69,7 @@ namespace OpenRA } public void Tick() - { + { var wasIdle = currentActivity is Idle; while (currentActivity != null) { @@ -142,7 +142,7 @@ namespace OpenRA return new RectangleF(loc.X, loc.Y, size.X, size.Y); } - public bool IsInWorld { get; set; } + public bool IsInWorld { get; internal set; } public void QueueActivity( IActivity nextActivity ) { @@ -209,7 +209,17 @@ namespace OpenRA public void AddTrait( object trait ) { - World.traitDict.Add( this, trait ); + World.traitDict.AddTrait( this, trait ); } + + public void Destroy() + { + World.AddFrameEndTask( w => World.Remove( this ) ); + } + + ~Actor() + { + World.traitDict.RemoveActor( this ); + } } } diff --git a/OpenRA.Game/TraitDictionary.cs b/OpenRA.Game/TraitDictionary.cs index d0eafffd87..3ddaaf8343 100755 --- a/OpenRA.Game/TraitDictionary.cs +++ b/OpenRA.Game/TraitDictionary.cs @@ -12,7 +12,6 @@ using System; using System.Collections.Generic; using System.Linq; using OpenRA.FileFormats; -using System.Diagnostics; namespace OpenRA { @@ -31,7 +30,7 @@ namespace OpenRA .GetConstructor( new Type[ 0 ] ).Invoke( new object[ 0 ] ); } - public void Add( Actor actor, object val ) + public void AddTrait( Actor actor, object val ) { var t = val.GetType(); @@ -48,78 +47,107 @@ namespace OpenRA public bool Contains( Actor actor ) { - return ( (TraitContainer)InnerGet( typeof( T ) ) ).GetMultiple( actor ).Count() != 0; + return ( (TraitContainer)InnerGet( typeof( T ) ) ).GetMultiple( actor.ActorID ).Count() != 0; } public T Get( Actor actor ) { - return ( (TraitContainer)InnerGet( typeof( T ) ) ).Get( actor ); + return ( (TraitContainer)InnerGet( typeof( T ) ) ).Get( actor.ActorID ); } public T GetOrDefault( Actor actor ) { - return ( (TraitContainer)InnerGet( typeof( T ) ) ).GetOrDefault( actor ); + return ( (TraitContainer)InnerGet( typeof( T ) ) ).GetOrDefault( actor.ActorID ); } public IEnumerable WithInterface( Actor actor ) { - return ( (TraitContainer)InnerGet( typeof( T ) ) ).GetMultiple( actor ); + return ( (TraitContainer)InnerGet( typeof( T ) ) ).GetMultiple( actor.ActorID ); + } + + public IEnumerable> ActorsWithTraitMultiple( World world ) + { + return ( (TraitContainer)InnerGet( typeof( T ) ) ).All().Where( x => x.Actor.IsInWorld ); + } + + public void RemoveActor( Actor a ) + { + foreach( var t in traits ) + t.Value.RemoveActor( a.ActorID ); } interface ITraitContainer { void Add( Actor actor, object trait ); + void RemoveActor( uint actor ); } class TraitContainer : ITraitContainer { - List actors = new List(); + List actors = new List(); List traits = new List(); public void Add( Actor actor, object trait ) { var insertIndex = actors.BinarySearchMany( actor.ActorID + 1 ); - actors.Insert( insertIndex, actor.ActorID ); + actors.Insert( insertIndex, actor ); traits.Insert( insertIndex, (T)trait ); } - public T Get( Actor actor ) + public T Get( uint actor ) { - var index = actors.BinarySearchMany( actor.ActorID ); - if( index >= actors.Count || actors[ index ] != actor.ActorID ) + var index = actors.BinarySearchMany( actor ); + if( index >= actors.Count || actors[ index ].ActorID != actor ) throw new InvalidOperationException( string.Format( "TraitDictionary does not contain instance of type `{0}`", typeof( T ) ) ); - else if( index + 1 < actors.Count && actors[ index + 1 ] == actor.ActorID ) + else if( index + 1 < actors.Count && actors[ index + 1 ].ActorID == actor ) throw new InvalidOperationException( string.Format( "TraitDictionary contains multiple instance of type `{0}`", typeof( T ) ) ); else return traits[ index ]; } - public T GetOrDefault( Actor actor ) + public T GetOrDefault( uint actor ) { - var index = actors.BinarySearchMany( actor.ActorID ); - if( index >= actors.Count || actors[ index ] != actor.ActorID ) + var index = actors.BinarySearchMany( actor ); + if( index >= actors.Count || actors[ index ].ActorID != actor ) return default( T ); - else if( index + 1 < actors.Count && actors[ index + 1 ] == actor.ActorID ) + else if( index + 1 < actors.Count && actors[ index + 1 ].ActorID == actor ) throw new InvalidOperationException( string.Format( "TraitDictionary contains multiple instance of type `{0}`", typeof( T ) ) ); else return traits[ index ]; } - public IEnumerable GetMultiple( Actor actor ) + public IEnumerable GetMultiple( uint actor ) { - var index = actors.BinarySearchMany( actor.ActorID ); - while( index < actors.Count && actors[ index ] == actor.ActorID ) + var index = actors.BinarySearchMany( actor ); + while( index < actors.Count && actors[ index ].ActorID == actor ) { yield return traits[ index ]; ++index; } } + + public IEnumerable> All() + { + for( int i = 0 ; i < actors.Count ; i++ ) + yield return new TraitPair { Actor = actors[ i ], Trait = traits[ i ] }; + } + + public void RemoveActor( uint actor ) + { + for( int i = actors.Count - 1 ; i >= 0 ; i-- ) + { + if( actors[ i ].ActorID == actor ) + { + actors.RemoveAt( i ); + traits.RemoveAt( i ); + } + } + } } } static class ListExts { - public static int BinarySearchMany( this List list, T searchFor ) - where T : IComparable + public static int BinarySearchMany( this List list, uint searchFor ) { int start = 0; int end = list.Count; @@ -127,7 +155,7 @@ namespace OpenRA while( start != end ) { mid = ( start + end ) / 2; - var c = list[ mid ].CompareTo( searchFor ); + var c = list[ mid ].ActorID.CompareTo( searchFor ); if( c < 0 ) start = mid + 1; else diff --git a/OpenRA.Game/Traits/Activities/RemoveSelf.cs b/OpenRA.Game/Traits/Activities/RemoveSelf.cs index 470390406c..4e9d57f5ee 100644 --- a/OpenRA.Game/Traits/Activities/RemoveSelf.cs +++ b/OpenRA.Game/Traits/Activities/RemoveSelf.cs @@ -18,7 +18,7 @@ namespace OpenRA.Traits.Activities public IActivity Tick(Actor self) { if (isCanceled) return NextActivity; - self.World.AddFrameEndTask(w => w.Remove(self)); + self.Destroy(); return null; } diff --git a/OpenRA.Game/Traits/Activities/Sell.cs b/OpenRA.Game/Traits/Activities/Sell.cs index 1b7c8719cf..1c13b05aab 100644 --- a/OpenRA.Game/Traits/Activities/Sell.cs +++ b/OpenRA.Game/Traits/Activities/Sell.cs @@ -30,7 +30,7 @@ namespace OpenRA.Traits.Activities foreach (var ns in self.TraitsImplementing()) ns.Sold(self); - self.World.AddFrameEndTask( _ => self.World.Remove( self ) ); + self.Destroy(); } public IActivity Tick(Actor self) diff --git a/OpenRA.Game/World.cs b/OpenRA.Game/World.cs index c4029b067d..38740b1c6e 100644 --- a/OpenRA.Game/World.cs +++ b/OpenRA.Game/World.cs @@ -173,8 +173,9 @@ namespace OpenRA Game.viewport.Tick(); Timer.Time(" viewport: {0:0.000}"); - while( frameEndActions.Count != 0 ) - frameEndActions.Dequeue()( this ); + while (frameEndActions.Count != 0) + frameEndActions.Dequeue()(this); + Timer.Time(" frameEndActions: {0:0.000}"); WorldRenderer.Tick(); @@ -215,9 +216,9 @@ namespace OpenRA OwnedBy = new Cache(p => new OwnedByCachedView(world, world.actors, x => x.Owner == p)); } - public CachedView> WithTrait() + public IEnumerable> WithTrait() { - return WithTraitInner( world.actors, hasTrait ); + return world.traitDict.ActorsWithTraitMultiple( world ); } static CachedView> WithTraitInner( Set set, TypeDictionary hasTrait ) @@ -233,28 +234,9 @@ namespace OpenRA return ret; } - public CachedView> WithTraitMultiple() + public IEnumerable> WithTraitMultiple() { - var ret = hasTrait.GetOrDefault>>(); - if( ret != null ) - return ret; - ret = new CachedView>( - world.actors, - x => x.HasTrait(), - x => x.TraitsImplementing().Select( t => new TraitPair { Actor = x, Trait = t } ) ); - hasTrait.Add( ret ); - return ret; - } - - public struct TraitPair - { - public Actor Actor; - public T Trait; - - public override string ToString() - { - return "{0}->{1}".F( Actor.Info.Name, Trait.GetType().Name ); - } + return world.traitDict.ActorsWithTraitMultiple( world ); } public class OwnedByCachedView : CachedView @@ -275,4 +257,15 @@ namespace OpenRA public AllQueries Queries; } + + public struct TraitPair + { + public Actor Actor; + public T Trait; + + public override string ToString() + { + return "{0}->{1}".F( Actor.Info.Name, Trait.GetType().Name ); + } + } } diff --git a/OpenRA.Mods.Cnc/DeadBuildingState.cs b/OpenRA.Mods.Cnc/DeadBuildingState.cs index 242d1428fb..344a002fd0 100644 --- a/OpenRA.Mods.Cnc/DeadBuildingState.cs +++ b/OpenRA.Mods.Cnc/DeadBuildingState.cs @@ -41,7 +41,7 @@ namespace OpenRA.Mods.Cnc self.World.AddFrameEndTask( w => w.Add( new DelayedAction(info.LingerTime, - () => w.Remove(self)))); + () => self.Destroy()))); } } } diff --git a/OpenRA.Mods.RA/Activities/CaptureBuilding.cs b/OpenRA.Mods.RA/Activities/CaptureBuilding.cs index 41c81cb392..c55374323e 100644 --- a/OpenRA.Mods.RA/Activities/CaptureBuilding.cs +++ b/OpenRA.Mods.RA/Activities/CaptureBuilding.cs @@ -34,8 +34,8 @@ namespace OpenRA.Mods.RA.Activities foreach (var t in target.TraitsImplementing()) t.OnCapture(target, self, oldOwner, self.Owner); - - w.Remove(self); + + self.Destroy(); }); return NextActivity; } diff --git a/OpenRA.Mods.RA/Activities/Infiltrate.cs b/OpenRA.Mods.RA/Activities/Infiltrate.cs index df1551054a..c88eea579b 100644 --- a/OpenRA.Mods.RA/Activities/Infiltrate.cs +++ b/OpenRA.Mods.RA/Activities/Infiltrate.cs @@ -26,7 +26,7 @@ namespace OpenRA.Mods.RA.Activities foreach (var t in target.TraitsImplementing()) t.OnInfiltrate(target, self); - self.World.AddFrameEndTask(w => w.Remove(self)); + self.Destroy(); return NextActivity; } diff --git a/OpenRA.Mods.RA/Activities/RepairBuilding.cs b/OpenRA.Mods.RA/Activities/RepairBuilding.cs index 2aeed5d556..149801cf2c 100644 --- a/OpenRA.Mods.RA/Activities/RepairBuilding.cs +++ b/OpenRA.Mods.RA/Activities/RepairBuilding.cs @@ -27,8 +27,8 @@ namespace OpenRA.Mods.RA.Activities if (health.DamageState == DamageState.Undamaged) return NextActivity; - target.InflictDamage(self, -health.MaxHP, null); - self.World.AddFrameEndTask(w => w.Remove(self)); + target.InflictDamage(self, -health.MaxHP, null); + self.Destroy(); return NextActivity; } diff --git a/OpenRA.Mods.RA/Activities/Transform.cs b/OpenRA.Mods.RA/Activities/Transform.cs index 5cffb5a020..26d32ec0e8 100644 --- a/OpenRA.Mods.RA/Activities/Transform.cs +++ b/OpenRA.Mods.RA/Activities/Transform.cs @@ -48,11 +48,11 @@ namespace OpenRA.Mods.RA.Activities self.World.AddFrameEndTask(w => { var selected = w.Selection.Contains(self); - - self.World.Remove(self); + + self.Destroy(); foreach (var s in sounds) Sound.PlayToPlayer(self.Owner, s, self.CenterLocation); - + var init = new TypeDictionary { new LocationInit( self.Location + offset ), diff --git a/OpenRA.Mods.RA/Crate.cs b/OpenRA.Mods.RA/Crate.cs index 6189d750a1..c3bc1146be 100644 --- a/OpenRA.Mods.RA/Crate.cs +++ b/OpenRA.Mods.RA/Crate.cs @@ -62,7 +62,7 @@ namespace OpenRA.Mods.RA var totalShares = shares.Sum(a => a.Second); var n = self.World.SharedRandom.Next(totalShares); - self.World.AddFrameEndTask(w => w.Remove(self)); + self.Destroy(); foreach (var s in shares) if (n < s.Second) { @@ -75,9 +75,9 @@ namespace OpenRA.Mods.RA public void Tick(Actor self) { - - if (++ticks >= self.Info.Traits.Get().Lifetime * 25) - self.World.AddFrameEndTask(w => w.Remove(self)); + + if( ++ticks >= self.Info.Traits.Get().Lifetime * 25 ) + self.Destroy(); } public int2 TopLeft { get { return Location; } } diff --git a/OpenRA.Mods.RA/DemoTruck.cs b/OpenRA.Mods.RA/DemoTruck.cs index 8266cff3e1..c45adfde19 100644 --- a/OpenRA.Mods.RA/DemoTruck.cs +++ b/OpenRA.Mods.RA/DemoTruck.cs @@ -45,7 +45,7 @@ namespace OpenRA.Mods.RA self.Kill(self); detonatedBy.Owner.Kills++; self.Owner.Deaths++; - w.Remove(self); + self.Destroy(); } ); } } diff --git a/OpenRA.Mods.RA/ReplaceWithActor.cs b/OpenRA.Mods.RA/ReplaceWithActor.cs index 768e7bad5c..d5c41556a5 100644 --- a/OpenRA.Mods.RA/ReplaceWithActor.cs +++ b/OpenRA.Mods.RA/ReplaceWithActor.cs @@ -26,8 +26,8 @@ namespace OpenRA.Mods.RA public ReplaceWithActor(Actor self, ReplaceWithActorInfo info) { self.World.AddFrameEndTask(w => - { - w.Remove(self); + { + self.Destroy(); w.CreateActor(info.Actor, new TypeDictionary { new LocationInit( self.Location ), diff --git a/OpenRA.Mods.RA/SupportPowers/AirstrikePower.cs b/OpenRA.Mods.RA/SupportPowers/AirstrikePower.cs index d16391ceeb..ed9604bc11 100755 --- a/OpenRA.Mods.RA/SupportPowers/AirstrikePower.cs +++ b/OpenRA.Mods.RA/SupportPowers/AirstrikePower.cs @@ -65,7 +65,7 @@ namespace OpenRA.Mods.RA a.QueueActivity(new Fly(order.TargetLocation)); if (flare != null) - a.QueueActivity(new CallFunc(() => Owner.World.AddFrameEndTask(_w => _w.Remove(flare)))); + a.QueueActivity(new CallFunc(() => flare.Destroy())); a.QueueActivity(new FlyOffMap { Interruptible = false }); a.QueueActivity(new RemoveSelf());