Unity - Photon PUN 本地与网络同步的逻辑分离 (二)

上篇实现了事件系统的设计,这篇就来结合发送RPC消息 并且不用标记 [PunRPC]

先来看下上编的代码 GameEnvent.cs

private static Dictionary<CommandType, Delegate> EvnDic = new Dictionary<CommandType, Delegate>(); //保存所有函数方法的字典

        public static List<CommandType> CommandTypeList = new List<CommandType>();

        //注册监听____________________________________
public static void Listen(CommandType command, CallFunction call) //通过传递参数枚举 和方法 进行绑定到EvnDic字典中
{
if (!CommandTypeList.Contains(command)) //如果不包含就添加进去
{
CommandTypeList.Add(command);
EvnDic.Add(command, call);
}
else //如果包含1.判断是否是null 2.不是null则进行绑定(+=)
{
if (EvnDic[command] == null)
{
Consoles.WriteError("Delegate对象异常为NULL Key:" + command);
return;
}
EvnDic[command] = (CallFunction)EvnDic[command] + call;
}
} public static void Listen<T>(CommandType command, CallFunction<T> call)
{
if (!CommandTypeList.Contains(command))
{
CommandTypeList.Add(command);
EvnDic.Add(command, call);
}
else
{ if (EvnDic[command] == null || EvnDic[command].GetType() != call.GetType())
{
Consoles.WriteError("Delegate对象异常为NULL Key:" + command);
return;
}
EvnDic[command] = (CallFunction<T>)EvnDic[command] + call;
}
} public static void Listen<T, U>(CommandType command, CallFunction<T, U> call)
{
if (!CommandTypeList.Contains(command))
{
CommandTypeList.Add(command);
EvnDic.Add(command, call);
}
else
{
if (EvnDic[command] == null || EvnDic[command].GetType() != call.GetType())
{
Consoles.WriteError("Delegate对象异常为NULL Key:" + command);
return;
}
EvnDic[command] = (CallFunction<T, U>)EvnDic[command] + call;
}
} public static void Listen<T, U, O>(CommandType command, CallFunction<T, U, O> call)
{
if (!CommandTypeList.Contains(command))
{
CommandTypeList.Add(command);
EvnDic.Add(command, call); }
else
{ if (EvnDic[command] == null || EvnDic[command].GetType() != call.GetType())
{
Consoles.WriteError("Delegate对象异常为NULL Key:" + command);
return;
}
EvnDic[command] = (CallFunction<T, U, O>)EvnDic[command] + call;
}
} public static void Listen<T, U, O, P>(CommandType command, CallFunction<T, U, O, P> call)
{
if (!CommandTypeList.Contains(command))
{
CommandTypeList.Add(command);
EvnDic.Add(command, call); }
else
{ if (EvnDic[command] == null || EvnDic[command].GetType() != call.GetType())
{
Consoles.WriteError("Delegate对象异常为NULL Key:" + command);
return;
}
EvnDic[command] = (CallFunction<T, U, O, P>)EvnDic[command] + call;
}
} private static void CheckCommad(CommandType command)
{
if (EvnDic[command] == null)
{
EvnDic.Remove(command);
CommandTypeList.Remove(command);
}
} //移除事件--------------------------------------------------------
public static void Remove(CommandType command, CallFunction call) //通过枚举 和 方法 从EvnDic字典中移除绑定
{ if (!CommandTypeList.Contains(command)) return; Delegate @delegate = EvnDic[command];
if (@delegate == null)
{
Consoles.WriteError("Delegate结果为NULL Key:" + command);
return;
}
else if (@delegate.GetType() != call.GetType())
{
Consoles.WriteError("Delegate对象不匹配 Key:" + command);
return;
}
EvnDic[command] = (CallFunction)EvnDic[command] - call;; CheckCommad(command);
} public static void Remove<T>(CommandType command, CallFunction<T> call)
{
if (!CommandTypeList.Contains(command)) return; Delegate @delegate = EvnDic[command];
if (@delegate == null)
{
Consoles.WriteError("Delegate结果为NULL Key:" + command);
return;
}
else if (@delegate.GetType() != call.GetType())
{
Consoles.WriteError("Delegate对象不匹配 Key:" + command);
return;
} EvnDic[command] = (CallFunction<T>)EvnDic[command] - call; CheckCommad(command);
} public static void Remove<T, U>(CommandType command, CallFunction<T, U> call)
{
if (!CommandTypeList.Contains(command)) return; Delegate @delegate = EvnDic[command];
if (@delegate == null)
{
Consoles.WriteError("Delegate结果为NULL Key:" + command);
return;
}
else if (@delegate.GetType() != call.GetType())
{
Consoles.WriteError("Delegate对象不匹配 Key:" + command);
return;
} EvnDic[command] = (CallFunction<T, U>)EvnDic[command] - call; CheckCommad(command);
} public static void Remove<T, U, O>(CommandType command, CallFunction<T, U, O> call)
{
if (!CommandTypeList.Contains(command)) return; Delegate @delegate = EvnDic[command];
if (@delegate == null)
{
Consoles.WriteError("Delegate结果为NULL Key:" + command);
return;
}
else if (@delegate.GetType() != call.GetType())
{
Consoles.WriteError("Delegate对象不匹配 Key:" + command);
return;
} EvnDic[command] = (CallFunction<T, U, O>)EvnDic[command] - call; CheckCommad(command);
} public static void Remove<T, U, O, P>(CommandType command, CallFunction<T, U, O, P> call)
{
if (!CommandTypeList.Contains(command)) return; Delegate @delegate = EvnDic[command];
if (@delegate == null)
{
Consoles.WriteError("Delegate结果为NULL Key:" + command);
return;
}
else if (@delegate.GetType() != call.GetType())
{
Consoles.WriteError("Delegate对象不匹配 Key:" + command);
return;
} EvnDic[command] = (CallFunction<T, U, O, P>)EvnDic[command] - call; CheckCommad(command);
} public static void Remove<T, U, O, P, Q>(CommandType command, CallFunction<T, U, O, P, Q> call)
{
if (!CommandTypeList.Contains(command)) return; Delegate @delegate = EvnDic[command];
if (@delegate == null)
{
Consoles.WriteError("Delegate结果为NULL Key:" + command);
return;
}
else if (@delegate.GetType() != call.GetType())
{
Consoles.WriteError("Delegate对象不匹配 Key:" + command);
return;
} EvnDic[command] = (CallFunction<T, U, O, P, Q>)EvnDic[command] - call; CheckCommad(command);
} //执行事件-------------------------------------------------------------
public static void Broadcast(CommandType command) //通过枚举 和要执行方法参数 从EvnDic中获取对象方法并调用
{
if (!CommandTypeList.Contains(command)) return;
Delegate @delegate;
if (EvnDic.TryGetValue(command, out @delegate))
{
CallFunction call = @delegate as CallFunction;
if (call != null)
call();
else
Consoles.WriteError("对应key的De'le'gate为空 Key:" + command);
}
} public static void Broadcast<T>(CommandType command, T arg1)
{
if (!CommandTypeList.Contains(command)) return;
Delegate @delegate;
if (EvnDic.TryGetValue(command, out @delegate))
{
CallFunction<T> call = @delegate as CallFunction<T>;
if (call != null)
call(arg1);
else
Consoles.WriteError("对应key的De'le'gate为空 Key:" + command);
}
} public static void Broadcast<T, U>(CommandType command, T arg1, U arg2)
{
if (!CommandTypeList.Contains(command)) return;
Delegate @delegate;
if (EvnDic.TryGetValue(command, out @delegate))
{
CallFunction<T, U> call = @delegate as CallFunction<T, U>;
if (call != null)
call(arg1, arg2);
else
Consoles.WriteError("对应key的De'le'gate为空 Key:" + command);
}
} public static void Broadcast<T, U, O>(CommandType command, T arg1, U arg2, O arg3)
{
if (!CommandTypeList.Contains(command)) return;
Delegate @delegate;
if (EvnDic.TryGetValue(command, out @delegate))
{
CallFunction<T, U, O> call = @delegate as CallFunction<T, U, O>;
if (call != null)
call(arg1, arg2, arg3);
else
Consoles.WriteError("对应key的De'le'gate为空 Key:" + command);
}
} public static void Broadcast<T, U, O, P>(CommandType command, T arg1, U arg2, O arg3, P arg4)
{
if (!CommandTypeList.Contains(command)) return;
Delegate @delegate;
if (EvnDic.TryGetValue(command, out @delegate))
{
CallFunction<T, U, O, P> call = @delegate as CallFunction<T, U, O, P>;
if (call != null)
call(arg1, arg2, arg3, arg4);
else
Consoles.WriteError("对应key的De'le'gate为空 Key:" + command);
}
} public static void Broadcast<T, U, O, P, Q>(CommandType command, T arg1, U arg2, O arg3, P arg4, Q arg5)
{
if (!CommandTypeList.Contains(command)) return;
Delegate @delegate;
if (EvnDic.TryGetValue(command, out @delegate))
{
CallFunction<T, U, O, P, Q> call = @delegate as CallFunction<T, U, O, P, Q>;
if (call != null)
call(arg1, arg2, arg3, arg4, arg5);
else
Consoles.WriteError("对应key的De'le'gate为空 Key:" + command);
}
} //清空事件--------------------------------------------------------
public static void Cleanup()
{
EvnDic.Clear();
}

