From bed26c3dee4a1b942a22bdc8f620aa8d97a19cda Mon Sep 17 00:00:00 2001 From: Sascha Biedermann Date: Wed, 3 Apr 2013 23:32:05 +0200 Subject: [PATCH 1/2] fixes #2941 - dump fields in syncreport --- OpenRA.Game/Network/SyncReport.cs | 121 ++++++++++++++++++++++++++++-- 1 file changed, 113 insertions(+), 8 deletions(-) diff --git a/OpenRA.Game/Network/SyncReport.cs b/OpenRA.Game/Network/SyncReport.cs index a5d7f966ad..016a410840 100755 --- a/OpenRA.Game/Network/SyncReport.cs +++ b/OpenRA.Game/Network/SyncReport.cs @@ -9,11 +9,18 @@ #endregion using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Reflection.Emit; +using System; +using OpenRA.FileFormats; namespace OpenRA.Network { class SyncReport { + static Cache>> dumpFuncCache = new Cache>>( t => GenerateDumpFunc( t ) ); + readonly OrderManager orderManager; const int numSyncReports = 5; Report[] syncReports = new Report[numSyncReports]; @@ -32,6 +39,92 @@ namespace OpenRA.Network curIndex = ++curIndex % numSyncReports; } + public static Dictionary DumpSyncTrait( object obj ) + { + return dumpFuncCache[ obj.GetType() ]( obj ); + } + + public static Func> GenerateDumpFunc(Type t) + { + var dictType = typeof(Dictionary); + + var d = new DynamicMethod("dump_{0}".F(t.Name), dictType, new Type[] { typeof(object) }, t); + var il = d.GetILGenerator(); + + var this_ = il.DeclareLocal(t).LocalIndex; + var dict_ = il.DeclareLocal(dictType).LocalIndex; + var obj_ = il.DeclareLocal(typeof(object)).LocalIndex; + + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Castclass, t); + il.Emit(OpCodes.Stloc, this_); + + + var dictAdd_ = dictType.GetMethod("Add", BindingFlags.Instance | BindingFlags.Public, null, new Type[] { typeof(string), typeof(string) }, null); + var dictCtor_ = dictType.GetConstructor(Type.EmptyTypes); + var objToString_ = typeof(object).GetMethod("ToString", BindingFlags.Instance | BindingFlags.Public, null, Type.EmptyTypes, null); + + il.Emit(OpCodes.Newobj, dictCtor_); + il.Emit(OpCodes.Stloc, dict_); + + const BindingFlags bf = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance; + foreach (var field in t.GetFields(bf).Where(x => x.HasAttribute())) + { + if (field.IsLiteral || field.IsStatic) continue; + + var lblNull = il.DefineLabel(); + + il.Emit(OpCodes.Ldloc, this_); + il.Emit(OpCodes.Ldfld, field); + + if (field.FieldType.IsValueType) + il.Emit(OpCodes.Box, field.FieldType); + + il.Emit(OpCodes.Dup); + il.Emit(OpCodes.Stloc, obj_); + + il.Emit(OpCodes.Brfalse, lblNull); + + il.Emit(OpCodes.Ldloc, dict_); + il.Emit(OpCodes.Ldstr, field.Name); + + il.Emit(OpCodes.Ldloc, obj_); + il.Emit(OpCodes.Callvirt, objToString_); + il.Emit(OpCodes.Callvirt, dictAdd_); + + il.MarkLabel(lblNull); + } + + foreach (var prop in t.GetProperties(bf).Where(x => x.HasAttribute())) + { + var lblNull = il.DefineLabel(); + + il.Emit(OpCodes.Ldloc, this_); + il.EmitCall(OpCodes.Call, prop.GetGetMethod(), null); + + if (prop.PropertyType.IsValueType) + il.Emit(OpCodes.Box, prop.PropertyType); + + il.Emit(OpCodes.Dup); + il.Emit(OpCodes.Stloc, obj_); + + il.Emit(OpCodes.Brfalse, lblNull); + + il.Emit(OpCodes.Ldloc, dict_); + il.Emit(OpCodes.Ldstr, prop.Name); + + il.Emit(OpCodes.Ldloc, obj_); + il.Emit(OpCodes.Callvirt, objToString_); + il.Emit(OpCodes.Callvirt, dictAdd_); + + il.MarkLabel(lblNull); + } + + il.Emit(OpCodes.Ldloc, dict_); + il.Emit(OpCodes.Ret); + return (Func>) d.CreateDelegate(typeof(Func>)); + } + void GenerateSyncReport(Report report) { report.Frame = orderManager.NetFrameNumber; @@ -42,14 +135,19 @@ namespace OpenRA.Network { var sync = Sync.CalculateSyncHash(a.Trait); if (sync != 0) - report.Traits.Add(new TraitReport() - { - ActorID = a.Actor.ActorID, - Type = a.Actor.Info.Name, - Owner = (a.Actor.Owner == null) ? "null" : a.Actor.Owner.PlayerName, - Trait = a.Trait.GetType().Name, - Hash = sync - }); + { + var tr = new TraitReport() + { + ActorID = a.Actor.ActorID, + Type = a.Actor.Info.Name, + Owner = (a.Actor.Owner == null) ? "null" : a.Actor.Owner.PlayerName, + Trait = a.Trait.GetType().Name, + Hash = sync + }; + + tr.Fields = DumpSyncTrait(a.Trait); + report.Traits.Add(tr); + } } } @@ -62,6 +160,7 @@ namespace OpenRA.Network Log.Write("sync", "SharedRandom: {0} (#{1})", r.SyncedRandom, r.TotalCount); Log.Write("sync", "Synced Traits:"); foreach (var a in r.Traits) + { Log.Write("sync", "\t {0} {1} {2} {3} ({4})".F( a.ActorID, a.Type, @@ -69,6 +168,11 @@ namespace OpenRA.Network a.Trait, a.Hash )); + + foreach (var f in a.Fields) + Log.Write("sync", "\t\t {0}: {1}".F(f.Key, f.Value)); + + } return; } Log.Write("sync", "No sync report available!"); @@ -89,6 +193,7 @@ namespace OpenRA.Network public string Owner; public string Trait; public int Hash; + public Dictionary Fields; } } From 2fb12f755aef040ee0ab2aa8dbdc7dacbaaac4a8 Mon Sep 17 00:00:00 2001 From: Sascha Biedermann Date: Sun, 7 Apr 2013 17:01:55 +0200 Subject: [PATCH 2/2] added ToString() for OpenRA.Player --- OpenRA.Game/Network/SyncReport.cs | 1 - OpenRA.Game/Player.cs | 5 +++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/OpenRA.Game/Network/SyncReport.cs b/OpenRA.Game/Network/SyncReport.cs index 016a410840..e8b911f7cf 100755 --- a/OpenRA.Game/Network/SyncReport.cs +++ b/OpenRA.Game/Network/SyncReport.cs @@ -59,7 +59,6 @@ namespace OpenRA.Network il.Emit(OpCodes.Castclass, t); il.Emit(OpCodes.Stloc, this_); - var dictAdd_ = dictType.GetMethod("Add", BindingFlags.Instance | BindingFlags.Public, null, new Type[] { typeof(string), typeof(string) }, null); var dictCtor_ = dictType.GetConstructor(Type.EmptyTypes); var objToString_ = typeof(object).GetMethod("ToString", BindingFlags.Instance | BindingFlags.Public, null, Type.EmptyTypes, null); diff --git a/OpenRA.Game/Player.cs b/OpenRA.Game/Player.cs index 74c7853efb..f519afb903 100644 --- a/OpenRA.Game/Player.cs +++ b/OpenRA.Game/Player.cs @@ -91,6 +91,11 @@ namespace OpenRA } } + public override string ToString() + { + return "{0} ({1})".F(PlayerName, ClientIndex); + } + public Dictionary Stances = new Dictionary(); } }