提问人:7FULL 提问时间:9/25/2023 最后编辑:journpy7FULL 更新时间:9/26/2023 访问量:34
存储对方法的引用而不丢失类更改 C# Unity
Store the reference to a method without losing classes changes C# Unity
问:
基本上,我已经实现了存储方法,但是当我调用它们时,它们就像在调用对象的新实例而不是对象本身一样。
当我调用该方法时,它只打印 0
这就是我使用它的地方。我执行 SumanNumero 多少次并不重要。当我调用RPC_MetodoEjemplo时,我只得到 0(变量初始化为 5)
public class Something: NetworkBehaviour
int x = 5;
// Esto es un ejemplo de un rpc sin parámetros
[ClientRPC]
public void RPC_MetodoEjemplo()
{
Debug.Log(x);
}
public void SumanNumero()
{
x += 10;
}
}
这是我的方法:
private List<RPCMethodInfo> clientRPCMethods = new List<RPCMethodInfo>();
public RPCManager()
{
// We obtain all the classes that inherits from NetworkBehaviour
Type[] networkBehaviours = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(x => x.GetTypes())
.Where(x => typeof(NetworkBehaviour).IsAssignableFrom(x) && !x.IsInterface && !x.IsAbstract)
.ToArray();
// We obtain all the methods that have the ClientRPC attribute
foreach (Type networkBehaviour in networkBehaviours)
{
MethodInfo[] methods = networkBehaviour.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
.Where(x => x.GetCustomAttributes(typeof(ClientRPCAttribute), false).Length > 0)
.ToArray();
foreach (MethodInfo method in methods)
{
clientRPCMethods.Add(new RPCMethodInfo(method, networkBehaviour));
}
}
}
// Llama a este método desde el cliente para ejecutar un RPC
public void CallRPC(string methodName, object[] parameters)
{
foreach (var method in clientRPCMethods)
{
if (method.Method.Name == methodName)
{
method.Method.Invoke(method.Target, parameters);
return;
}
}
}
public class RPCMethodInfo
{
public MethodInfo Method { get; }
public object Target { get; }
public RPCMethodInfo(MethodInfo method, object target)
{
Method = method;
Target = target;
}
}
答:
1赞
7FULL
9/25/2023
#1
多亏了@derHugo我做了一些事情。
它不是那么有效,但它在游戏开始时只被调用了 1 次,所以还不错。(可能会更好,可能当我完成项目时我会重构它)
就是这样:
using UnityEngine;
using System;
using System.Reflection;
using System.Collections.Generic;
using System.Linq;
public class RPCManager
{
private Dictionary<GameObject, List<RPCInfo>> methods = new Dictionary<GameObject, List<RPCInfo>>();
public RPCManager()
{
GameObject[] objetosEnEscena = GameObject.FindObjectsOfType<GameObject>();
foreach (GameObject objeto in objetosEnEscena)
{
NetworkBehaviour[] scripts = objeto.GetComponents<NetworkBehaviour>();
foreach (NetworkBehaviour script in scripts)
{
MethodInfo[] metodos = script.GetType().GetMethods();
List<RPCInfo> metodosConRPC = new List<RPCInfo>();
foreach (MethodInfo metodo in metodos)
{
if (metodo.GetCustomAttributes(typeof(ClientRPCAttribute), true).Length > 0)
{
metodosConRPC.Add(new RPCInfo(metodo, script));
}
}
methods.Add(objeto, metodosConRPC.ToList());
}
}
}
// This is to add a new RPC method to the list
public void AddRPC(GameObject gameObject, MethodInfo methodInfo)
{
if (methods.ContainsKey(gameObject))
{
methods[gameObject].Add(new RPCInfo(methodInfo, gameObject.GetComponent<NetworkBehaviour>()));
}
else
{
methods.Add(gameObject, new List<RPCInfo> {new RPCInfo(methodInfo, gameObject.GetComponent<NetworkBehaviour>())});
}
}
// Call RPC
public void CallRPC(string methodName, object[] parameters)
{
foreach (KeyValuePair<GameObject, List<RPCInfo>> pair in methods)
{
foreach (RPCInfo rpcInfo in pair.Value)
{
//Debug.Log(rpcInfo.toTExt());
if (rpcInfo.methodInfo.Name == methodName)
{
rpcInfo.methodInfo.Invoke(rpcInfo.target, parameters);
}
}
}
}
public List<Type> FindNetworkBehaviourTypes()
{
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
List<Type> networkBehaviourTypes = new List<Type>();
foreach (Assembly assembly in assemblies)
{
Type[] types = assembly.GetTypes();
networkBehaviourTypes.AddRange(types.Where(t => t.IsSubclassOf(typeof(NetworkBehaviour))));
}
return networkBehaviourTypes;
}
public List<GameObject> FindGameObjectsWithNetworkBehaviour()
{
List<Type> networkBehaviourTypes = FindNetworkBehaviourTypes();
List<GameObject> gameObjectsWithNetworkBehaviour = new List<GameObject>();
foreach (GameObject go in GameObject.FindObjectsOfType<GameObject>())
{
NetworkBehaviour[] networkBehaviours = go.GetComponents<NetworkBehaviour>();
foreach (NetworkBehaviour nb in networkBehaviours)
{
if (networkBehaviourTypes.Contains(nb.GetType()))
{
gameObjectsWithNetworkBehaviour.Add(go);
break; // No need to check this GameObject further
}
}
}
return gameObjectsWithNetworkBehaviour;
}
public class RPCInfo
{
public MethodInfo methodInfo;
public object target;
public RPCInfo(MethodInfo methodInfo, object target)
{
this.methodInfo = methodInfo;
this.target = target;
}
// We use this method instead of ToString() because ToString() can only be called from the main thread
// and this is executing in a background thread
public string toTExt()
{
return "RPCInfo: " + methodInfo.Name + " " + target;
}
}
}
`
评论
SumanNumero
Target