Прежний вопрос решен, пожалуйста, продолжайте до конца.
Итак, у меня есть этот код здесь:
using Harmony;
using RimWorld;
using Verse;
using UnityEngine;
using System.Collections.Generic;
using System.Reflection.Emit;
using System;
using System.Reflection;
namespace RandomPlus
{
[HarmonyPatch (typeof(Page_ConfigureStartingPawns), "RandomizeCurPawn")]
class Patch_RandomizeMethod
{
static void Prefix ()
{
RandomSettings.ResetRerollCounter ();
}
static IEnumerable<CodeInstruction> Transpiler (IEnumerable<CodeInstruction> instructions)
{
var curPawnFieldInfo = typeof(Page_ConfigureStartingPawns)
.GetField ("curPawn", BindingFlags.NonPublic | BindingFlags.Instance);
var randomizeInPlaceMethodInfo = typeof(StartingPawnUtility)
.GetMethod ("RandomizeInPlace", BindingFlags.Public | BindingFlags.Static);
var checkPawnIsSatisfiedMethodInfo = typeof(RandomSettings)
.GetMethod ("CheckPawnIsSatisfied", BindingFlags.Public | BindingFlags.Static);
var codes = new List<CodeInstruction> (instructions);
var appropriatePlace = 6;
/* Removing the following code in its IL form */
// this.curPawn = StartingPawnUtility.RandomizeInPlace(this.curPawn);
codes.RemoveRange (appropriatePlace, 5);
/* Adding the following code in its IL form: */
// do {
// this.curPawn = StartingPawnUtility.RandomizeInPlace (this.curPawn);
// } while (!RandomSettings.CheckPawnIsSatisfiedMethodInfo);
//
// // loop start (head: IL_0016)
// IL_0016: nop
// IL_0017: ldarg.0
// IL_0018: ldarg.0
// IL_0019: ldarg.0
// IL_001a: ldfld int32 C::curPawn
// IL_001f: call instance int32 C::RandomizeInPlace(int32)
// IL_0024: stfld int32 C::curPawn
// IL_0029: nop
// IL_002a: ldarg.0
// IL_002b: call instance bool C::CheckPawnIsSatisfied()
// IL_0030: ldc.i4.0
// IL_0031: ceq
// IL_0033: stloc.1
// // sequence point: hidden
// IL_0034: ldloc.1
// IL_0035: brtrue.s IL_0016
// // end loop
List <CodeInstruction> newCodes = new List<CodeInstruction> {
new CodeInstruction (OpCodes.Nop),
new CodeInstruction (OpCodes.Ldarg_0),
new CodeInstruction (OpCodes.Ldarg_0),
new CodeInstruction (OpCodes.Ldarg_0),
new CodeInstruction (OpCodes.Ldfld, curPawnFieldInfo),
new CodeInstruction (OpCodes.Call, randomizeInPlaceMethodInfo),
new CodeInstruction (OpCodes.Stfld, curPawnFieldInfo),
new CodeInstruction (OpCodes.Nop),
new CodeInstruction (OpCodes.Ldarg_0),
new CodeInstruction (OpCodes.Call, checkPawnIsSatisfiedMethodInfo),
new CodeInstruction (OpCodes.Ldc_I4_0),
new CodeInstruction (OpCodes.Ceq),
new CodeInstruction (OpCodes.Stloc_1),
new CodeInstruction (OpCodes.Ldloc_1),
};
newCodes [0].labels.Add (new Label ());
var nopLabel = newCodes [0].labels [0];
newCodes.Add (new CodeInstruction (OpCodes.Brtrue_S, nopLabel));
codes.InsertRange (appropriatePlace, newCodes);
for (var i = 0; i < codes.Count; i++) {
Log.Message (codes [i].ToString ());
}
return codes;
}
}
}
Что он в основном делает, так это изменяеткод метода в IL, и он должен изменить это
private void RandomizeCurPawn()
{
if (!TutorSystem.AllowAction("RandomizePawn"))
{
return;
}
this.curPawn = StartingPawnUtility.RandomizeInPlace(this.curPawn);
TutorSystem.Notify_Event("RandomizePawn");
}
на:
private void RandomizeCurPawn()
{
if (!TutorSystem.AllowAction("RandomizePawn"))
{
return;
}
do
{
this.curPawn = StartingPawnUtility.RandomizeInPlace(this.curPawn);
}
while (!RandomSettings.CheckPawnIsSatisfiedMethodInfo);
TutorSystem.Notify_Event("RandomizePawn");
}
И чтобы получить код IL для части с помощью while, я пришелс этим примером программы , чтобы я мог получить код и изменить его для своих нужд, но, хотя я правильно скопировал код IL (насколько я могу судить), он не работает и выдает исключение, котороеговорит:
Could not execute post-long-event action. Exception: System.TypeInitializationException: An exception was thrown by the type initializer for RandomPlus.HarmonyPatches ---> System.FormatException: Method RimWorld.Page_ConfigureStartingPawns.RandomizeCurPawn() cannot be patched. Reason: Invalid IL code in (wrapper dynamic-method) RimWorld.Page_ConfigureStartingPawns:RandomizeCurPawn_Patch1 (object): IL_003c: stloc.1
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__7_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 RandomPlus.HarmonyPatches..cctor () [0x00000] in <filename unknown>:0
--- End of inner exception stack trace ---
at (wrapper managed-to-native) System.Runtime.CompilerServices.RuntimeHelpers:RunClassConstructor (intptr)
at System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor (RuntimeTypeHandle type) [0x00000] in <filename unknown>:0
at Verse.StaticConstructorOnStartupUtility.CallAll () [0x00000] in <filename unknown>:0
at Verse.PlayDataLoader.<DoPlayLoad>m__2 () [0x00000] in <filename unknown>:0
at Verse.LongEventHandler.ExecuteToExecuteWhenFinished () [0x00000] in <filename unknown>:0
Verse.Log:Error(String)
Verse.LongEventHandler:ExecuteToExecuteWhenFinished()
Verse.LongEventHandler:UpdateCurrentAsynchronousEvent()
Verse.LongEventHandler:LongEventsUpdate(Boolean&)
Verse.Root:Update()
Verse.Root_Entry:Update()
Как видите, он жалуется на строку "stloc.1", и я не уверен почему.Если кто-нибудь знает, как решить эту проблему, пожалуйста, дайте мне знать, я был бы очень признателен!
UPD.
Я хотел бы задать еще один вопрос здесьчем создать отдельный.
Вот что изменилось:
// // loop start (head: IL_000e)
// IL_000e: ldarg.0
// IL_000f: ldarg.0
// IL_0010: ldarg.0
// IL_0011: ldfld int32 C::curPawn
// IL_0016: call instance int32 C::RandomizeInPlace(int32)
// IL_001b: stfld int32 C::curPawn
// IL_0020: ldarg.0
// IL_0021: call instance bool C::CheckPawnIsSatisfied()
// IL_0026: brfalse.s IL_000e
// // end loop
List <CodeInstruction> newCodes = new List<CodeInstruction> {
new CodeInstruction (OpCodes.Ldarg_0),
new CodeInstruction (OpCodes.Ldarg_0),
new CodeInstruction (OpCodes.Ldarg_0),
new CodeInstruction (OpCodes.Ldfld, curPawnFieldInfo),
new CodeInstruction (OpCodes.Call, randomizeInPlaceMethodInfo),
new CodeInstruction (OpCodes.Stfld, curPawnFieldInfo),
new CodeInstruction (OpCodes.Ldarg_0),
new CodeInstruction (OpCodes.Call, checkPawnIsSatisfiedMethodInfo),
};
Игра теперь показывает мне эту ошибку:
Could not execute post-long-event action. Exception: System.TypeInitializationException: An exception was thrown by the type initializer for RandomPlus.HarmonyPatches ---> System.FormatException: Method RimWorld.Page_ConfigureStartingPawns.RandomizeCurPawn() cannot be patched. Reason: Invalid IL code in (wrapper dynamic-method) RimWorld.Page_ConfigureStartingPawns:RandomizeCurPawn_Patch1 (object): IL_003c: call 0x00000011
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__7_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 RandomPlus.HarmonyPatches..cctor () [0x00000] in <filename unknown>:0
--- End of inner exception stack trace ---
at (wrapper managed-to-native) System.Runtime.CompilerServices.RuntimeHelpers:RunClassConstructor (intptr)
at System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor (RuntimeTypeHandle type) [0x00000] in <filename unknown>:0
at Verse.StaticConstructorOnStartupUtility.CallAll () [0x00000] in <filename unknown>:0
at Verse.PlayDataLoader.<DoPlayLoad>m__2 () [0x00000] in <filename unknown>:0
at Verse.LongEventHandler.ExecuteToExecuteWhenFinished () [0x00000] in <filename unknown>:0
Verse.Log:Error(String)
Verse.LongEventHandler:ExecuteToExecuteWhenFinished()
Как вы думаете, это потому, что яне передать аргумент для RandomizeInPlace?
UPD2:
Я обновил площадку , и вот мой текущий код и ошибка:
List <CodeInstruction> newCodes = new List<CodeInstruction> {
new CodeInstruction (OpCodes.Ldarg_0),
new CodeInstruction (OpCodes.Ldarg_0),
new CodeInstruction (OpCodes.Ldfld, curPawnFieldInfo),
new CodeInstruction (OpCodes.Call, randomizeInPlaceMethodInfo),
new CodeInstruction (OpCodes.Stfld, curPawnFieldInfo),
new CodeInstruction (OpCodes.Call, checkPawnIsSatisfiedMethodInfo),
};
Could not execute post-long-event action. Exception: System.TypeInitializationException: An exception was thrown by the type initializer for RandomPlus.HarmonyPatches ---> System.FormatException: Method RimWorld.Page_ConfigureStartingPawns.RandomizeCurPawn() cannot be patched. Reason: Invalid IL code in (wrapper dynamic-method) RimWorld.Page_ConfigureStartingPawns:RandomizeCurPawn_Patch1 (object): IL_003a: call 0x00000011