Closed CannibarRechter closed 4 years ago
Update. Here is my entire attempt at patching it. Please note the annotations below (unrelated). I have used that method. I have used variations of explicit calls as well. You are just seeing the most current manual way of me getting at nested type. I've done it with "." notation also.
using Harmony; using System; using System.Reflection; using System.Collections.Generic; using Klei;
namespace HeatExchange { public class HeatExchangerPatches { public static class Mod_OnLoad { public static void OnLoad() { HarmonyInstance harmony = HarmonyInstance.Create("oni.cr.hex"); HarmonyInstance.DEBUG = true;
Debug.Log("--> Heat Exchanger attempting patch...");
//MethodInfo origMethod = AccessTools.Method(typeof(ConduitFlow.ConduitContents), "GetEffectiveCapacity");
MethodInfo origMethod = AccessTools.Method(typeof(ConduitFlow).GetNestedType("ConduitContents", BindingFlags.Public | BindingFlags.Instance), "GetEffectiveCapacity");
HarmonyMethod replaceMethod = new HarmonyMethod( typeof(ConduitContentsPatch), "Prefix" );
Debug.Log($"--> origMethod = {origMethod} replaceMethod = {replaceMethod}");
try{
harmony.Patch(
origMethod,
replaceMethod
);
}
catch( Exception e )
{
Debug.Log($"##### Exception { e }");
throw e;
}
Debug.Log("--> Heat Exchanger Mod loaded.");
}
}
public static class ConduitContentsPatch
{
public static void Prefix( ConduitFlow.ConduitContents __instance, float maximum_capacity )
{
float mass = __instance.mass;
Debug.Assert( mass <= maximum_capacity );
}
}
[HarmonyPatch(typeof(GeneratedBuildings))]
[HarmonyPatch(nameof(GeneratedBuildings.LoadGeneratedBuildings))]
public static class GeneratedBuildings_LoadGeneratedBuildings_Patch
{
public static void Prefix()
{
StringUtils.AddBuildingStrings(HeatExchangerConfig.ID, HeatExchangerConfig.DisplayName, HeatExchangerConfig.Description, HeatExchangerConfig.Effect);
BuildingUtils.AddBuildingToPlanScreen("Utilities", HeatExchangerConfig.ID);
}
}
[HarmonyPatch(typeof(Db))]
[HarmonyPatch("Initialize")]
public static class Db_Initialize_Patch
{
public static void Prefix()
{
BuildingUtils.AddBuildingToTechnology("LiquidTemperature", HeatExchangerConfig.ID);
}
}
}
}
Also, I turned off all other mods "just to be sure," except for the mod manager mod.
I've just hit exactly this same issue attempting to move my mod over to Harmony.
Environment: Windows 10, 64 bit. Pretty sure I'm running .NET 4 Harmony version: 1.2.0.1
Name of game: Cities:Skylines
The output from the C:S debug window is below:
The Mod C:\Users\XXXXX\AppData\Local\Colossal Order\Cities_Skylines\Addons\Mods\Crossings [0Harmony.dll, Crossings.dll] has caused an error [ModException]
Details:
System.FormatException: Method NetNode.CalculateNode(System.UInt16) cannot be patched. Reason: Invalid IL code in (wrapper dynamic-method) NetNode:CalculateNode_Patch1 (object,uint16): IL_0758: callvirt 0x0000011b
at Harmony.PatchFunctions.UpdateWrapper (System.Reflection.MethodBase original, Harmony.PatchInfo patchInfo, System.String instanceID) [0x00000] in <filename unknown>:0
at Harmony.PatchProcessor.Patch () [0x00000] in <filename unknown>:0
at Harmony.HarmonyInstance.<PatchAll>b__9_0 (System.Type type) [0x00000] in <filename unknown>:0
at Harmony.CollectionExtensions.Do[Type] (IEnumerable`1 sequence, System.Action`1 action) [0x00000] in <filename unknown>:0
at Harmony.HarmonyInstance.PatchAll (System.Reflection.Assembly assembly) [0x00000] in <filename unknown>:0
at Crossings.Loader.OnCreated (ILoading loading) [0x00000] in <filename unknown>:0
at LoadingWrapper.OnLoadingExtensionsCreated () [0x00000] in <filename unknown>:0
I'm running it with no other mods active, and the patch in question is pretty trivial:
using Harmony;
namespace Crossings
{
[HarmonyPatch(typeof(NetNode))]
[HarmonyPatch(nameof(NetNode.CalculateNode))]
class CalculateNode
{
static void Postfix(ref NetNode __instance)
{
bool isCrossing = (__instance.m_flags & (NetNode.Flags)Crossings.CrossingFlag) != NetNode.Flags.None;
if ((__instance.m_flags & (NetNode.Flags.Junction | NetNode.Flags.Bend | NetNode.Flags.End)) != NetNode.Flags.None)
{
__instance.m_flags |= ~(NetNode.Flags)Crossings.CrossingFlag;
}
if (isCrossing)
{
__instance.m_flags |= NetNode.Flags.Junction;
}
}
}
}
Please let me know if there's any more info I can provide to help debug this.
You can start by testing with Harmony 2.0b (no release yet, needs to be build from master). This will help to identify if this is an issue that was fixed after 1.2.0.1
It does indeed appear to be resolved in 2.0b - thanks for that.
Due to time constraints I cannot update v1.2.0.1 and rather make sure 2.0 comes out of beta as soon as possible.
Describe the bug
Exception issued when attempting to patch an inner class, as follows:
ConduitFlow+ConduitContents.GetEffectiveCapacity(System.Single) cannot be patched. Reason: Invalid IL code in (wrapper dynamic-method) ConduitFlow/ConduitContents:GetEffectiveCapacity_Patch1 (object,single): IL_000d: call 0x00000001 at Harmony.PatchFunctions.UpdateWrapper (System.Reflection.MethodBase original, Harmony.PatchInfo patchInfo, System.String instanceID) [0x00000] in:0
at Harmony.PatchProcessor.Patch () [0x00000] in :0
at Harmony.HarmonyInstance.Patch (System.Reflection.MethodBase original, Harmony.HarmonyMethod prefix, Harmony.HarmonyMethod postfix, Harmony.HarmonyMethod transpiler) [0x00000] in :0
at HeatExchange.HeatExchangerPatches+Mod_OnLoad.OnLoad () [0x00000] in :0
harmony.log.txt:
Patch ConduitFlow+ConduitContents, Single GetEffectiveCapacity(Single)
L_0000: Local var 0: System.Single L_0000: Local var 1: System.Single L_0000: ldc.r4 0 L_0005: stloc 1 (System.Single) L_0006: ldarg.0 L_0007: ldarg 1 L_000d: call Void Prefix(ConduitContents, Single) L_0012: ldarg.0 L_0013: call Single get_mass() L_0018: stloc.0 L_0019: ldloc.0 L_001a: ldarg.1 L_001b: cgt.un L_001d: ldc.i4.0 L_001e: ceq L_0020: ldstr "Effective mass cannot be greater than capacity!" L_0025: call Void DevAssert(Boolean, System.String) L_002a: ldc.r4 0 L_002f: ldarg.1 L_0030: ldloc.0 L_0031: sub L_0032: call Single Max(Single, Single) L_0037: stloc 1 (System.Single) L_0038: ldloc 1 (System.Single) L_0039: ret DONE
To Reproduce
Occurs with a prefix or postfix patch. Occurs with an annotation, or with an explicit call. Here is the outer class header:
public class ConduitFlow : IConduitFlow {
Here is the inner (struct) error:
Here it the method defintiion:
Expected behavior
Expect a succesful patch.
Screenshots / Code
See above. Can forward entire patched code file if needed.
Runtime environment (please complete the following information):
Windows 10, 64 bit. .NET 3.5 [assembly: AssemblyVersion("1.2.0.1")]
Additional context
"mono" appears at various times in the ONI decoompiled, so I suspect it is a mono app.