Merge pull request #4611 from Mailaender/imove-crash

Fixed a crash in IMove
This commit is contained in:
Chris Forbes
2014-02-10 20:13:41 +13:00
2 changed files with 76 additions and 75 deletions

View File

@@ -15,13 +15,42 @@ using OpenRA.FileFormats;
namespace OpenRA namespace OpenRA
{ {
static class ListExts
{
public static int BinarySearchMany(this List<Actor> list, uint searchFor)
{
int start = 0;
int end = list.Count;
int mid = 0;
while (start != end)
{
mid = (start + end) / 2;
var c = list[mid].ActorID.CompareTo(searchFor);
if (c < 0)
start = mid + 1;
else
end = mid;
}
return start;
}
}
class TraitDictionary class TraitDictionary
{ {
// construct this delegate once.
static Func<Type, ITraitContainer> doCreateTraitContainer = CreateTraitContainer;
static ITraitContainer CreateTraitContainer(Type t)
{
return (ITraitContainer)typeof(TraitContainer<>).MakeGenericType(t)
.GetConstructor(Type.EmptyTypes).Invoke(null);
}
Dictionary<Type, ITraitContainer> traits = new Dictionary<Type, ITraitContainer>(); Dictionary<Type, ITraitContainer> traits = new Dictionary<Type, ITraitContainer>();
ITraitContainer InnerGet( Type t ) ITraitContainer InnerGet(Type t)
{ {
return traits.GetOrAdd( t, doCreateTraitContainer ); return traits.GetOrAdd(t, doCreateTraitContainer);
} }
public void PrintReport() public void PrintReport()
@@ -31,27 +60,19 @@ namespace OpenRA
Log.Write("traitreport", "{0}: {1}", t.Key.Name, t.Value.Queries); Log.Write("traitreport", "{0}: {1}", t.Key.Name, t.Value.Queries);
} }
// construct this delegate once. public void AddTrait(Actor actor, object val)
static Func<Type, ITraitContainer> doCreateTraitContainer = CreateTraitContainer;
static ITraitContainer CreateTraitContainer( Type t )
{
return (ITraitContainer)typeof( TraitContainer<> ).MakeGenericType( t )
.GetConstructor( Type.EmptyTypes ).Invoke( null );
}
public void AddTrait( Actor actor, object val )
{ {
var t = val.GetType(); var t = val.GetType();
foreach( var i in t.GetInterfaces() ) foreach (var i in t.GetInterfaces())
InnerAdd( actor, i, val ); InnerAdd(actor, i, val);
foreach( var tt in t.BaseTypes() ) foreach (var tt in t.BaseTypes())
InnerAdd( actor, tt, val ); InnerAdd(actor, tt, val);
} }
void InnerAdd( Actor actor, Type t, object val ) void InnerAdd(Actor actor, Type t, object val)
{ {
InnerGet( t ).Add( actor, val ); InnerGet(t).Add(actor, val);
} }
void CheckDestroyed(Actor actor) void CheckDestroyed(Actor actor)
@@ -60,45 +81,45 @@ namespace OpenRA
throw new InvalidOperationException("Attempted to get trait from destroyed object ({0})".F(actor)); throw new InvalidOperationException("Attempted to get trait from destroyed object ({0})".F(actor));
} }
public bool Contains<T>( Actor actor ) public bool Contains<T>(Actor actor)
{ {
CheckDestroyed(actor); CheckDestroyed(actor);
return ( (TraitContainer<T>)InnerGet( typeof( T ) ) ).GetMultiple( actor.ActorID ).Count() != 0; return ((TraitContainer<T>)InnerGet(typeof(T))).GetMultiple(actor.ActorID).Count() != 0;
} }
public T Get<T>( Actor actor ) public T Get<T>(Actor actor)
{ {
CheckDestroyed(actor); CheckDestroyed(actor);
return ( (TraitContainer<T>)InnerGet( typeof( T ) ) ).Get( actor.ActorID ); return ((TraitContainer<T>)InnerGet(typeof(T))).Get(actor.ActorID);
} }
public T GetOrDefault<T>( Actor actor ) public T GetOrDefault<T>(Actor actor)
{ {
CheckDestroyed(actor); CheckDestroyed(actor);
return ( (TraitContainer<T>)InnerGet( typeof( T ) ) ).GetOrDefault( actor.ActorID ); return ((TraitContainer<T>)InnerGet(typeof(T))).GetOrDefault(actor.ActorID);
} }
public IEnumerable<T> WithInterface<T>( Actor actor ) public IEnumerable<T> WithInterface<T>(Actor actor)
{ {
CheckDestroyed(actor); CheckDestroyed(actor);
return ( (TraitContainer<T>)InnerGet( typeof( T ) ) ).GetMultiple( actor.ActorID ); return ((TraitContainer<T>)InnerGet(typeof(T))).GetMultiple(actor.ActorID);
} }
public IEnumerable<TraitPair<T>> ActorsWithTraitMultiple<T>( World world ) public IEnumerable<TraitPair<T>> ActorsWithTraitMultiple<T>(World world)
{ {
return ( (TraitContainer<T>)InnerGet( typeof( T ) ) ).All(); return ((TraitContainer<T>)InnerGet(typeof(T))).All();
} }
public void RemoveActor( Actor a ) public void RemoveActor(Actor a)
{ {
foreach( var t in traits ) foreach (var t in traits)
t.Value.RemoveActor( a.ActorID ); t.Value.RemoveActor(a.ActorID);
} }
interface ITraitContainer interface ITraitContainer
{ {
void Add( Actor actor, object trait ); void Add(Actor actor, object trait);
void RemoveActor( uint actor ); void RemoveActor(uint actor);
int Queries { get; } int Queries { get; }
} }
@@ -111,14 +132,14 @@ namespace OpenRA
public int Queries { get { return queries; } } public int Queries { get { return queries; } }
public void Add( Actor actor, object trait ) public void Add(Actor actor, object trait)
{ {
var insertIndex = actors.BinarySearchMany( actor.ActorID + 1 ); var insertIndex = actors.BinarySearchMany(actor.ActorID + 1);
actors.Insert( insertIndex, actor ); actors.Insert(insertIndex, actor);
traits.Insert( insertIndex, (T)trait ); traits.Insert(insertIndex, (T)trait);
} }
public T Get( uint actor ) public T Get(uint actor)
{ {
var result = GetOrDefault(actor); var result = GetOrDefault(actor);
if ((object)result == null) if ((object)result == null)
@@ -126,24 +147,24 @@ namespace OpenRA
return result; return result;
} }
public T GetOrDefault( uint actor ) public T GetOrDefault(uint actor)
{ {
++queries; ++queries;
var index = actors.BinarySearchMany( actor ); var index = actors.BinarySearchMany(actor);
if( index >= actors.Count || actors[ index ].ActorID != actor ) if (index >= actors.Count || actors[index].ActorID != actor)
return default( T ); return default(T);
else if( index + 1 < actors.Count && actors[ index + 1 ].ActorID == actor ) else if (index + 1 < actors.Count && actors[index + 1].ActorID == actor)
throw new InvalidOperationException("Actor has multiple traits of type `{0}`".F(typeof(T))); throw new InvalidOperationException("Actor has multiple traits of type `{0}`".F(typeof(T)));
else return traits[ index ]; else return traits[index];
} }
public IEnumerable<T> GetMultiple( uint actor ) public IEnumerable<T> GetMultiple(uint actor)
{ {
++queries; ++queries;
var index = actors.BinarySearchMany( actor ); var index = actors.BinarySearchMany(actor);
while( index < actors.Count && actors[ index ].ActorID == actor ) while (index < actors.Count && actors[index].ActorID == actor)
{ {
yield return traits[ index ]; yield return traits[index];
++index; ++index;
} }
} }
@@ -151,41 +172,21 @@ namespace OpenRA
public IEnumerable<TraitPair<T>> All() public IEnumerable<TraitPair<T>> All()
{ {
++queries; ++queries;
for( int i = 0 ; i < actors.Count ; i++ ) for (int i = 0; i < actors.Count; i++)
yield return new TraitPair<T> { Actor = actors[ i ], Trait = traits[ i ] }; yield return new TraitPair<T> { Actor = actors[i], Trait = traits[i] };
} }
public void RemoveActor( uint actor ) public void RemoveActor(uint actor)
{ {
for( int i = actors.Count - 1 ; i >= 0 ; i-- ) for (int i = actors.Count - 1; i >= 0; i--)
{ {
if( actors[ i ].ActorID == actor ) if (actors[i].ActorID == actor)
{ {
actors.RemoveAt( i ); actors.RemoveAt(i);
traits.RemoveAt( i ); traits.RemoveAt(i);
} }
} }
} }
} }
} }
static class ListExts
{
public static int BinarySearchMany( this List<Actor> list, uint searchFor )
{
int start = 0;
int end = list.Count;
int mid = 0;
while( start != end )
{
mid = ( start + end ) / 2;
var c = list[ mid ].ActorID.CompareTo( searchFor );
if( c < 0 )
start = mid + 1;
else
end = mid;
}
return start;
}
}
} }

View File

@@ -29,7 +29,7 @@ namespace OpenRA.Mods.RA.Move
public override Activity Tick(Actor self) public override Activity Tick(Actor self)
{ {
var positionable = self.Trait<IPositionable>(); var positionable = self.Trait<IPositionable>();
var movement = self.Trait<IMove>(); var movement = self.TraitOrDefault<IMove>();
var pos = length > 1 var pos = length > 1
? WPos.Lerp(start, end, ticks, length - 1) ? WPos.Lerp(start, end, ticks, length - 1)