其中 public static void Broadcast 方法已经具备了调用绑定事件的功能,但如果发送rpc同步消息还是需要添加 [PunRPC]标记,所以下一步我们再建立一个类 GeneralSubmit.cs ,这个类主要负责就是通过让其他地方可以跳过添加标记的繁琐。

是的其实原理很简单,我们先说下思路:

GameEnvent.cs 负责同步消息的绑定和执行

GeneralSubmit.cs 是个rpc消息的中介类

过程是 通过GameEnvent .cs 向GeneralSubmit .cs 发送一个 要调用的 delegate函数 (CallBackFunction),GeneralSubmit .cs 通过内部的一个PRC方法再来执行这个 delegate ,这样简单几步除了GeneralSubmit这个rpc消息中介类外 再也没有什么地方需要我们添加 [PunRPC]标记 就可以执行rpc消息同步了。

1.那么我们就开始写一下 GeneralSubmit.cs

using System.Reflection;
using System.Linq;
public class GeneralSubmit :MonoBehaviour
{
private PhotonView view;
public PhotonView GetView
{
set { view = value; }
get
{
if (view == null)
view = GetComponent<PhotonView>();
if (view == null)
view = gameObject.AddComponent<PhotonView>();
return view;
}
} private Type _SelfType;
public Type SelfType
{
private set
{
_SelfType = value;
}
get
{
if (_SelfType == null)
_SelfType = GetType();
return _SelfType;
}
} public static GeneralSubmit instance; private void Awake()
{
instance = this;
DontDestroyOnLoad(gameObject);
} //--------------------------------------------------------------
//简单封装了Rpc发送,发送方式是PhotonTargets.AllBuffered
public void Net(string functionName,params object[]args)
{
PhotonView view =GetComponent<PhotonView>();
if (view == null){Debug.LogError("ERROR"); return;}
view.RPC(functionName, PhotonTargets.AllBuffered, args);
} // GameMessage 方法接收枚举(因为绑定事件是由枚举作为key)和参数并以RPC的方式执行OnGameEvent函数,当然这个只是个基础的,重要的是看GameMessage 的泛型
public void GameMessage(CommandType command)
{
int commandIndex = (int)command;
Net("OnGameEvent", commandIndex);
} //接收枚举(因为绑定事件是由枚举作为key)和参数并已RPC的方式执行OnGameEvent函数
public void GameMessage<T>(CommandType command,T arg1)
{
//重要 这里将T等泛型以字符串的形式传出,接收方再将其转换成类型,这样就巧妙地实现了类型的传送 给 本类的OnGameEvent方法
Net("OnGameEvent", typeof(T).FullName, (int)command, arg1);
} public void GameMessage<T,U>(CommandType command, T arg1,U arg2)
{
//重要 这里将T,U等泛型以字符串的形式传出,接收方再将其转换成类型,这样就巧妙地实现了类型的传送 给 本类的OnGameEvent方法 ,其他的泛型也是如此
Net("OnGameEvent", typeof(T).FullName,typeof(U).FullName, (int)command, arg1,arg2);
} public void GameMessage<T, U, V>(CommandType command, T arg1, U arg2, V arg3)
{
transform.Net("OnGameEvent", typeof(T).FullName, typeof(U).FullName,typeof(V).FullName, (int)command, arg1, arg2,arg3);
} public void GameMessage<T, U, V,N>(CommandType command, T arg1, U arg2, V arg3,N arg4)
{
Net("OnGameEvent", typeof(T).FullName, typeof(U).FullName, typeof(V).FullName, typeof(N).FullName, (int)command, arg1, arg2,arg3,arg4);
} //*********
//OnGameEvent 是以RPC方式执行所以都要加上[PunRpc],声明 我们只会在OnGameEvent和他的泛型添加这个标记,完成后其他地方是全部不需要添加标记的 [PunRPC]
public void OnGameEvent(int index)
{
//TODO:将 index转换成枚举作为key
} /// <summary> Params 1 </summary>
[PunRPC]
public void OnGameEvent(string typeName, int index,object t1)
{ object o = Activator.CreateInstance(SelfType);
MethodInfo MI = SelfType.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Default).FirstOrDefault(F => F.IsGenericMethod && F.Name == "SendFunctionToServer" && F.GetParameters().Length == );
MethodInfo mi1 = MI.MakeGenericMethod(new Type[] { Type.GetType(typeName) });
mi1.Invoke(o, new object[] {index,t1 }); /* 注释: FirstOrDefault(F => F.IsGenericMethod && F.Name == "SendFunctionToServer" && F.GetParameters().Length == 2);
F.Name == "SendFunctionToServer -要调用的方法名
F.GetParameters().Length == 2 -该方法的参数有几个
当有个这两个条件,我们就可以调用我们需要的重载函数了。
其他的也是一样的方式
这样我们就把 泛型的类型 和参数 都拿到了并用反射SendFunctionToServer调用了对应的重载函数
看完 OnGameEvent的泛型后我们再去看下SendFunctionToServer 方法
*/
} public void SendFunctionToServer<T>(int command, object arg1)
{
T arg = (T)arg1;
将 参数转换成对应的类型 (因为是反射调用的所以我们不用去关心太多) //TODO: 将 command转换为枚举类型做为key
} /// <summary> Params 2 </summary>
[PunRPC]
public void OnGameEvent(string typeName,string typeNameU, int index, object t1,object t2)
{ object o = Activator.CreateInstance(SelfType);
MethodInfo MI = SelfType.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Default).FirstOrDefault(F => F.IsGenericMethod && F.Name == "SendFunctionToServer" && F.GetParameters().Length == );
MethodInfo mi1 = MI.MakeGenericMethod(new Type[] { Type.GetType(typeName) , Type.GetType(typeNameU) });
mi1.Invoke(o, new object[] { index, t1 ,t2});
} public void SendFunctionToServer<T,U>(int command, object arg1,object arg2)
{
T par1 = (T)arg1;
U par2 = (U)arg2;
} /// <summary> Params 3 </summary>
[PunRPC]
public void OnGameEvent(string typeName, string typeNameU, string typeNameV, int index, object t1, object t2,object t3)
{
// print(Type.GetType(typeName));
object o = Activator.CreateInstance(SelfType);
MethodInfo MI = SelfType.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Default).FirstOrDefault(F => F.IsGenericMethod && F.Name == "SendFunctionToServer" && F.GetParameters().Length == );
MethodInfo mi1 = MI.MakeGenericMethod(new Type[] { Type.GetType(typeName), Type.GetType(typeNameU),Type.GetType(typeNameV) });
mi1.Invoke(o, new object[] { index, t1, t2 ,t3 });
} public void SendFunctionToServer<T, U,V>(int command, object arg1, object arg2,object arg3)
{
T par1 = (T)arg1;
U par2 = (U)arg2;
V par3 = (V)arg3;
} /// <summary> Params 4 </summary>
[PunRPC]
public void OnGameEvent(string typeName, string typeNameU, string typeNameV, string typeNameN, int index, object t1, object t2, object t3,object t4)
{
// print(Type.GetType(typeName));
object o = Activator.CreateInstance(SelfType);
MethodInfo MI = SelfType.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Default).FirstOrDefault(F => F.IsGenericMethod && F.Name == "SendFunctionToServer" && F.GetParameters().Length == );
MethodInfo mi1 = MI.MakeGenericMethod(new Type[] { Type.GetType(typeName), Type.GetType(typeNameU), Type.GetType(typeNameV),Type.GetType(typeNameN) });
mi1.Invoke(o, new object[] { index, t1, t2, t3 ,t4});
} public void SendFunctionToServer<T, U, V,N>(int command, object arg1, object arg2, object arg3,object arg4)
{
T par1 = (T)arg1;
U par2 = (U)arg2;
V par3 = (V)arg3;
N par4 = (N)arg4;
}

