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]标记
Unity - Photon PUN 本地与网络同步的逻辑分离 (二)的更多相关文章
- Unity - Photon PUN 本地与网络同步的逻辑分离 (一)
服务器大家可以使用Photon官网提供的,这样会变得很简单,直接搭建下就好.或者下载到本地开启本地端Photon服务器 (大家也可以使用和我一样方式有时间做了个winform 程序用来管理本地服务器开 ...
- 实现一个简易的Unity网络同步引擎——netgo
实现一个简易的Unity网络同步引擎Netgo 目前GOLANG有大行其道的趋势,尤其是在网络编程方面.因为和c/c++比较起来,虽然GC占用了一部分机器性能,但是出错概率小了,开发效率大大提升,而且 ...
- Unite 2017 | 从《闹闹天宫》看MOBA游戏里的网络同步技术
http://mp.weixin.qq.com/s/0v0EU79Q6rFafrh8ptlmhw 在Unite 2017 Shanghai案例分享专场,来自蓝港互动<闹闹天宫>项目组的主程 ...
- MOBA游戏的网络同步技术
转自:http://www.gameres.com/750888.html 在5月13日Unite 2017 案例分享专场上,蓝港互动<闹闹天宫>项目组的主程序陈实分享了MOBA游戏的网络 ...
- Photon PUN 一 介绍
有句话说的好 , 官网永远是最好的学习地方 . 虽然国内的资料不多 , 但是官网的资料还是很充足 , 这就带着英汉词典就着作阅读理解的劲头去官网学习吧 https://doc.photonengine ...
- 游戏中的网络同步机制——Lockstep(帧同步)
本文来自: https://bindog.github.io/blog/2015/03/10/synchronization-in-multiplayer-networked-game-lockste ...
- 手游后台PVP系统网络同步方案总结
游戏程序 平台类型: 程序设计: 编程语言: 引擎/SDK: 概述 PVP系统俨然成为现在新手游的上线标配,手游Pvp系统体验是否优秀,很大程度上决定了游戏的品质.从最近半年上线的新手 ...
- Photon PUN 三 RPCs & RaiseEvent
官方文档地址 https://doc.photonengine.com/en-us/pun/current/manuals-and-demos/rpcsandraiseevent 一, RPC P ...
- 百度云+ KeePass 网络同步你的密码
百度云+ KeePass 网络同步你的密码 百度云一个目前不限流量不限格式能直链的网盘,速度在我这里很快,难得了!KeePass(小众介绍过 KeePass.) 是一个免费开源的密码管理类软件, ...
随机推荐
- 比较C#中几种常见的复制字节数组方法的效率
在日常编程过程中,我们可能经常需要Copy各种数组,一般来说有以下几种常见的方法:Array.Copy,IList<T>.Copy,BinaryReader.ReadBytes,Buffe ...
- python目录结构
import sys,os #__file__取得当前文件名,pycharm会自动加上完整路径 #os.path.dirname取得上一级目录 #os.path.abspath取得绝对路径 BASE_ ...
- react源码第一天
1.下载源码:github 16.7版本 2.找到笔记:https://react.jokcy.me/book/api/react.html#
- python练习题_04
import os def fetch(data): # print('\033[1;43m这是查询功能\033[0m') # print('\033[1;43m用户数据是\033[0m',data) ...
- JAVA版本微信管家平台—JeeWx 捷微 4.1 微服务版本发布,微信砍价活动闪亮登场!
捷微 4.1 微服务版本发布,微信砍价活动闪亮登场 ^_^ JEEWX 从4.0版本开始,技术架构全新换代更名 “捷微H5”.这是一款开源免费的微信运营平台,是jeewx的新一代产品,平台涵盖了: ...
- 秋日上新!H5活动之家营销平台升级大盘点!
H5活动之家活动营销平台,免费定制使用抽奖.投票.砍价.红包.互动.游戏等不同类型的微信营销活动. 近期多个活动进行了升级改造,更有集福卡持续热度,微助力火热上线等亮点:同时平台也进行了提高访问速度. ...
- delphi:Exception EInvalidPointer in module Project1.exe
在用delphi XE5编程时遇到如下问题: Exception EInvalidPointer in module Project1.exe at 00007595. Invalid pointer ...
- Delphi 10.3中使用JSON
有一个对JSON处理的单元,在你需要使用JSON的单元里面引入"System.json",随后你就可以用Delphi自己的json处理类了. 注意: 1,JSON类创建后,里面 ...
- 虚拟机JVM
虚拟机组成:类加载器,运行时数据区,执行引擎 运行时数据区:堆,栈,方法区,程序计数器,本地方法栈 堆:对象实例 栈:入栈出栈,线程的执行 栈帧:一个方法一个 栈的结构:放 局部变量表,操作数栈,动态 ...
- 优化Android Studio/Gradle构建(转)
参考:http://hm.itheima.com/thread-204217-1-1.html