使用 Harmony 修补 Unity 游戏异步方法的真实内容

问题描述 投票:0回答:1

使用 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();
}

我这里有什么选择吗?还是这是一个失败的原因?

c# unity-game-engine cil harmony
1个回答
0
投票

您使用 dotPeek 来检查和修改 Unity 游戏中的异步方法真是太棒了!像这样修改代码对于自定义和修复问题非常有用。修补异步方法的内容时,保持和谐并确保更改不会导致意外后果或错误至关重要。

确保彻底理解该方法的工作原理并广泛测试您的更改,以确保它们不会破坏游戏的其他部分。另外,请考虑记录您的更改,以供将来参考以及与您的团队协作。在改变游戏逻辑时,制定清晰的计划并关注性能影响始终是一个很好的做法。

现在,关于“Gacha Nox”,这似乎是一个有趣的话题,但我不确定您在寻找什么具体信息。 Gacha Nox 可能与扭蛋游戏或软件有关,但我需要更多背景信息来提供相关信息或建议。请随时提供更多详细信息,我很乐意提供帮助!

© www.soinside.com 2019 - 2024. All rights reserved.