现在已经可以使用泛型作为参数传递了,那么就差具体执行 通过传来的key做为键去调用值的这一步了

下面我们为GameEnvent.cs中添加一个泛型方法 用来专门调用 GeneralSubmit .cs的静态方法

 //同步调用
public static void Execute(CommandType command)
{
if (!CommandTypeList.Contains(command)) return;
Delegate @delegate;
if (EvnDic.TryGetValue(command, out @delegate))
{
CallFunction call = @delegate as CallFunction;
if (call != null)
{
GeneralSubmit.instance.GameMessage(command);
}
else
Consoles.WriteError("对应key的De'le'gate为空 Key:" + command);
}
} public static void Execute<T>(CommandType command,T arg1)
{
if (!CommandTypeList.Contains(command)) return;
Delegate @delegate;
if (EvnDic.TryGetValue(command, out @delegate))
{
CallFunction<T> call = @delegate as CallFunction<T>;
if (call != null)
{
GeneralSubmit.instance.GameMessage<T>(command, arg1);
}
else
Consoles.WriteError("对应key的De'le'gate为空 Key:" + command);
}
} public static void Execute<T,U>(CommandType command, T arg1,U arg2)
{
if (!CommandTypeList.Contains(command)) return;
Delegate @delegate;
if (EvnDic.TryGetValue(command, out @delegate))
{
CallFunction<T,U> call = @delegate as CallFunction<T,U>;
if (call != null)
{
GeneralSubmit.instance.GameMessage<T,U>(command, arg1,arg2);
}
else
Consoles.WriteError("对应key的De'le'gate为空 Key:" + command);
}
} public static void Execute<T,U,V>(CommandType command, T arg1,U arg2 ,V arg3)
{
if (!CommandTypeList.Contains(command)) return;
Delegate @delegate;
if (EvnDic.TryGetValue(command, out @delegate))
{
CallFunction<T,U,V> call = @delegate as CallFunction<T,U,V>;
if (call != null)
{
GeneralSubmit.instance.GameMessage<T,U,V>(command, arg1,arg2,arg3);
}
else
Consoles.WriteError("对应key的De'le'gate为空 Key:" + command);
}
} public static void Execute<T,U,V,N>(CommandType command, T arg1,U arg2, V arg3, N arg4)
{
if (!CommandTypeList.Contains(command)) return;
Delegate @delegate;
if (EvnDic.TryGetValue(command, out @delegate))
{
CallFunction<T,U,V,N> call = @delegate as CallFunction<T,U,V,N>;
if (call != null)
{
GeneralSubmit.instance.GameMessage<T,U,V,N>(command, arg1,arg2,arg3,arg4);
}
else
Consoles.WriteError("对应key的De'le'gate为空 Key:" + command);
}
}

