Last active
December 29, 2015 01:39
-
-
Save cnsoft/7594445 to your computer and use it in GitHub Desktop.
Pun是如何处理 RPC的 通过 RaiseEvent 消息. 筛选接收者.(按id group ) NetworkPeer.onSerializedRead() > // Use incoming data according to observed type if (view.observed is MonoBehaviour) { object[] contents = data[(byte)1] as object[]; PhotonStream pStream = new PhotonStream(false, contents); PhotonMessageInfo info = new PhotonMessageInfo(sender, networkTime, view…
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
case PunEvent.RPC: | |
//ts: each event now contains a single RPC. execute this | |
this.ExecuteRPC(photonEvent[ParameterCode.Data] as Hashtable, originatingPlayer); | |
break; | |
case PunEvent.SendSerialize: | |
case PunEvent.SendSerializeReliable: | |
Hashtable serializeData = (Hashtable)photonEvent[ParameterCode.Data]; | |
//Debug.Log(serializeData.ToStringFull()); | |
int remoteUpdateServerTimestamp = (int)serializeData[(byte)0]; | |
short remoteLevelPrefix = -1; | |
short initialDataIndex = 1; | |
if (serializeData.ContainsKey((byte)1)) | |
{ | |
remoteLevelPrefix = (short)serializeData[(byte)1]; | |
initialDataIndex = 2; | |
} | |
for (short s = initialDataIndex; s < serializeData.Count; s++) | |
{ | |
this.OnSerializeRead(serializeData[s] as Hashtable, originatingPlayer, remoteUpdateServerTimestamp, remoteLevelPrefix); | |
} | |
break; | |
case PunEvent.Instantiation: | |
this.DoInstantiate((Hashtable)photonEvent[ParameterCode.Data], originatingPlayer, null); | |
break; | |
// | |
// PHOTONVIEW/RPC related | |
// 接收到RPC请求后 呼叫本地. PhotonView | |
/// <summary> | |
/// Executes a received RPC event | |
/// </summary> | |
public void ExecuteRPC(Hashtable rpcData, PhotonPlayer sender) | |
{ | |
if (rpcData == null || !rpcData.ContainsKey((byte)0)) | |
{ | |
this.DebugReturn(DebugLevel.ERROR, "Malformed RPC; this should never occur."); | |
return; | |
} | |
// ts: updated with "flat" event data | |
int netViewID = (int)rpcData[(byte)0]; // LIMITS PHOTONVIEWS&PLAYERS | |
int otherSidePrefix = 0; // by default, the prefix is 0 (and this is not being sent) | |
if (rpcData.ContainsKey((byte)1)) | |
{ | |
otherSidePrefix = (short)rpcData[(byte)1]; | |
} | |
string inMethodName; | |
if (rpcData.ContainsKey((byte)5)) | |
{ | |
int rpcIndex = (byte)rpcData[(byte)5]; // LIMITS RPC COUNT | |
if (rpcIndex > PhotonNetwork.PhotonServerSettings.RpcList.Count - 1) | |
{ | |
Debug.LogError("Could not find RPC with index: " + rpcIndex + ". Going to ignore! Check PhotonServerSettings.RpcList"); | |
return; | |
} | |
else | |
{ | |
inMethodName = PhotonNetwork.PhotonServerSettings.RpcList[rpcIndex]; | |
} | |
} | |
else | |
{ | |
inMethodName = (string)rpcData[(byte)3]; | |
} | |
object[] inMethodParameters = null; | |
if (rpcData.ContainsKey((byte)4)) | |
{ | |
inMethodParameters = (object[])rpcData[(byte)4]; | |
} | |
if (inMethodParameters == null) | |
{ | |
inMethodParameters = new object[0]; | |
} | |
PhotonView photonNetview = this.GetPhotonView(netViewID); | |
if (photonNetview == null) | |
{ | |
int viewOwnerId = netViewID/PhotonNetwork.MAX_VIEW_IDS; | |
bool owningPv = (viewOwnerId == this.mLocalActor.ID); | |
bool ownerSent = (viewOwnerId == sender.ID); | |
if (owningPv) | |
{ | |
Debug.LogWarning("Received RPC \"" + inMethodName + "\" for viewID " + netViewID + " but this PhotonView does not exist! View was/is ours." + (ownerSent ? " Owner called." : " Remote called.")); | |
} | |
else | |
{ | |
Debug.LogError("Received RPC \"" + inMethodName + "\" for viewID " + netViewID + " but this PhotonView does not exist! Was remote PV." + (ownerSent ? " Owner called." : " Remote called.")); | |
} | |
return; | |
} | |
if (photonNetview.prefix != otherSidePrefix) | |
{ | |
Debug.LogError( | |
"Received RPC \"" + inMethodName + "\" on viewID " + netViewID + " with a prefix of " + otherSidePrefix | |
+ ", our prefix is " + photonNetview.prefix + ". The RPC has been ignored."); | |
return; | |
} | |
// Get method name | |
if (inMethodName == string.Empty) | |
{ | |
this.DebugReturn(DebugLevel.ERROR, "Malformed RPC; this should never occur."); | |
return; | |
} | |
if (this.DebugOut >= DebugLevel.ALL) | |
{ | |
this.DebugReturn(DebugLevel.ALL, "Received RPC; " + inMethodName); | |
} | |
// SetReceiving filtering | |
if (photonNetview.group != 0 && !allowedReceivingGroups.Contains(photonNetview.group)) | |
{ | |
return; // Ignore group | |
} | |
Type[] argTypes = new Type[0]; | |
if (inMethodParameters.Length > 0) | |
{ | |
argTypes = new Type[inMethodParameters.Length]; | |
int i = 0; | |
for (int index = 0; index < inMethodParameters.Length; index++) | |
{ | |
object objX = inMethodParameters[index]; | |
if (objX == null) | |
{ | |
argTypes[i] = null; | |
} | |
else | |
{ | |
argTypes[i] = objX.GetType(); | |
} | |
i++; | |
} | |
} | |
int receivers = 0; | |
int foundMethods = 0; | |
MonoBehaviour[] mbComponents = photonNetview.GetComponents<MonoBehaviour>(); // NOTE: we could possibly also cache MonoBehaviours per view?! | |
for (int componentsIndex = 0; componentsIndex < mbComponents.Length; componentsIndex++) | |
{ | |
MonoBehaviour monob = mbComponents[componentsIndex]; | |
if (monob == null) | |
{ | |
Debug.LogError("ERROR You have missing MonoBehaviours on your gameobjects!"); | |
continue; | |
} | |
Type type = monob.GetType(); | |
// Get [RPC] methods from cache | |
List<MethodInfo> cachedRPCMethods = null; | |
if (this.monoRPCMethodsCache.ContainsKey(type)) | |
{ | |
cachedRPCMethods = this.monoRPCMethodsCache[type]; | |
} | |
if (cachedRPCMethods == null) | |
{ | |
List<MethodInfo> entries = SupportClass.GetMethods(type, typeof(UnityEngine.RPC)); | |
this.monoRPCMethodsCache[type] = entries; | |
cachedRPCMethods = entries; | |
} | |
if (cachedRPCMethods == null) | |
{ | |
continue; | |
} | |
// Check cache for valid methodname+arguments | |
for (int index = 0; index < cachedRPCMethods.Count; index++) | |
{ | |
MethodInfo mInfo = cachedRPCMethods[index]; | |
if (mInfo.Name == inMethodName) | |
{ | |
foundMethods++; | |
ParameterInfo[] pArray = mInfo.GetParameters(); | |
if (pArray.Length == argTypes.Length) | |
{ | |
// Normal, PhotonNetworkMessage left out | |
if (this.CheckTypeMatch(pArray, argTypes)) | |
{ | |
receivers++; | |
object result = mInfo.Invoke((object)monob, inMethodParameters); | |
if (mInfo.ReturnType == typeof(IEnumerator)) | |
{ | |
monob.StartCoroutine((IEnumerator)result); | |
} | |
} | |
} | |
else if ((pArray.Length - 1) == argTypes.Length) | |
{ | |
// Check for PhotonNetworkMessage being the last | |
if (this.CheckTypeMatch(pArray, argTypes)) | |
{ | |
if (pArray[pArray.Length - 1].ParameterType == typeof(PhotonMessageInfo)) | |
{ | |
receivers++; | |
int sendTime = (int)rpcData[(byte)2]; | |
object[] deParamsWithInfo = new object[inMethodParameters.Length + 1]; | |
inMethodParameters.CopyTo(deParamsWithInfo, 0); | |
deParamsWithInfo[deParamsWithInfo.Length - 1] = new PhotonMessageInfo(sender, sendTime, photonNetview); | |
object result = mInfo.Invoke((object)monob, deParamsWithInfo); | |
if (mInfo.ReturnType == typeof(IEnumerator)) | |
{ | |
monob.StartCoroutine((IEnumerator)result); | |
} | |
} | |
} | |
} | |
else if (pArray.Length == 1 && pArray[0].ParameterType.IsArray) | |
{ | |
receivers++; | |
object result = mInfo.Invoke((object)monob, new object[] { inMethodParameters }); | |
if (mInfo.ReturnType == typeof(IEnumerator)) | |
{ | |
monob.StartCoroutine((IEnumerator)result); | |
} | |
} | |
} | |
} | |
} | |
// Error handling | |
if (receivers != 1) | |
{ | |
string argsString = string.Empty; | |
for (int index = 0; index < argTypes.Length; index++) | |
{ | |
Type ty = argTypes[index]; | |
if (argsString != string.Empty) | |
{ | |
argsString += ", "; | |
} | |
if (ty == null) | |
{ | |
argsString += "null"; | |
} | |
else | |
{ | |
argsString += ty.Name; | |
} | |
} | |
if (receivers == 0) | |
{ | |
if (foundMethods == 0) | |
{ | |
this.DebugReturn( | |
DebugLevel.ERROR, | |
"PhotonView with ID " + netViewID + " has no method \"" + inMethodName | |
+ "\" marked with the [RPC](C#) or @RPC(JS) property! Args: " + argsString); | |
} | |
else | |
{ | |
this.DebugReturn( | |
DebugLevel.ERROR, | |
"PhotonView with ID " + netViewID + " has no method \"" + inMethodName + "\" that takes " | |
+ argTypes.Length + " argument(s): " + argsString); | |
} | |
} | |
else | |
{ | |
this.DebugReturn( | |
DebugLevel.ERROR, | |
"PhotonView with ID " + netViewID + " has " + receivers + " methods \"" + inMethodName | |
+ "\" that takes " + argTypes.Length + " argument(s): " + argsString + ". Should be just one?"); | |
} | |
} | |
} | |
// | |
//PhotonSteam PhotonMessageInfo Define | |
/// <summary> | |
/// Container class for info about a particular message, RPC or update. | |
/// </summary> | |
/// \ingroup publicApi | |
public class PhotonMessageInfo | |
{ | |
private int timeInt; | |
public PhotonPlayer sender; | |
public PhotonView photonView; | |
/// <summary> | |
/// Initializes a new instance of the <see cref="PhotonMessageInfo"/> class. | |
/// To create an empty messageinfo only! | |
/// </summary> | |
public PhotonMessageInfo() | |
{ | |
this.sender = PhotonNetwork.player; | |
this.timeInt = (int)(PhotonNetwork.time * 1000); | |
this.photonView = null; | |
} | |
public PhotonMessageInfo(PhotonPlayer player, int timestamp, PhotonView view) | |
{ | |
this.sender = player; | |
this.timeInt = timestamp; | |
this.photonView = view; | |
} | |
public double timestamp | |
{ | |
get { return ((double)(uint)this.timeInt) / 1000.0f; } | |
} | |
public override string ToString() | |
{ | |
return string.Format("[PhotonMessageInfo: player='{1}' timestamp={0}]", this.timestamp, this.sender); | |
} | |
} | |
public class PBitStream | |
{ | |
List<byte> streamBytes; | |
private int currentByte; | |
private int totalBits = 0; | |
public int ByteCount | |
{ | |
get { return BytesForBits(this.totalBits); } | |
} | |
public int BitCount | |
{ | |
get { return this.totalBits; } | |
private set { this.totalBits = value; } | |
} | |
public PBitStream() | |
{ | |
this.streamBytes = new List<byte>(1); | |
} | |
public PBitStream(int bitCount) | |
{ | |
this.streamBytes = new List<byte>(BytesForBits(bitCount)); | |
} | |
public PBitStream(IEnumerable<byte> bytes, int bitCount) | |
{ | |
this.streamBytes = new List<byte>(bytes); | |
this.BitCount = bitCount; | |
} | |
public static int BytesForBits(int bitCount) | |
{ | |
if (bitCount <= 0) | |
{ | |
return 0; | |
} | |
return ((bitCount - 1) / 8) + 1; | |
} | |
public void Add(bool val) | |
{ | |
int bytePos = this.totalBits / 8; | |
if (bytePos > this.streamBytes.Count-1 || totalBits == 0) | |
{ | |
this.streamBytes.Add(0); | |
} | |
if (val) | |
{ | |
int currentByteBit = 7 - (this.totalBits % 8); | |
this.streamBytes[bytePos] |= (byte)(1 << currentByteBit); | |
} | |
this.totalBits++; | |
} | |
public byte[] ToBytes() | |
{ | |
return streamBytes.ToArray(); | |
} | |
public int Position { get; set; } | |
public bool GetNext() | |
{ | |
if (this.Position > this.totalBits) | |
{ | |
throw new Exception("End of PBitStream reached. Can't read more."); | |
} | |
return Get(this.Position++); | |
} | |
public bool Get(int bitIndex) | |
{ | |
int byteIndex = bitIndex / 8; | |
int bitInByIndex = 7 - (bitIndex % 8); | |
return ((streamBytes[byteIndex] & (byte)(1 << bitInByIndex)) > 0); | |
} | |
public void Set(int bitIndex, bool value) | |
{ | |
int byteIndex = bitIndex / 8; | |
int bitInByIndex = 7 - (bitIndex % 8); | |
this.streamBytes[byteIndex] |= (byte)(1 << bitInByIndex); | |
} | |
} | |
/// <summary> | |
/// This "container" class is used to carry your data as written by OnPhotonSerializeView. | |
/// </summary> | |
/// <seealso cref="PhotonNetworkingMessage"/> | |
/// \ingroup publicApi | |
public class PhotonStream | |
{ | |
bool write = false; | |
internal List<object> data; | |
byte currentItem = 0; //Used to track the next item to receive. | |
public PhotonStream(bool write, object[] incomingData) | |
{ | |
this.write = write; | |
if (incomingData == null) | |
{ | |
this.data = new List<object>(); | |
} | |
else | |
{ | |
this.data = new List<object>(incomingData); | |
} | |
} | |
public bool isWriting | |
{ | |
get { return this.write; } | |
} | |
public bool isReading | |
{ | |
get { return !this.write; } | |
} | |
public int Count | |
{ | |
get | |
{ | |
return data.Count; | |
} | |
} | |
public object ReceiveNext() | |
{ | |
if (this.write) | |
{ | |
Debug.LogError("Error: you cannot read this stream that you are writing!"); | |
return null; | |
} | |
object obj = this.data[this.currentItem]; | |
this.currentItem++; | |
return obj; | |
} | |
public void SendNext(object obj) | |
{ | |
if (!this.write) | |
{ | |
Debug.LogError("Error: you cannot write/send to this stream that you are reading!"); | |
return; | |
} | |
this.data.Add(obj); | |
} | |
public object[] ToArray() | |
{ | |
return this.data.ToArray(); | |
} | |
public void Serialize(ref bool myBool) | |
{ | |
if (this.write) | |
{ | |
this.data.Add(myBool); | |
} | |
else | |
{ | |
if (this.data.Count > currentItem) | |
{ | |
myBool = (bool)data[currentItem]; | |
this.currentItem++; | |
} | |
} | |
} | |
public void Serialize(ref int myInt) | |
{ | |
if (write) | |
{ | |
this.data.Add(myInt); | |
} | |
else | |
{ | |
if (this.data.Count > currentItem) | |
{ | |
myInt = (int)data[currentItem]; | |
currentItem++; | |
} | |
} | |
} | |
public void Serialize(ref string value) | |
{ | |
if (write) | |
{ | |
this.data.Add(value); | |
} | |
else | |
{ | |
if (this.data.Count > currentItem) | |
{ | |
value = (string)data[currentItem]; | |
currentItem++; | |
} | |
} | |
} | |
public void Serialize(ref char value) | |
{ | |
if (write) | |
{ | |
this.data.Add(value); | |
} | |
else | |
{ | |
if (this.data.Count > currentItem) | |
{ | |
value = (char)data[currentItem]; | |
currentItem++; | |
} | |
} | |
} | |
public void Serialize(ref short value) | |
{ | |
if (write) | |
{ | |
this.data.Add(value); | |
} | |
else | |
{ | |
if (this.data.Count > currentItem) | |
{ | |
value = (short)data[currentItem]; | |
currentItem++; | |
} | |
} | |
} | |
public void Serialize(ref float obj) | |
{ | |
if (write) | |
{ | |
this.data.Add(obj); | |
} | |
else | |
{ | |
if (this.data.Count > currentItem) | |
{ | |
obj = (float)data[currentItem]; | |
currentItem++; | |
} | |
} | |
} | |
public void Serialize(ref PhotonPlayer obj) | |
{ | |
if (write) | |
{ | |
this.data.Add(obj); | |
} | |
else | |
{ | |
if (this.data.Count > currentItem) | |
{ | |
obj = (PhotonPlayer)data[currentItem]; | |
currentItem++; | |
} | |
} | |
} | |
public void Serialize(ref Vector3 obj) | |
{ | |
if (write) | |
{ | |
this.data.Add(obj); | |
} | |
else | |
{ | |
if (this.data.Count > currentItem) | |
{ | |
obj = (Vector3)data[currentItem]; | |
currentItem++; | |
} | |
} | |
} | |
public void Serialize(ref Vector2 obj) | |
{ | |
if (write) | |
{ | |
this.data.Add(obj); | |
} | |
else | |
{ | |
if (this.data.Count > currentItem) | |
{ | |
obj = (Vector2)data[currentItem]; | |
currentItem++; | |
} | |
} | |
} | |
public void Serialize(ref Quaternion obj) | |
{ | |
if (write) | |
{ | |
this.data.Add(obj); | |
} | |
else | |
{ | |
if (this.data.Count > currentItem) | |
{ | |
obj = (Quaternion)data[currentItem]; | |
currentItem++; | |
} | |
} | |
} | |
// |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
// 把标记成RPC类型的函数都存起来.然后发送索引.互相调用.
// 有可能破坏不同版本client间的通讯. 索引不同就有问题.
public static void UpdateRpcList()
{
HashSet additionalRpcs = new HashSet();
HashSet currentRpcs = new HashSet();
//
public static System.Type[] GetAllSubTypesInScripts(System.Type aBaseClass)
{
var result = new System.Collections.Generic.List<System.Type>();
System.Reflection.Assembly[] AS = System.AppDomain.CurrentDomain.GetAssemblies();
foreach (var A in AS)
{
// this skips all but the Unity-scripted assemblies for RPC-list creation. You could remove this to search all assemblies in project
if (!A.FullName.StartsWith("Assembly-"))
{
// Debug.Log("Skipping Assembly: " + A);
continue;
}
//