using System; using System.Collections.Generic; using System.Reflection; using Mono.Cecil; using Mono.Cecil.Cil; namespace dtdfixer { class MainClass { public static void Main (string[] args) { ModuleDefinition module = ModuleDefinition.ReadModule ("Assembly-CSharp.dll"); TypeDefinition type = module.GetType ("GameManager"); if (isPatched (type)) { Console.WriteLine ("Assembly already patched"); return; } markTypePatched (module, type); mappingPatch (module); consoleOutputPatch (module); telnetPatch (module); connectLogPatch (module); publicCommandPermissionsPatch (module); playerDataPatch (module); module.Write ("Assembly-CSharp.patched.dll"); Console.WriteLine ("Done"); } private static void mappingPatch (ModuleDefinition module) { TypeDefinition type = module.GetType ("Chunk"); addHook (type, "CalcMapColors", true, 0, true, typeof(MapRendering).GetMethod ("RenderSingleChunk")); } private static void consoleOutputPatch (ModuleDefinition module) { TypeDefinition type = module.GetType ("ConsoleSdtd"); replaceMethod (type, "ExecuteCmdFromClient", true, 3, typeof(ConsoleOutputSeparator).GetMethod ("C_ExecuteCmdFromClient")); addHook (type, "Run", true, 0, true, typeof(ConsoleOutputSeparator).GetMethod ("C_Run")); replaceMethod (type, "SendResult", true, 1, typeof(ConsoleOutputSeparator).GetMethod ("C_SendResult")); } private static void playerDataPatch (ModuleDefinition module) { TypeDefinition type = module.GetType ("GameManager"); addHook (type, "SavePlayerData", true, 2, true, typeof(PlayerDataStuff).GetMethod ("GM_SavePlayerData")); addHook (type, "Awake", true, 0, true, typeof(CommandExtensions).GetMethod ("InitCommandExtensions")); } private static void publicCommandPermissionsPatch (ModuleDefinition module) { TypeDefinition type = module.GetType ("AdminTools"); replaceMethod (type, "GetAllowedCommandsList", true, 1, typeof(AdminToolsStuff).GetMethod ("GetAllowedCommandsList")); } private static void connectLogPatch (ModuleDefinition module) { TypeDefinition type = module.GetType ("GameManager"); addHook (type, "RequestToSpawnPlayer", true, 5, true, typeof(AllocsLogFunctions).GetMethod ("RequestToSpawnPlayer")); } private static void telnetPatch (ModuleDefinition module) { TypeDefinition type = module.GetType ("NetTelnetServer"); replaceMethod (type, ".ctor", false, 1, typeof(AllocsNetTelnetServer).GetMethod ("init")); replaceMethod (type, "Disconnect", false, 0, typeof(AllocsNetTelnetServer).GetMethod ("Disconnect")); replaceMethod (type, "SetConsole", false, 1, typeof(AllocsNetTelnetServer).GetMethod ("SetConsole")); replaceMethod (type, "WriteToClient", false, 1, typeof(AllocsNetTelnetServer).GetMethod ("WriteToClient")); } private static void markTypePatched (ModuleDefinition module, TypeDefinition type) { type.Fields.Add (new FieldDefinition ("AllocsPatch", Mono.Cecil.FieldAttributes.Private | Mono.Cecil.FieldAttributes.SpecialName, module.Import (typeof(int)))); } private static void addHook (TypeDefinition type, string methodName, bool addThisRef, int opCount, bool atEnd, MethodBase targetMethod) { foreach (MethodDefinition method in type.Methods) { if (method.Name.Equals (methodName)) { var il = method.Body.GetILProcessor (); var call = il.Create (OpCodes.Call, method.Module.Import (targetMethod)); if (atEnd) { int insBefore = method.Body.Instructions.Count; if (addThisRef) il.Append (il.Create (OpCodes.Ldarg, 0)); for (int op = 0; op < opCount; op++) { il.Append (il.Create (OpCodes.Ldarg, op + 1)); } il.Append (call); il.Remove (method.Body.Instructions [insBefore - 1]); il.Append (il.Create (OpCodes.Ret)); } else { var i = 0; if (addThisRef) il.InsertBefore (method.Body.Instructions [i++], il.Create (OpCodes.Ldarg, 0)); for (int op = 0; op < opCount; op++) { il.InsertBefore (method.Body.Instructions [i++], il.Create (OpCodes.Ldarg, op + 1)); } il.InsertBefore (method.Body.Instructions [i++], call); } return; } } Console.WriteLine ("ERROR: Did not find " + type.Name + "." + methodName + "()"); } private static void replaceMethod (TypeDefinition type, string methodName, bool addThisRef, int opCount, MethodBase targetMethod) { foreach (MethodDefinition method in type.Methods) { if (method.Name.Equals (methodName)) { var il = method.Body.GetILProcessor (); var call = il.Create (OpCodes.Call, method.Module.Import (targetMethod)); var i = 0; if (addThisRef) il.InsertBefore (method.Body.Instructions [i++], il.Create (OpCodes.Ldarg, 0)); for (int op = 0; op < opCount; op++) { il.InsertBefore (method.Body.Instructions [i++], il.Create (OpCodes.Ldarg, op + 1)); } il.InsertBefore (method.Body.Instructions [i++], call); il.InsertBefore (method.Body.Instructions [i++], il.Create (OpCodes.Ret)); return; } } Console.WriteLine ("ERROR: Did not find " + type.Name + "." + methodName + "()"); } private static bool isPatched (TypeDefinition type) { foreach (FieldDefinition fd in type.Fields) { if (fd.Name.Equals ("AllocsPatch")) { return true; } } return false; } } }