提问人:redassser 提问时间:11/7/2023 最后编辑:redassser 更新时间:11/15/2023 访问量:48
使用 Harmony 修补 Unity 游戏的异步方法的实际内容
Using Harmony to patch the real content of an async method for a Unity game
问:
使用 dotPeek,我能够看到一个我想更改其一部分的方法,特别是 CreateLobbyAsync 中的 4 为另一个整数。
public async void StartHost()
{
if (!(bool) (UnityEngine.Object) UnityEngine.Object.FindObjectOfType<MenuManager>())
{
Debug.Log((object) "Menu manager script is not present in scene; unable to start host");
}
else
{
if (GameNetworkManager.Instance.currentLobby.HasValue)
{
Debug.Log((object) "Tried starting host but currentLobby is not null! This should not happen. Leaving currentLobby and setting null.");
this.LeaveCurrentSteamLobby();
}
if (!this.disableSteam)
{
GameNetworkManager gameNetworkManager = GameNetworkManager.Instance;
gameNetworkManager.currentLobby = await SteamMatchmaking.CreateLobbyAsync(4);
gameNetworkManager = (GameNetworkManager) null;
}
UnityEngine.Object.FindObjectOfType<MenuManager>().StartHosting();
this.SubscribeToConnectionCallbacks();
this.isHostingGame = true;
this.connectedPlayers = 1;
}
}
但是,基础 IL 显示,我要更改的实际功能不是保存在可访问的方法中,而是保存在另一个自动生成的方法中。
这是我想改变的方法。
StartHost() cil managed
{
.custom instance void [netstandard]System.Runtime.CompilerServices.AsyncStateMachineAttribute::.ctor(class [netstandard]System.Type)
= (
01 00 23 47 61 6d 65 4e 65 74 77 6f 72 6b 4d 61 // ..#GameNetworkMa
6e 61 67 65 72 2b 3c 53 74 61 72 74 48 6f 73 74 // nager+<StartHost
3e 64 5f 5f 37 39 00 00 // >d__79..
)
// type(valuetype GameNetworkManager/'<StartHost>d__79')
.maxstack 2
.locals init (
[0] valuetype GameNetworkManager/'<StartHost>d__79' V_0
)
IL_0000: ldloca.s V_0
IL_0002: call valuetype [netstandard]System.Runtime.CompilerServices.AsyncVoidMethodBuilder [netstandard]System.Runtime.CompilerServices.AsyncVoidMethodBuilder::Create()
IL_0007: stfld valuetype [netstandard]System.Runtime.CompilerServices.AsyncVoidMethodBuilder GameNetworkManager/'<StartHost>d__79'::'<>t__builder'
IL_000c: ldloca.s V_0
IL_000e: ldarg.0 // this
IL_000f: stfld class GameNetworkManager GameNetworkManager/'<StartHost>d__79'::'<>4__this'
IL_0014: ldloca.s V_0
IL_0016: ldc.i4.m1
IL_0017: stfld int32 GameNetworkManager/'<StartHost>d__79'::'<>1__state'
IL_001c: ldloca.s V_0
IL_001e: ldflda valuetype [netstandard]System.Runtime.CompilerServices.AsyncVoidMethodBuilder GameNetworkManager/'<StartHost>d__79'::'<>t__builder'
IL_0023: ldloca.s V_0
IL_0025: call instance void [netstandard]System.Runtime.CompilerServices.AsyncVoidMethodBuilder::Start<valuetype GameNetworkManager/'<StartHost>d__79'>(!!0/*valuetype GameNetworkManager/'<StartHost>d__79'*/&)
IL_002a: ret
} // end of method GameNetworkManager::StartHost
这是我无法访问的引用的真实功能
.class nested private sealed auto ansi beforefieldinit
'<StartHost>d__79'
extends [netstandard]System.ValueType
implements [netstandard]System.Runtime.CompilerServices.IAsyncStateMachine
{
.custom instance void [netstandard]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor()
= (01 00 00 00 )
.field public int32 '<>1__state'
.field public valuetype [netstandard]System.Runtime.CompilerServices.AsyncVoidMethodBuilder '<>t__builder'
.field public class GameNetworkManager '<>4__this'
.field private class GameNetworkManager '<>7__wrap1'
.field private valuetype [netstandard]System.Runtime.CompilerServices.TaskAwaiter`1<valuetype [netstandard]System.Nullable`1<valuetype [Facepunch.Steamworks.Win64]Steamworks.Data.Lobby>> '<>u__1'
.method private final hidebysig virtual newslot instance void
MoveNext() cil managed
{
.override method instance void [netstandard]System.Runtime.CompilerServices.IAsyncStateMachine::MoveNext()
.maxstack 3
.locals init (
[0] int32 V_0,
[1] class GameNetworkManager V_1,
[2] valuetype [netstandard]System.Nullable`1<valuetype [Facepunch.Steamworks.Win64]Steamworks.Data.Lobby> V_2,
[3] valuetype [netstandard]System.Runtime.CompilerServices.TaskAwaiter`1<valuetype [netstandard]System.Nullable`1<valuetype [Facepunch.Steamworks.Win64]Steamworks.Data.Lobby>> V_3,
[4] class [netstandard]System.Exception V_4
)
IL_0000: ldarg.0 // this
IL_0001: ldfld int32 GameNetworkManager/'<StartHost>d__79'::'<>1__state'
IL_0006: stloc.0 // V_0
IL_0007: ldarg.0 // this
IL_0008: ldfld class GameNetworkManager GameNetworkManager/'<StartHost>d__79'::'<>4__this'
IL_000d: stloc.1 // V_1
.try
{
IL_000e: ldloc.0 // V_0
IL_000f: brfalse IL_009e
// [654 5 - 654 89]
IL_0014: call !!0/*class MenuManager*/ [UnityEngine.CoreModule]UnityEngine.Object::FindObjectOfType<class MenuManager>()
IL_0019: call bool [UnityEngine.CoreModule]UnityEngine.Object::op_Implicit(class [UnityEngine.CoreModule]UnityEngine.Object)
IL_001e: brtrue.s IL_002f
// [656 7 - 656 94]
IL_0020: ldstr "Menu manager script is not present in scene; unable to start host"
IL_0025: call void [UnityEngine.CoreModule]UnityEngine.Debug::Log(object)
IL_002a: leave IL_010e
// [660 7 - 660 61]
IL_002f: call class GameNetworkManager GameNetworkManager::get_Instance()
IL_0034: callvirt instance valuetype [netstandard]System.Nullable`1<valuetype [Facepunch.Steamworks.Win64]Steamworks.Data.Lobby> GameNetworkManager::get_currentLobby()
IL_0039: stloc.2 // V_2
IL_003a: ldloca.s V_2
IL_003c: call instance bool valuetype [netstandard]System.Nullable`1<valuetype [Facepunch.Steamworks.Win64]Steamworks.Data.Lobby>::get_HasValue()
IL_0041: brfalse.s IL_0053
// [662 9 - 662 143]
IL_0043: ldstr "Tried starting host but currentLobby is not null! This should not happen. Leaving currentLobby and setting null."
IL_0048: call void [UnityEngine.CoreModule]UnityEngine.Debug::Log(object)
// [663 9 - 663 38]
IL_004d: ldloc.1 // V_1
IL_004e: call instance void GameNetworkManager::LeaveCurrentSteamLobby()
// [665 7 - 665 30]
IL_0053: ldloc.1 // V_1
IL_0054: ldfld bool GameNetworkManager::disableSteam
IL_0059: brtrue.s IL_00d5
// [667 9 - 667 76]
IL_005b: ldarg.0 // this
IL_005c: call class GameNetworkManager GameNetworkManager::get_Instance()
IL_0061: stfld class GameNetworkManager GameNetworkManager/'<StartHost>d__79'::'<>7__wrap1'
// [668 9 - 668 85]
IL_0066: ldc.i4.4
IL_0067: call class [netstandard]System.Threading.Tasks.Task`1<valuetype [netstandard]System.Nullable`1<valuetype [Facepunch.Steamworks.Win64]Steamworks.Data.Lobby>> [Facepunch.Steamworks.Win64]Steamworks.SteamMatchmaking::CreateLobbyAsync(int32)
IL_006c: callvirt instance valuetype [netstandard]System.Runtime.CompilerServices.TaskAwaiter`1<!0/*valuetype [netstandard]System.Nullable`1<valuetype [Facepunch.Steamworks.Win64]Steamworks.Data.Lobby>*/> class [netstandard]System.Threading.Tasks.Task`1<valuetype [netstandard]System.Nullable`1<valuetype [Facepunch.Steamworks.Win64]Steamworks.Data.Lobby>>::GetAwaiter()
IL_0071: stloc.3 // V_3
IL_0072: ldloca.s V_3
IL_0074: call instance bool valuetype [netstandard]System.Runtime.CompilerServices.TaskAwaiter`1<valuetype [netstandard]System.Nullable`1<valuetype [Facepunch.Steamworks.Win64]Steamworks.Data.Lobby>>::get_IsCompleted()
IL_0079: brtrue.s IL_00ba
IL_007b: ldarg.0 // this
IL_007c: ldc.i4.0
IL_007d: dup
IL_007e: stloc.0 // V_0
IL_007f: stfld int32 GameNetworkManager/'<StartHost>d__79'::'<>1__state'
IL_0084: ldarg.0 // this
IL_0085: ldloc.3 // V_3
IL_0086: stfld valuetype [netstandard]System.Runtime.CompilerServices.TaskAwaiter`1<valuetype [netstandard]System.Nullable`1<valuetype [Facepunch.Steamworks.Win64]Steamworks.Data.Lobby>> GameNetworkManager/'<StartHost>d__79'::'<>u__1'
IL_008b: ldarg.0 // this
IL_008c: ldflda valuetype [netstandard]System.Runtime.CompilerServices.AsyncVoidMethodBuilder GameNetworkManager/'<StartHost>d__79'::'<>t__builder'
IL_0091: ldloca.s V_3
IL_0093: ldarg.0 // this
IL_0094: call instance void [netstandard]System.Runtime.CompilerServices.AsyncVoidMethodBuilder::AwaitUnsafeOnCompleted<valuetype [netstandard]System.Runtime.CompilerServices.TaskAwaiter`1<valuetype [netstandard]System.Nullable`1<valuetype [Facepunch.Steamworks.Win64]Steamworks.Data.Lobby>>, valuetype GameNetworkManager/'<StartHost>d__79'>(!!0/*valuetype [netstandard]System.Runtime.CompilerServices.TaskAwaiter`1<valuetype [netstandard]System.Nullable`1<valuetype [Facepunch.Steamworks.Win64]Steamworks.Data.Lobby>>*/&, !!1/*valuetype GameNetworkManager/'<StartHost>d__79'*/&)
IL_0099: leave IL_0121
IL_009e: ldarg.0 // this
IL_009f: ldfld valuetype [netstandard]System.Runtime.CompilerServices.TaskAwaiter`1<valuetype [netstandard]System.Nullable`1<valuetype [Facepunch.Steamworks.Win64]Steamworks.Data.Lobby>> GameNetworkManager/'<StartHost>d__79'::'<>u__1'
IL_00a4: stloc.3 // V_3
IL_00a5: ldarg.0 // this
IL_00a6: ldflda valuetype [netstandard]System.Runtime.CompilerServices.TaskAwaiter`1<valuetype [netstandard]System.Nullable`1<valuetype [Facepunch.Steamworks.Win64]Steamworks.Data.Lobby>> GameNetworkManager/'<StartHost>d__79'::'<>u__1'
IL_00ab: initobj valuetype [netstandard]System.Runtime.CompilerServices.TaskAwaiter`1<valuetype [netstandard]System.Nullable`1<valuetype [Facepunch.Steamworks.Win64]Steamworks.Data.Lobby>>
IL_00b1: ldarg.0 // this
IL_00b2: ldc.i4.m1
IL_00b3: dup
IL_00b4: stloc.0 // V_0
IL_00b5: stfld int32 GameNetworkManager/'<StartHost>d__79'::'<>1__state'
IL_00ba: ldloca.s V_3
IL_00bc: call instance !0/*valuetype [netstandard]System.Nullable`1<valuetype [Facepunch.Steamworks.Win64]Steamworks.Data.Lobby>*/ valuetype [netstandard]System.Runtime.CompilerServices.TaskAwaiter`1<valuetype [netstandard]System.Nullable`1<valuetype [Facepunch.Steamworks.Win64]Steamworks.Data.Lobby>>::GetResult()
IL_00c1: stloc.2 // V_2
IL_00c2: ldarg.0 // this
IL_00c3: ldfld class GameNetworkManager GameNetworkManager/'<StartHost>d__79'::'<>7__wrap1'
IL_00c8: ldloc.2 // V_2
IL_00c9: callvirt instance void GameNetworkManager::set_currentLobby(valuetype [netstandard]System.Nullable`1<valuetype [Facepunch.Steamworks.Win64]Steamworks.Data.Lobby>)
// [669 9 - 669 55]
IL_00ce: ldarg.0 // this
IL_00cf: ldnull
IL_00d0: stfld class GameNetworkManager GameNetworkManager/'<StartHost>d__79'::'<>7__wrap1'
// [671 7 - 671 72]
IL_00d5: call !!0/*class MenuManager*/ [UnityEngine.CoreModule]UnityEngine.Object::FindObjectOfType<class MenuManager>()
IL_00da: callvirt instance void MenuManager::StartHosting()
// [672 7 - 672 44]
IL_00df: ldloc.1 // V_1
IL_00e0: call instance void GameNetworkManager::SubscribeToConnectionCallbacks()
// [673 7 - 673 32]
IL_00e5: ldloc.1 // V_1
IL_00e6: ldc.i4.1
IL_00e7: stfld bool GameNetworkManager::isHostingGame
// [674 7 - 674 32]
IL_00ec: ldloc.1 // V_1
IL_00ed: ldc.i4.1
IL_00ee: stfld int32 GameNetworkManager::connectedPlayers
IL_00f3: leave.s IL_010e
} // end of .try
catch [netstandard]System.Exception
{
IL_00f5: stloc.s V_4
IL_00f7: ldarg.0 // this
IL_00f8: ldc.i4.s -2 // 0xfe
IL_00fa: stfld int32 GameNetworkManager/'<StartHost>d__79'::'<>1__state'
IL_00ff: ldarg.0 // this
IL_0100: ldflda valuetype [netstandard]System.Runtime.CompilerServices.AsyncVoidMethodBuilder GameNetworkManager/'<StartHost>d__79'::'<>t__builder'
IL_0105: ldloc.s V_4
IL_0107: call instance void [netstandard]System.Runtime.CompilerServices.AsyncVoidMethodBuilder::SetException(class [netstandard]System.Exception)
IL_010c: leave.s IL_0121
} // end of catch
IL_010e: ldarg.0 // this
IL_010f: ldc.i4.s -2 // 0xfe
IL_0111: stfld int32 GameNetworkManager/'<StartHost>d__79'::'<>1__state'
IL_0116: ldarg.0 // this
IL_0117: ldflda valuetype [netstandard]System.Runtime.CompilerServices.AsyncVoidMethodBuilder GameNetworkManager/'<StartHost>d__79'::'<>t__builder'
IL_011c: call instance void [netstandard]System.Runtime.CompilerServices.AsyncVoidMethodBuilder::SetResult()
IL_0121: ret
} // end of method '<StartHost>d__79'::MoveNext
.method private final hidebysig virtual newslot instance void
SetStateMachine(
class [netstandard]System.Runtime.CompilerServices.IAsyncStateMachine stateMachine
) cil managed
{
.custom instance void [netstandard]System.Diagnostics.DebuggerHiddenAttribute::.ctor()
= (01 00 00 00 )
.override method instance void [netstandard]System.Runtime.CompilerServices.IAsyncStateMachine::SetStateMachine(class [netstandard]System.Runtime.CompilerServices.IAsyncStateMachine)
.maxstack 8
IL_0000: ldarg.0 // this
IL_0001: ldflda valuetype [netstandard]System.Runtime.CompilerServices.AsyncVoidMethodBuilder GameNetworkManager/'<StartHost>d__79'::'<>t__builder'
IL_0006: ldarg.1 // stateMachine
IL_0007: call instance void [netstandard]System.Runtime.CompilerServices.AsyncVoidMethodBuilder::SetStateMachine(class [netstandard]System.Runtime.CompilerServices.IAsyncStateMachine)
IL_000c: ret
} // end of method '<StartHost>d__79'::SetStateMachine
} // end of class '<StartHost>d__79'
到目前为止,我无法访问我真正想要更改的部分,即d__79中保存的整数,因为我无法使用 Harmony 访问自动生成的方法。
到目前为止,我所拥有的,修补程序可以工作并返回原始可访问但无用的方法。
当我将 MethodType.Enumerator 添加到 HarmonyPatch() 时,它使它只返回“字典中不存在给定的键”错误。我假设是因为我尝试访问 StartHost 的 GetNext 而不是 d__79。
[HarmonyTranspiler]
[HarmonyPatch(typeof(GameNetworkManager), nameof(GameNetworkManager.StartHost)]
static IEnumerable<CodeInstruction> TranspileMoveNext(IEnumerable<CodeInstruction> instr)
{
var codes = new List<CodeInstruction>(instr);
for (int i = 0; i < codes.Count; i++)
{
Plugin.mls.LogError(codes[i].ToString());
if (codes[i].opcode == OpCodes.Ldc_I4_4)
{
//Plugin.mls.LogError(codes[i+1].ToString());
if (codes[i - 1].ToString() == "call int Steamworks.Data.Lobby::get_MemberCount()")
{
codes[i].opcode = OpCodes.Ldc_I4_8;
}
}
}
return codes.AsEnumerable();
}
我在这里有什么选择还是这是一个失败的原因?
答: 暂无答案
评论