Unity BepInEx 关于自定义NetworkBehaviour RPC无法使用问题

前言

之前使用BepInEx开发游戏模组时 发现使用自定义网络物体无法使用ClientRpc和ServerRpc函数 于是在网上查了很多资料终于找到了解决方法

原因

由于Unity网络库Netcode在编译时 会自动Patch代码 将ClientRpc/ServerRpc加上网络通信代码

没修补之前

using System;
using Unity.Netcode;
using UnityEngine;

namespace Test
{
	// Token: 0x02000003 RID: 3
	public class Test : NetworkBehaviour
	{
		// Token: 0x06000002 RID: 2 RVA: 0x00002050 File Offset: 0x00000250
		[ClientRpc]
		public void ServerToClient_ClientRpc(int parameter1, int parameter2)
		{
			Debug.Log("ClientRpc");
		}

		// Token: 0x06000003 RID: 3 RVA: 0x0000205C File Offset: 0x0000025C
		[ServerRpc(RequireOwnership = false)]
		public void ClientToServer_ServerRpc(int parameter1, int parameter2)
		{
			Debug.Log("ServerRpc");
		}
	}
}

修补之后

using System;
using Unity.Netcode;
using UnityEngine;

namespace Test
{
	// Token: 0x02000003 RID: 3
	public class Test : NetworkBehaviour
	{
		// Token: 0x06000003 RID: 3 RVA: 0x0000205C File Offset: 0x0000025C
		[ClientRpc]
		public void ServerToClient_ClientRpc(int parameter1, int parameter2)
		{
			NetworkManager networkManager = base.NetworkManager;
			if (networkManager == null || !networkManager.IsListening)
			{
				return;
			}
			if (this.__rpc_exec_stage != 2 && (networkManager.IsServer || networkManager.IsHost))
			{
				ClientRpcParams clientRpcParams;
				FastBufferWriter fastBufferWriter = base.__beginSendClientRpc(961691156U, clientRpcParams, 0);
				BytePacker.WriteValueBitPacked(fastBufferWriter, parameter1);
				BytePacker.WriteValueBitPacked(fastBufferWriter, parameter2);
				base.__endSendClientRpc(ref fastBufferWriter, 961691156U, clientRpcParams, 0);
			}
			if (this.__rpc_exec_stage != 2 || (!networkManager.IsClient && !networkManager.IsHost))
			{
				return;
			}
			Debug.Log("ClientRpc");
		}

		// Token: 0x06000004 RID: 4 RVA: 0x00002148 File Offset: 0x00000348
		[ServerRpc(RequireOwnership = false)]
		public void ClientToServer_ServerRpc(int parameter1, int parameter2)
		{
			NetworkManager networkManager = base.NetworkManager;
			if (networkManager == null || !networkManager.IsListening)
			{
				return;
			}
			if (this.__rpc_exec_stage != 1 && (networkManager.IsClient || networkManager.IsHost))
			{
				ServerRpcParams serverRpcParams;
				FastBufferWriter fastBufferWriter = base.__beginSendServerRpc(1806026893U, serverRpcParams, 0);
				BytePacker.WriteValueBitPacked(fastBufferWriter, parameter1);
				BytePacker.WriteValueBitPacked(fastBufferWriter, parameter2);
				base.__endSendServerRpc(ref fastBufferWriter, 1806026893U, serverRpcParams, 0);
			}
			if (this.__rpc_exec_stage != 1 || (!networkManager.IsServer && !networkManager.IsHost))
			{
				return;
			}
			Debug.Log("ServerRpc");
		}

		// Token: 0x06000006 RID: 6 RVA: 0x0000223C File Offset: 0x0000043C
		protected override void __initializeVariables()
		{
			base.__initializeVariables();
		}

		// Token: 0x06000007 RID: 7 RVA: 0x00002252 File Offset: 0x00000452
		[RuntimeInitializeOnLoadMethod]
		internal static void InitializeRPCS_Test()
		{
			NetworkManager.__rpc_func_table.Add(961691156U, new NetworkManager.RpcReceiveHandler(Test.__rpc_handler_961691156));
			NetworkManager.__rpc_func_table.Add(1806026893U, new NetworkManager.RpcReceiveHandler(Test.__rpc_handler_1806026893));
		}

