@@ -9,6 +9,7 @@
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Reflection.Emit;
|
||||
@@ -22,19 +23,36 @@ namespace OpenRA
|
||||
|
||||
public static class Sync
|
||||
{
|
||||
static Cache<Type, Func<object, int>> hashFuncCache = new Cache<Type, Func<object, int>>( t => GenerateHashFunc( t ) );
|
||||
static Cache<Type, Func<object, int>> hashFuncCache = new Cache<Type, Func<object, int>>(t => GenerateHashFunc(t));
|
||||
|
||||
public static int CalculateSyncHash( object obj )
|
||||
public static int CalculateSyncHash(object obj)
|
||||
{
|
||||
return hashFuncCache[ obj.GetType() ]( obj );
|
||||
return hashFuncCache[obj.GetType()](obj);
|
||||
}
|
||||
|
||||
static Dictionary<Type, MethodInfo> hashFunctions = new Dictionary<Type, MethodInfo>()
|
||||
{
|
||||
{typeof(int2), ((Func<int2, int>)hash_int2).Method},
|
||||
{typeof(CPos), ((Func<CPos, int>)hash_CPos).Method},
|
||||
{typeof(CVec), ((Func<CVec, int>)hash_CVec).Method},
|
||||
{typeof(PPos), ((Func<PPos, int>)hash_PPos).Method},
|
||||
{typeof(PVecInt), ((Func<PVecInt, int>)hash_PVecInt).Method},
|
||||
{typeof(PSubPos), ((Func<PSubPos, int>)hash_PSubPos).Method},
|
||||
{typeof(PSubVec), ((Func<PSubVec, int>)hash_PSubVec).Method},
|
||||
{typeof(WRange), ((Func<WRange, int>)hash<WRange>).Method},
|
||||
{typeof(WPos), ((Func<WPos, int>)hash<WPos>).Method},
|
||||
{typeof(WVec), ((Func<WVec, int>)hash<WVec>).Method},
|
||||
{typeof(WAngle), ((Func<WAngle, int>)hash<WAngle>).Method},
|
||||
{typeof(WRot), ((Func<WRot, int>)hash<WRot>).Method},
|
||||
{typeof(TypeDictionary), ((Func<TypeDictionary, int>)hash_tdict).Method},
|
||||
{typeof(Actor), ((Func<Actor, int>)hash_actor).Method},
|
||||
{typeof(Player), ((Func<Player, int>)hash_player).Method},
|
||||
};
|
||||
|
||||
static void EmitSyncOpcodes(Type type, ILGenerator il)
|
||||
{
|
||||
if (type == typeof(int))
|
||||
{
|
||||
il.Emit(OpCodes.Xor);
|
||||
}
|
||||
if (hashFunctions.ContainsKey(type))
|
||||
il.EmitCall(OpCodes.Call, hashFunctions[type], null);
|
||||
else if (type == typeof(bool))
|
||||
{
|
||||
var l = il.DefineLabel();
|
||||
@@ -43,90 +61,13 @@ namespace OpenRA
|
||||
il.Emit(OpCodes.Pop);
|
||||
il.Emit(OpCodes.Ldc_I4, 0x555);
|
||||
il.MarkLabel(l);
|
||||
il.Emit(OpCodes.Xor);
|
||||
}
|
||||
else if (type == typeof(int2))
|
||||
{
|
||||
il.EmitCall(OpCodes.Call, ((Func<int2, int>)hash_int2).Method, null);
|
||||
il.Emit(OpCodes.Xor);
|
||||
}
|
||||
else if (type == typeof(CPos))
|
||||
{
|
||||
il.EmitCall(OpCodes.Call, ((Func<CPos, int>)hash_CPos).Method, null);
|
||||
il.Emit(OpCodes.Xor);
|
||||
}
|
||||
else if (type == typeof(CVec))
|
||||
{
|
||||
il.EmitCall(OpCodes.Call, ((Func<CVec, int>)hash_CVec).Method, null);
|
||||
il.Emit(OpCodes.Xor);
|
||||
}
|
||||
else if (type == typeof(PPos))
|
||||
{
|
||||
il.EmitCall(OpCodes.Call, ((Func<PPos, int>)hash_PPos).Method, null);
|
||||
il.Emit(OpCodes.Xor);
|
||||
}
|
||||
else if (type == typeof(PVecInt))
|
||||
{
|
||||
il.EmitCall(OpCodes.Call, ((Func<PVecInt, int>)hash_PVecInt).Method, null);
|
||||
il.Emit(OpCodes.Xor);
|
||||
}
|
||||
else if (type == typeof(PSubPos))
|
||||
{
|
||||
il.EmitCall(OpCodes.Call, ((Func<PSubPos, int>)hash_PSubPos).Method, null);
|
||||
il.Emit(OpCodes.Xor);
|
||||
}
|
||||
else if (type == typeof(PSubVec))
|
||||
{
|
||||
il.EmitCall(OpCodes.Call, ((Func<PSubVec, int>)hash_PSubVec).Method, null);
|
||||
il.Emit(OpCodes.Xor);
|
||||
}
|
||||
else if (type == typeof(WRange))
|
||||
{
|
||||
il.EmitCall(OpCodes.Call, ((Func<WRange, int>)(a => a.GetHashCode())).Method, null);
|
||||
il.Emit(OpCodes.Xor);
|
||||
}
|
||||
else if (type == typeof(WPos))
|
||||
{
|
||||
il.EmitCall(OpCodes.Call, ((Func<WPos, int>)(a => a.GetHashCode())).Method, null);
|
||||
il.Emit(OpCodes.Xor);
|
||||
}
|
||||
else if (type == typeof(WVec))
|
||||
{
|
||||
il.EmitCall(OpCodes.Call, ((Func<WVec, int>)(a => a.GetHashCode())).Method, null);
|
||||
il.Emit(OpCodes.Xor);
|
||||
}
|
||||
else if (type == typeof(WAngle))
|
||||
{
|
||||
il.EmitCall(OpCodes.Call, ((Func<WAngle, int>)(a => a.GetHashCode())).Method, null);
|
||||
il.Emit(OpCodes.Xor);
|
||||
}
|
||||
else if (type == typeof(WRot))
|
||||
{
|
||||
il.EmitCall(OpCodes.Call, ((Func<WRot, int>)(a => a.GetHashCode())).Method, null);
|
||||
il.Emit(OpCodes.Xor);
|
||||
}
|
||||
else if (type == typeof(TypeDictionary))
|
||||
{
|
||||
il.EmitCall(OpCodes.Call, ((Func<TypeDictionary, int>)hash_tdict).Method, null);
|
||||
il.Emit(OpCodes.Xor);
|
||||
}
|
||||
else if (type == typeof(Actor))
|
||||
{
|
||||
il.EmitCall(OpCodes.Call, ((Func<Actor, int>)hash_actor).Method, null);
|
||||
il.Emit(OpCodes.Xor);
|
||||
}
|
||||
else if (type == typeof(Player))
|
||||
{
|
||||
il.EmitCall(OpCodes.Call, ((Func<Player, int>)hash_player).Method, null);
|
||||
il.Emit(OpCodes.Xor);
|
||||
}
|
||||
else if (type.HasAttribute<SyncAttribute>())
|
||||
{
|
||||
il.EmitCall(OpCodes.Call, ((Func<object, int>)CalculateSyncHash).Method, null);
|
||||
il.Emit(OpCodes.Xor);
|
||||
}
|
||||
else
|
||||
else if (type != typeof(int))
|
||||
throw new NotImplementedException("SyncAttribute on member of unhashable type: {0}".F(type.FullName));
|
||||
|
||||
il.Emit(OpCodes.Xor);
|
||||
}
|
||||
|
||||
public static Func<object, int> GenerateHashFunc(Type t)
|
||||
@@ -160,29 +101,29 @@ namespace OpenRA
|
||||
return (Func<object, int>)d.CreateDelegate(typeof(Func<object, int>));
|
||||
}
|
||||
|
||||
public static int hash_int2( int2 i2 )
|
||||
public static int hash_int2(int2 i2)
|
||||
{
|
||||
return ( ( i2.X * 5 ) ^ ( i2.Y * 3 ) ) / 4;
|
||||
return ((i2.X * 5) ^ (i2.Y * 3)) / 4;
|
||||
}
|
||||
|
||||
public static int hash_CPos( CPos i2 )
|
||||
public static int hash_CPos(CPos i2)
|
||||
{
|
||||
return ( ( i2.X * 5) ^ ( i2.Y * 3 ) ) / 4;
|
||||
return ((i2.X * 5) ^ (i2.Y * 3)) / 4;
|
||||
}
|
||||
|
||||
public static int hash_CVec( CVec i2 )
|
||||
public static int hash_CVec(CVec i2)
|
||||
{
|
||||
return ( ( i2.X * 5) ^ ( i2.Y * 3 ) ) / 4;
|
||||
return ((i2.X * 5) ^ (i2.Y * 3)) / 4;
|
||||
}
|
||||
|
||||
public static int hash_PPos( PPos i2 )
|
||||
public static int hash_PPos(PPos i2)
|
||||
{
|
||||
return ( ( i2.X * 5) ^ ( i2.Y * 3 ) ) / 4;
|
||||
return ((i2.X * 5) ^ (i2.Y * 3)) / 4;
|
||||
}
|
||||
|
||||
public static int hash_PVecInt( PVecInt i2 )
|
||||
public static int hash_PVecInt(PVecInt i2)
|
||||
{
|
||||
return ( ( i2.X * 5) ^ ( i2.Y * 3 ) ) / 4;
|
||||
return ((i2.X * 5) ^ (i2.Y * 3)) / 4;
|
||||
}
|
||||
|
||||
public static int hash_PSubPos(PSubPos i2)
|
||||
@@ -195,38 +136,45 @@ namespace OpenRA
|
||||
return ((i2.X * 5) ^ (i2.Y * 3)) / 4;
|
||||
}
|
||||
|
||||
public static int hash_tdict( TypeDictionary d )
|
||||
public static int hash_tdict(TypeDictionary d)
|
||||
{
|
||||
int ret = 0;
|
||||
foreach( var o in d )
|
||||
ret += CalculateSyncHash( o );
|
||||
foreach (var o in d)
|
||||
ret += CalculateSyncHash(o);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static int hash_actor( Actor a )
|
||||
public static int hash_actor(Actor a)
|
||||
{
|
||||
if( a != null )
|
||||
return (int)( a.ActorID << 16 );
|
||||
if (a != null)
|
||||
return (int)(a.ActorID << 16);
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static int hash_player( Player p )
|
||||
public static int hash_player(Player p)
|
||||
{
|
||||
if( p != null )
|
||||
return (int)( p.PlayerActor.ActorID << 16 ) * 0x567;
|
||||
if (p != null)
|
||||
return (int)(p.PlayerActor.ActorID << 16) * 0x567;
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static void CheckSyncUnchanged( World world, Action fn )
|
||||
public static int hash<T>(T t)
|
||||
{
|
||||
CheckSyncUnchanged( world, () => { fn(); return true; } );
|
||||
return t.GetHashCode();
|
||||
}
|
||||
|
||||
public static void CheckSyncUnchanged(World world, Action fn)
|
||||
{
|
||||
CheckSyncUnchanged(world, () => { fn(); return true; });
|
||||
}
|
||||
|
||||
static bool inUnsyncedCode = false;
|
||||
|
||||
public static T CheckSyncUnchanged<T>( World world, Func<T> fn )
|
||||
public static T CheckSyncUnchanged<T>(World world, Func<T> fn)
|
||||
{
|
||||
if( world == null ) return fn();
|
||||
if (world == null)
|
||||
return fn();
|
||||
|
||||
var shouldCheckSync = Game.Settings.Debug.SanityCheckUnsyncedCode;
|
||||
int sync = shouldCheckSync ? world.SyncHash() : 0;
|
||||
bool prevInUnsyncedCode = inUnsyncedCode;
|
||||
@@ -239,15 +187,15 @@ namespace OpenRA
|
||||
finally
|
||||
{
|
||||
inUnsyncedCode = prevInUnsyncedCode;
|
||||
if( shouldCheckSync && sync != world.SyncHash() )
|
||||
throw new InvalidOperationException( "CheckSyncUnchanged: sync-changing code may not run here" );
|
||||
if (shouldCheckSync && sync != world.SyncHash())
|
||||
throw new InvalidOperationException("CheckSyncUnchanged: sync-changing code may not run here");
|
||||
}
|
||||
}
|
||||
|
||||
public static void AssertUnsynced( string message )
|
||||
public static void AssertUnsynced(string message)
|
||||
{
|
||||
if( !inUnsyncedCode )
|
||||
throw new InvalidOperationException( message );
|
||||
if (!inUnsyncedCode)
|
||||
throw new InvalidOperationException(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,8 +90,13 @@ namespace OpenRA.Traits
|
||||
return false;
|
||||
|
||||
// Target ranges are calculated in 2D, so ignore height differences
|
||||
return Positions.Any(t => (t.X - origin.X)*(t.X - origin.X) +
|
||||
(t.Y - origin.Y)*(t.Y - origin.Y) <= range.Range*range.Range);
|
||||
var rangeSquared = range.Range*range.Range;
|
||||
return Positions.Any(t =>
|
||||
{
|
||||
var dx = (long)(t.X - origin.X);
|
||||
var dy = (long)(t.Y - origin.Y);
|
||||
return dx*dx + dy*dy <= rangeSquared;
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -30,8 +30,12 @@ namespace OpenRA.Widgets
|
||||
|
||||
public override bool HandleMouseInput(MouseInput mi)
|
||||
{
|
||||
if (ClickThrough) return false;
|
||||
if (!Draggable || moving && (!TakeFocus(mi) || mi.Button != MouseButton.Left)) return true;
|
||||
if (ClickThrough || !Bounds.Contains(mi.Location))
|
||||
return false;
|
||||
|
||||
if (!Draggable || moving && (!TakeFocus(mi) || mi.Button != MouseButton.Left))
|
||||
return true;
|
||||
|
||||
if (prevMouseLocation == null)
|
||||
prevMouseLocation = mi.Location;
|
||||
var vec = mi.Location - (int2)prevMouseLocation;
|
||||
@@ -51,6 +55,7 @@ namespace OpenRA.Widgets
|
||||
Bounds = new Rectangle(Bounds.X + vec.X, Bounds.Y + vec.Y, Bounds.Width, Bounds.Height);
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -22,14 +22,15 @@ namespace OpenRA.Mods.RA.Widgets
|
||||
public int AnimationLength = 5;
|
||||
public string RadarOnlineSound = null;
|
||||
public string RadarOfflineSound = null;
|
||||
public Func<bool> IsEnabled = () => false;
|
||||
public Func<bool> IsEnabled = () => true;
|
||||
public Action AfterOpen = () => {};
|
||||
public Action AfterClose = () => {};
|
||||
|
||||
float radarMinimapHeight;
|
||||
int frame = 0;
|
||||
bool hasRadar = false;
|
||||
int updateTicks = 0;
|
||||
int frame;
|
||||
bool hasRadar;
|
||||
bool cachedEnabled;
|
||||
int updateTicks;
|
||||
|
||||
float previewScale = 0;
|
||||
int2 previewOrigin = int2.Zero;
|
||||
@@ -43,7 +44,10 @@ namespace OpenRA.Mods.RA.Widgets
|
||||
readonly World world;
|
||||
|
||||
[ObjectCreator.UseCtor]
|
||||
public RadarWidget(World world) { this.world = world; }
|
||||
public RadarWidget(World world)
|
||||
{
|
||||
this.world = world;
|
||||
}
|
||||
|
||||
public override void Initialize(WidgetArgs args)
|
||||
{
|
||||
@@ -85,7 +89,7 @@ namespace OpenRA.Mods.RA.Widgets
|
||||
Modifiers = Game.GetModifierKeys()
|
||||
};
|
||||
|
||||
var cursor = world.OrderGenerator.GetCursor( world, loc, mi );
|
||||
var cursor = world.OrderGenerator.GetCursor(world, loc, mi);
|
||||
if (cursor == null)
|
||||
return "default";
|
||||
|
||||
@@ -94,10 +98,10 @@ namespace OpenRA.Mods.RA.Widgets
|
||||
|
||||
public override bool HandleMouseInput(MouseInput mi)
|
||||
{
|
||||
if (!hasRadar)
|
||||
return true;
|
||||
|
||||
if (!mapRect.Contains(mi.Location))
|
||||
return false;
|
||||
|
||||
if (!hasRadar)
|
||||
return true;
|
||||
|
||||
var loc = MinimapPixelToCell(mi.Location);
|
||||
@@ -127,8 +131,6 @@ namespace OpenRA.Mods.RA.Widgets
|
||||
return true;
|
||||
}
|
||||
|
||||
public override Rectangle EventBounds { get { return mapRect; } }
|
||||
|
||||
public override void Draw()
|
||||
{
|
||||
if (world == null)
|
||||
@@ -157,7 +159,6 @@ namespace OpenRA.Mods.RA.Widgets
|
||||
}
|
||||
}
|
||||
|
||||
bool cachedEnabled;
|
||||
public override void Tick()
|
||||
{
|
||||
// Update the radar animation even when its closed
|
||||
|
||||
Reference in New Issue
Block a user