现在梳理下 执行GameEvent.Execute方法 会到

GeneralSubmit.instance.GameMessage 这里 然后会根据传来的 枚举和参数的不同执行OnGameEvent泛型,然后会反射执行
GeneralSubmit类中的SendFunctionToServer方法。
到这里SendFunctionToServer 中可以得到 枚举和参数,那么我们只需要再通过GameEvent.Broadcast 执行下去就可以了(注意通过此方式(GameEvent.Execute)此时是以rpc同步方式调用的
GameEvent.Broadcast,这样其他客户端也同样会做相同的调用,并且其他类中不再需要添加[PunRPC]标记
GeneralSubmit完整的代码
public class GeneralSubmit :PunBehaviour
{
private PhotonView view; public PhotonView GetView
{
set { view = value; } get
{
if (view == null)
view = GetComponent<PhotonView>();
if (view == null)
view = gameObject.AddComponent<PhotonView>();
return view;
}
} private Type _SelfType;
public Type SelfType
{
private set
{
_SelfType = value;
}
get
{
if (_SelfType == null)
_SelfType = GetType();
return _SelfType;
}
} public static GeneralSubmit instance; private void Awake()
{
instance = this;
DontDestroyOnLoad(gameObject);
} public void GameMessage(CommandType command)
{
int commandIndex = (int)command;
transform.Net("OnGameEvent", commandIndex);
} public void GameMessage<T>(CommandType command,T arg1)
{
transform.Net("OnGameEvent", typeof(T).FullName, (int)command, arg1);
} public void GameMessage<T,U>(CommandType command, T arg1,U arg2)
{
transform.Net("OnGameEvent", typeof(T).FullName,typeof(U).FullName, (int)command, arg1,arg2);
} public void GameMessage<T, U, V>(CommandType command, T arg1, U arg2, V arg3)
{
transform.Net("OnGameEvent", typeof(T).FullName, typeof(U).FullName,typeof(V).FullName, (int)command, arg1, arg2,arg3);
} public void GameMessage<T, U, V,N>(CommandType command, T arg1, U arg2, V arg3,N arg4)
{
transform.Net("OnGameEvent", typeof(T).FullName, typeof(U).FullName, typeof(V).FullName, typeof(N).FullName, (int)command, arg1, arg2,arg3,arg4);
} public void GameMessage<T, U, V, N,K>(CommandType command, T arg1, U arg2, V arg3, N arg4, K arg5)
{
transform.Net("OnGameEvent", typeof(T).FullName, typeof(U).FullName, typeof(V).FullName, typeof(N).FullName,typeof(K).FullName,(int)command, arg1, arg2, arg3, arg4,arg5);
} [PunRPC]
public void OnGameEvent(int index)
{
GameEnvent.Broadcast((CommandType)index);
} /// <summary> Params 1 </summary>
[PunRPC]
public void OnGameEvent(string typeName, int index,object t1)
{
object o = Activator.CreateInstance(SelfType);
MethodInfo MI = SelfType.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Default).FirstOrDefault(F => F.IsGenericMethod && F.Name == "SendFunctionToServer" && F.GetParameters().Length == );
MethodInfo mi1 = MI.MakeGenericMethod(new Type[] { Type.GetType(typeName) });
mi1.Invoke(o, new object[] {index,t1 });
} public void SendFunctionToServer<T>(int command, object arg1)
{
T arg = (T)arg1;
GameEnvent.Broadcast<T>((CommandType)command, arg);
} /// <summary> Params 2 </summary>
[PunRPC]
public void OnGameEvent(string typeName,string typeNameU, int index, object t1,object t2)
{
object o = Activator.CreateInstance(SelfType);
MethodInfo MI = SelfType.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Default).FirstOrDefault(F => F.IsGenericMethod && F.Name == "SendFunctionToServer" && F.GetParameters().Length == );
MethodInfo mi1 = MI.MakeGenericMethod(new Type[] { Type.GetType(typeName) , Type.GetType(typeNameU) });
mi1.Invoke(o, new object[] { index, t1 ,t2});
} public void SendFunctionToServer<T,U>(int command, object arg1,object arg2)
{
T par1 = (T)arg1;
U par2 = (U)arg2;
GameEnvent.Broadcast<T,U>((CommandType)command, par1,par2);
} /// <summary> Params 3 </summary>
[PunRPC]
public void OnGameEvent(string typeName, string typeNameU, string typeNameV, int index, object t1, object t2,object t3)
{
object o = Activator.CreateInstance(SelfType);
MethodInfo MI = SelfType.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Default).FirstOrDefault(F => F.IsGenericMethod && F.Name == "SendFunctionToServer" && F.GetParameters().Length == );
MethodInfo mi1 = MI.MakeGenericMethod(new Type[] { Type.GetType(typeName), Type.GetType(typeNameU),Type.GetType(typeNameV) });
mi1.Invoke(o, new object[] { index, t1, t2 ,t3 });
} public void SendFunctionToServer<T, U,V>(int command, object arg1, object arg2,object arg3)
{
T par1 = (T)arg1;
U par2 = (U)arg2;
V par3 = (V)arg3;
GameEnvent.Broadcast<T, U, V>((CommandType)command, par1, par2,par3);
} /// <summary> Params 4 </summary>
[PunRPC]
public void OnGameEvent(string typeName, string typeNameU, string typeNameV, string typeNameN, int index, object t1, object t2, object t3,object t4)
{
object o = Activator.CreateInstance(SelfType);
MethodInfo MI = SelfType.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Default).FirstOrDefault(F => F.IsGenericMethod && F.Name == "SendFunctionToServer" && F.GetParameters().Length == );
MethodInfo mi1 = MI.MakeGenericMethod(new Type[] { Type.GetType(typeName), Type.GetType(typeNameU), Type.GetType(typeNameV),Type.GetType(typeNameN) });
mi1.Invoke(o, new object[] { index, t1, t2, t3 ,t4});
} public void SendFunctionToServer<T, U, V,N>(int command, object arg1, object arg2, object arg3,object arg4)
{
T par1 = (T)arg1;
U par2 = (U)arg2;
V par3 = (V)arg3;
N par4 = (N)arg4;
GameEnvent.Broadcast<T, U, V, N>((CommandType)command, par1, par2, par3,par4);
}


