Tidy Sync.

This commit is contained in:
Paul Chote
2013-07-11 18:35:46 +12:00
parent 60f49b39d4
commit a49cc78c57

View File

@@ -9,6 +9,7 @@
#endregion #endregion
using System; using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Reflection.Emit; using System.Reflection.Emit;
@@ -22,19 +23,36 @@ namespace OpenRA
public static class Sync 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) static void EmitSyncOpcodes(Type type, ILGenerator il)
{ {
if (type == typeof(int)) if (hashFunctions.ContainsKey(type))
{ il.EmitCall(OpCodes.Call, hashFunctions[type], null);
il.Emit(OpCodes.Xor);
}
else if (type == typeof(bool)) else if (type == typeof(bool))
{ {
var l = il.DefineLabel(); var l = il.DefineLabel();
@@ -43,90 +61,13 @@ namespace OpenRA
il.Emit(OpCodes.Pop); il.Emit(OpCodes.Pop);
il.Emit(OpCodes.Ldc_I4, 0x555); il.Emit(OpCodes.Ldc_I4, 0x555);
il.MarkLabel(l); 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>)hash<WRange>).Method, null);
il.Emit(OpCodes.Xor);
}
else if (type == typeof(WPos))
{
il.EmitCall(OpCodes.Call, ((Func<WPos, int>)hash<WPos>).Method, null);
il.Emit(OpCodes.Xor);
}
else if (type == typeof(WVec))
{
il.EmitCall(OpCodes.Call, ((Func<WVec, int>)hash<WVec>).Method, null);
il.Emit(OpCodes.Xor);
}
else if (type == typeof(WAngle))
{
il.EmitCall(OpCodes.Call, ((Func<WAngle, int>)hash<WAngle>).Method, null);
il.Emit(OpCodes.Xor);
}
else if (type == typeof(WRot))
{
il.EmitCall(OpCodes.Call, ((Func<WRot, int>)hash<WRot>).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>()) else if (type.HasAttribute<SyncAttribute>())
{
il.EmitCall(OpCodes.Call, ((Func<object, int>)CalculateSyncHash).Method, null); il.EmitCall(OpCodes.Call, ((Func<object, int>)CalculateSyncHash).Method, null);
il.Emit(OpCodes.Xor); else if (type != typeof(int))
}
else
throw new NotImplementedException("SyncAttribute on member of unhashable type: {0}".F(type.FullName)); 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) public static Func<object, int> GenerateHashFunc(Type t)
@@ -160,29 +101,29 @@ namespace OpenRA
return (Func<object, int>)d.CreateDelegate(typeof(Func<object, int>)); 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) public static int hash_PSubPos(PSubPos i2)
@@ -195,25 +136,25 @@ namespace OpenRA
return ((i2.X * 5) ^ (i2.Y * 3)) / 4; 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; int ret = 0;
foreach( var o in d ) foreach (var o in d)
ret += CalculateSyncHash( o ); ret += CalculateSyncHash(o);
return ret; return ret;
} }
public static int hash_actor( Actor a ) public static int hash_actor(Actor a)
{ {
if( a != null ) if (a != null)
return (int)( a.ActorID << 16 ); return (int)(a.ActorID << 16);
return 0; return 0;
} }
public static int hash_player( Player p ) public static int hash_player(Player p)
{ {
if( p != null ) if (p != null)
return (int)( p.PlayerActor.ActorID << 16 ) * 0x567; return (int)(p.PlayerActor.ActorID << 16) * 0x567;
return 0; return 0;
} }
@@ -222,16 +163,18 @@ namespace OpenRA
return t.GetHashCode(); return t.GetHashCode();
} }
public static void CheckSyncUnchanged( World world, Action fn ) public static void CheckSyncUnchanged(World world, Action fn)
{ {
CheckSyncUnchanged( world, () => { fn(); return true; } ); CheckSyncUnchanged(world, () => { fn(); return true; });
} }
static bool inUnsyncedCode = false; 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; var shouldCheckSync = Game.Settings.Debug.SanityCheckUnsyncedCode;
int sync = shouldCheckSync ? world.SyncHash() : 0; int sync = shouldCheckSync ? world.SyncHash() : 0;
bool prevInUnsyncedCode = inUnsyncedCode; bool prevInUnsyncedCode = inUnsyncedCode;
@@ -244,15 +187,15 @@ namespace OpenRA
finally finally
{ {
inUnsyncedCode = prevInUnsyncedCode; inUnsyncedCode = prevInUnsyncedCode;
if( shouldCheckSync && sync != world.SyncHash() ) if (shouldCheckSync && sync != world.SyncHash())
throw new InvalidOperationException( "CheckSyncUnchanged: sync-changing code may not run here" ); 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 ) if (!inUnsyncedCode)
throw new InvalidOperationException( message ); throw new InvalidOperationException(message);
} }
} }
} }