From c0d0636e08375a0937b33eb47c878fc3b96e1409 Mon Sep 17 00:00:00 2001 From: Bob Date: Sat, 14 Aug 2010 20:11:54 +1200 Subject: [PATCH] store traits differently (index on trait class rather than actor) --- OpenRA.FileFormats/TypeDictionary.cs | 2 +- OpenRA.Game/Actor.cs | 14 ++- OpenRA.Game/OpenRA.Game.csproj | 5 +- OpenRA.Game/Support/Program.cs | 1 + OpenRA.Game/TraitDictionary.cs | 139 +++++++++++++++++++++++++++ OpenRA.Game/World.cs | 1 + 6 files changed, 151 insertions(+), 11 deletions(-) create mode 100755 OpenRA.Game/TraitDictionary.cs diff --git a/OpenRA.FileFormats/TypeDictionary.cs b/OpenRA.FileFormats/TypeDictionary.cs index b7f86ef4b1..c751e41bb8 100644 --- a/OpenRA.FileFormats/TypeDictionary.cs +++ b/OpenRA.FileFormats/TypeDictionary.cs @@ -92,7 +92,7 @@ namespace OpenRA.FileFormats } } - static class TypeExts + public static class TypeExts { public static IEnumerable BaseTypes( this Type t ) { diff --git a/OpenRA.Game/Actor.cs b/OpenRA.Game/Actor.cs index fd6a438910..f46cc7e7a5 100755 --- a/OpenRA.Game/Actor.cs +++ b/OpenRA.Game/Actor.cs @@ -21,8 +21,6 @@ namespace OpenRA { public class Actor { - [Sync] - readonly TypeDictionary traits = new TypeDictionary(); public readonly ActorInfo Info; public readonly World World; @@ -191,27 +189,27 @@ namespace OpenRA public T Trait() { - return traits.Get(); + return World.traitDict.Get( this ); } public T TraitOrDefault() { - return traits.GetOrDefault(); + return World.traitDict.GetOrDefault( this ); } public IEnumerable TraitsImplementing() { - return traits.WithInterface(); + return World.traitDict.WithInterface( this ); } public bool HasTrait() { - return traits.Contains(); + return World.traitDict.Contains( this ); } - public void AddTrait( object t ) + public void AddTrait( object trait ) { - traits.Add( t ); + World.traitDict.Add( this, trait ); } } } diff --git a/OpenRA.Game/OpenRA.Game.csproj b/OpenRA.Game/OpenRA.Game.csproj index e7e06f3170..2a9a25e8f0 100755 --- a/OpenRA.Game/OpenRA.Game.csproj +++ b/OpenRA.Game/OpenRA.Game.csproj @@ -1,4 +1,4 @@ - + Debug @@ -238,6 +238,7 @@ + @@ -269,4 +270,4 @@ --> - \ No newline at end of file + diff --git a/OpenRA.Game/Support/Program.cs b/OpenRA.Game/Support/Program.cs index 1bd4422445..5c15085ecc 100644 --- a/OpenRA.Game/Support/Program.cs +++ b/OpenRA.Game/Support/Program.cs @@ -45,6 +45,7 @@ namespace OpenRA static void Run( string[] args ) { Game.Initialize( new Arguments(args) ); + GC.Collect(); Game.Run(); } } diff --git a/OpenRA.Game/TraitDictionary.cs b/OpenRA.Game/TraitDictionary.cs new file mode 100755 index 0000000000..d0eafffd87 --- /dev/null +++ b/OpenRA.Game/TraitDictionary.cs @@ -0,0 +1,139 @@ +#region Copyright & License Information +/* + * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) + * 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. For more information, + * see LICENSE. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Linq; +using OpenRA.FileFormats; +using System.Diagnostics; + +namespace OpenRA +{ + class TraitDictionary + { + Dictionary traits = new Dictionary(); + + ITraitContainer InnerGet( Type t ) + { + return traits.GetOrAdd( t, CreateTraitContainer ); + } + + static ITraitContainer CreateTraitContainer( Type t ) + { + return (ITraitContainer)typeof( TraitContainer<> ).MakeGenericType( t ) + .GetConstructor( new Type[ 0 ] ).Invoke( new object[ 0 ] ); + } + + public void Add( Actor actor, object val ) + { + var t = val.GetType(); + + foreach( var i in t.GetInterfaces() ) + InnerAdd( actor, i, val ); + foreach( var tt in t.BaseTypes() ) + InnerAdd( actor, tt, val ); + } + + void InnerAdd( Actor actor, Type t, object val ) + { + InnerGet( t ).Add( actor, val ); + } + + public bool Contains( Actor actor ) + { + return ( (TraitContainer)InnerGet( typeof( T ) ) ).GetMultiple( actor ).Count() != 0; + } + + public T Get( Actor actor ) + { + return ( (TraitContainer)InnerGet( typeof( T ) ) ).Get( actor ); + } + + public T GetOrDefault( Actor actor ) + { + return ( (TraitContainer)InnerGet( typeof( T ) ) ).GetOrDefault( actor ); + } + + public IEnumerable WithInterface( Actor actor ) + { + return ( (TraitContainer)InnerGet( typeof( T ) ) ).GetMultiple( actor ); + } + + interface ITraitContainer + { + void Add( Actor actor, object trait ); + } + + class TraitContainer : ITraitContainer + { + 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 ); + traits.Insert( insertIndex, (T)trait ); + } + + public T Get( Actor actor ) + { + var index = actors.BinarySearchMany( actor.ActorID ); + if( index >= actors.Count || actors[ index ] != actor.ActorID ) + 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 ) + throw new InvalidOperationException( string.Format( "TraitDictionary contains multiple instance of type `{0}`", typeof( T ) ) ); + else + return traits[ index ]; + } + + public T GetOrDefault( Actor actor ) + { + var index = actors.BinarySearchMany( actor.ActorID ); + if( index >= actors.Count || actors[ index ] != actor.ActorID ) + return default( T ); + else if( index + 1 < actors.Count && actors[ index + 1 ] == actor.ActorID ) + throw new InvalidOperationException( string.Format( "TraitDictionary contains multiple instance of type `{0}`", typeof( T ) ) ); + else return traits[ index ]; + } + + public IEnumerable GetMultiple( Actor actor ) + { + var index = actors.BinarySearchMany( actor.ActorID ); + while( index < actors.Count && actors[ index ] == actor.ActorID ) + { + yield return traits[ index ]; + ++index; + } + } + } + } + + static class ListExts + { + public static int BinarySearchMany( this List list, T searchFor ) + where T : IComparable + { + int start = 0; + int end = list.Count; + int mid = 0; + while( start != end ) + { + mid = ( start + end ) / 2; + var c = list[ mid ].CompareTo( searchFor ); + if( c < 0 ) + start = mid + 1; + else + end = mid; + } + return start; + } + } +} diff --git a/OpenRA.Game/World.cs b/OpenRA.Game/World.cs index 7a2ab9ff47..c4029b067d 100644 --- a/OpenRA.Game/World.cs +++ b/OpenRA.Game/World.cs @@ -25,6 +25,7 @@ namespace OpenRA { public class World { + internal TraitDictionary traitDict = new TraitDictionary(); Set actors = new Set(); List effects = new List(); Queue> frameEndActions = new Queue>();