当完成了上述后我们来看下使用示例:
public class Test2 : MonoBehaviour
{
private void Start()
{
GameEnvent.Listen<string>(CommandType.Test1, Say); }
private void Say(string Name)
{
print("Hello"+Name);
}
} public class Test3 : MonoBehaviour
{
private void Update()
{
if (Input.GetKeyDown(KeyCode.T))
GameEnvent.Execute<string>(CommandType.Test1, "NAME");
//按T后调用会以rpc方式调用 Test2类中的Say方法 且这个Say方法不需要添加[PunRpc]标记,这也是我们要达到的目的。
}
}

最后大家只要记住

1.GameEnvent.Broadcast 是本地调用

2.GameEnvent.Execute 是rpc同步调用

任何以GameEnvent.Execute方式执行的都会被以rpc方式同步调用

这种方式下开发时不需要考虑这个方法是同步方法 还是本地执行的方法。 我们只是在调用时使用不同的方式 GameEnvent.Broadcast / GameEnvent.Execute  就可以使一个函数随意成为本地或网络同步的方法,这个函数用来本地调用还是网络同步调用在着之间是可以很好很容易的切换。同时我们也去除了繁琐的标记。且任何方法通过GameEnvent.Execute执行都是以rpc方式调用的,而且不需要到处添加[PunRPC]标记

上一篇:jQuery自适应倒计时插件


下一篇:File Input Features