diff --git a/Source/Client/Syncing/Game/SyncFields.cs b/Source/Client/Syncing/Game/SyncFields.cs index a0e28313..8dd5ddb9 100644 --- a/Source/Client/Syncing/Game/SyncFields.cs +++ b/Source/Client/Syncing/Game/SyncFields.cs @@ -4,6 +4,9 @@ using RimWorld.Planet; using System; using System.Collections.Generic; +using System.Reflection; +using System.Reflection.Emit; +using HarmonyLib; using UnityEngine; using Verse; using static Verse.Widgets; @@ -396,12 +399,42 @@ static void DialogBillConfig(Dialog_BillConfig __instance) } } - [MpPrefix(typeof(BillRepeatModeUtility), nameof(BillRepeatModeUtility.MakeConfigFloatMenu), lambdaOrdinal: 0)] - [MpPrefix(typeof(BillRepeatModeUtility), nameof(BillRepeatModeUtility.MakeConfigFloatMenu), lambdaOrdinal: 1)] - [MpPrefix(typeof(BillRepeatModeUtility), nameof(BillRepeatModeUtility.MakeConfigFloatMenu), lambdaOrdinal: 2)] - static void BillRepeatMode(object __instance) + [MpTranspiler(typeof(BillRepeatModeUtility), nameof(BillRepeatModeUtility.MakeConfigFloatMenu))] + static IEnumerable BillConfigFloatMenuTranspiler(IEnumerable insts, MethodBase orig) { - SyncBillProduction.Watch(__instance.GetPropertyOrField("bill")); + // Find the last occurence of Find.WindowStack.Add(new FloatMenu(opts)) by searching for Find.WindowStack property access. + var findWindowStackGetProp = AccessTools.DeclaredPropertyGetter(typeof(Find), nameof(Find.WindowStack)); + var found = 0; + foreach (var inst in insts) + { + if (inst.Calls(findWindowStackGetProp)) + { + found++; + yield return new CodeInstruction(OpCodes.Ldarg_0); // Bill_Production bill + yield return new CodeInstruction(OpCodes.Ldloc_1); // List options + yield return new CodeInstruction(OpCodes.Call, ((Delegate) SyncBillConfigFloatMenuOptions).Method); + } + + yield return inst; + } + + if (found == 0) + { + throw new Exception("Unexpected code structure in BillRepeatModeUtility.MakeConfigFloatMenu (couldn't find `Find.WindowStack`)." + + " Bill repeat mode will not be synchronized!"); + } + + if (found > 1) + { + Log.Warning( + $"Atypical code structure in BillRepeatModeUtility.MakeConfigFloatMenu (`Find.WindowStack` occurred ${found} times)." + + " This may cause unexpected behaviour or desynchronization when interacting with a bill's repeat mode."); + } + } + + private static void SyncBillConfigFloatMenuOptions(Bill_Production bill, List opts) + { + WatchMenuOptions(() => SyncBillProduction.Watch(bill), opts); } [MpPrefix(typeof(ITab_Bills), nameof(ITab_Bills.TabUpdate))] @@ -491,11 +524,22 @@ static IEnumerable> WatchDropdowns(Action watchAction, foreach (var entry in dropdowns) { if (entry.option.action != null) - entry.option.action = (SyncFieldUtil.FieldWatchPrefix + watchAction + entry.option.action + SyncFieldUtil.FieldWatchPostfix); + entry.option.action = SyncFieldUtil.FieldWatchPrefix + watchAction + entry.option.action + SyncFieldUtil.FieldWatchPostfix; yield return entry; } } + static void WatchMenuOptions(Action watchAction, IEnumerable opts) + { + foreach (var entry in opts) + { + if (entry.action != null) + { + entry.action = SyncFieldUtil.FieldWatchPrefix + watchAction + entry.action + SyncFieldUtil.FieldWatchPostfix; + } + } + } + [MpPrefix(typeof(Gizmo_PruningConfig), nameof(Gizmo_PruningConfig.DrawBar))] static void WatchTreeConnectionStrength(Gizmo_PruningConfig __instance) { diff --git a/Source/Client/Util/MpPatch.cs b/Source/Client/Util/MpPatch.cs index e4c146ed..a56223d8 100644 --- a/Source/Client/Util/MpPatch.cs +++ b/Source/Client/Util/MpPatch.cs @@ -195,7 +195,7 @@ public MpTranspiler(string typeName, string method) : base(typeName, method) { } - public MpTranspiler(Type type, string method, Type[] argTypes) : base(type, method, argTypes) + public MpTranspiler(Type type, string method, Type[] argTypes = null) : base(type, method, argTypes) { }