		// Token: 0x06000008 RID: 8 RVA: 0x0000228C File Offset: 0x0000048C
		private static void __rpc_handler_961691156(NetworkBehaviour target, FastBufferReader reader, __RpcParams rpcParams)
		{
			NetworkManager networkManager = target.NetworkManager;
			if (networkManager == null || !networkManager.IsListening)
			{
				return;
			}
			int parameter;
			ByteUnpacker.ReadValueBitPacked(reader, ref parameter);
			int parameter2;
			ByteUnpacker.ReadValueBitPacked(reader, ref parameter2);
			target.__rpc_exec_stage = 2;
			((Test)target).ServerToClient_ClientRpc(parameter, parameter2);
			target.__rpc_exec_stage = 0;
		}

		// Token: 0x06000009 RID: 9 RVA: 0x00002300 File Offset: 0x00000500
		private static void __rpc_handler_1806026893(NetworkBehaviour target, FastBufferReader reader, __RpcParams rpcParams)
		{
			NetworkManager networkManager = target.NetworkManager;
			if (networkManager == null || !networkManager.IsListening)
			{
				return;
			}
			int parameter;
			ByteUnpacker.ReadValueBitPacked(reader, ref parameter);
			int parameter2;
			ByteUnpacker.ReadValueBitPacked(reader, ref parameter2);
			target.__rpc_exec_stage = 1;
			((Test)target).ClientToServer_ServerRpc(parameter, parameter2);
			target.__rpc_exec_stage = 0;
		}

		// Token: 0x0600000A RID: 10 RVA: 0x00002373 File Offset: 0x00000573
		protected internal override string __getTypeName()
		{
			return "Test";
		}
	}
}

问题显而易见

解决方法

1, 使用 UnityNetcodePatcher (直接修补DLL)

使用之前需要先将调试信息改为嵌入式或可移植

 在你模组的Awake函数中添加:

 /* 用来加载NetworkBehaviour初始化函数 */

 var types = Assembly.GetExecutingAssembly().GetTypes();
 foreach (var type in types)
 {
     var methods = type.GetMethods(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
     foreach (var method in methods)
     {
         var attributes = method.GetCustomAttributes(typeof(RuntimeInitializeOnLoadMethodAttribute), false);
         if (attributes.Length > 0)
         {
             method.Invoke(null, null);
         }
     }
 }

如果你用的是 Visual studio 就打开dotnet终端输入 不是的话就去releases下载

dotnet tool install -g Evaisa.NetcodePatcher.Cli
netcode-patch [你生成的模组DLL文件位置] [依赖文件夹位置]

依赖文件夹用游戏的Managed文件夹就行了

然后没问题的话就会生成两个文件 带original结尾的就是源文件 不带original结尾的文件就是修补好的

2, 使用 RuntimeNetcodeRPCValidator (不需要修补DLL)

// Example of using NetcodeValidator
namespace SomePlugin {
    [BepInPlugin("My.Plugin.Guid", "My Plugin Name", "0.1.1")]
    [BepInDependency(RuntimeNetcodeRPCValidator.MyPluginInfo.PLUGIN_GUID, RuntimeNetcodeRPCValidator.MyPluginInfo.PLUGIN_VERSION)]
    public class MyPlugin : BaseUnityPlugin {
        private NetcodeValidator netcodeValidator;
        
        private void Awake()
        {
            netcodeValidator = new NetcodeValidator("My.Plugin.Guid");
            netcodeValidator.PatchAll();
            
            netcodeValidator.BindToPreExistingObjectByBehaviour<PluginNetworkingInstance, Terminal>();
        }
    }
}

将 PluginNetworkingInstance 替换为你自定义的NetworkBehaviour

将 Terminal 替换为游戏存在的GameObject

PS: 这个是用于Lethal Company游戏的代码我也不知道其他游戏能不能用 :P

  • 8
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值