本文章由cartzhang编写,转载请注明出处。 所有权利保留。
文章链接:http://blog.csdn.net/cartzhang/article/details/51425225
作者:cartzhang

一、Photon简介

Photon是一款非常不错的游戏服务端引擎,是一个服务器应用程序,可以在你选择的机器上运行,并且完全是自定义和权威性的控制,你可以自由的配置和部署多人应用的基础设施。
在客户端,Photon支持多样的平台,使用C,C#,Flash进行编程的方式是不同的,但是基本的工作流是相似的。在这文档中我们尝试去解释它的概念和背景,而语言的细节部分需要查阅每个语言平台的参考文档。
下载地址:https://www.photonengine.com/en/OnPremise/Download
解压后的相关文件夹说明:
deploy:主要存放photon的服务器控制程序和服务端Demo
doc:顾名思义,文档
lib:Photon类库,开发服务端需要引用的
src-server:服务端Demo源代码

在网络段,使用了Photon,所以拿来研究了下。看看代码,梳理了一下RPC流程。
记录下来,以供以后参考和使用。
官方网站:https://www.photonengine.com/en/PUN
分两个部分一个编辑器界面工作流程,一个是网络调用流程。

二、RPC编辑器调用代码

PhotonEditor.cs文件内,直接说代码

 #region RPC List Handlingpublic static void UpdateRpcList(){List<string> additionalRpcs = new List<string>();HashSet<string> currentRpcs = new HashSet<string>();var types = GetAllSubTypesInScripts(typeof(MonoBehaviour));int countOldRpcs = 0;foreach (var mono in types){MethodInfo[] methods = mono.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);foreach (MethodInfo method in methods){bool isOldRpc = false;#pragma warning disable 618// we let the Editor check for outdated RPC attributes in code. that should not cause a compile warningif (method.IsDefined(typeof (RPC), false)){countOldRpcs++;isOldRpc = true;}#pragma warning restore 618if (isOldRpc || method.IsDefined(typeof(PunRPC), false)){currentRpcs.Add(method.Name);if (!additionalRpcs.Contains(method.Name) && !PhotonNetwork.PhotonServerSettings.RpcList.Contains(method.Name)){additionalRpcs.Add(method.Name);}}}}if (additionalRpcs.Count > 0){// LIMITS RPC COUNTif (additionalRpcs.Count + PhotonNetwork.PhotonServerSettings.RpcList.Count >= byte.MaxValue){if (currentRpcs.Count <= byte.MaxValue){bool clearList = EditorUtility.DisplayDialog(CurrentLang.IncorrectRPCListTitle, CurrentLang.IncorrectRPCListLabel, CurrentLang.RemoveOutdatedRPCsLabel, CurrentLang.CancelButton);if (clearList){PhotonNetwork.PhotonServerSettings.RpcList.Clear();PhotonNetwork.PhotonServerSettings.RpcList.AddRange(currentRpcs);}else{return;}}else{EditorUtility.DisplayDialog(CurrentLang.FullRPCListTitle, CurrentLang.FullRPCListLabel, CurrentLang.SkipRPCListUpdateLabel);return;}}additionalRpcs.Sort();PhotonNetwork.PhotonServerSettings.RpcList.AddRange(additionalRpcs);EditorUtility.SetDirty(PhotonNetwork.PhotonServerSettings);}if (countOldRpcs > 0){bool convertRPCs = EditorUtility.DisplayDialog(CurrentLang.RpcFoundDialogTitle, CurrentLang.RpcFoundMessage, CurrentLang.RpcReplaceButton, CurrentLang.RpcSkipReplace);if (convertRPCs){PhotonConverter.ConvertRpcAttribute("");}}}

这是一个这个Unity编辑器上的RPC 列表更新代码。
一图胜千言!
上个图!!!

这里有新旧版本的兼容,代码里面自动把原来的属性[Rpc]替换为[PUNRpc]。
注意到这里面还有对列表长度的限制为255,即为byte字节的最大值。

三、Rpc View调用

在文件NetworkingPeer.cs中,Rpc的执行过程,代码:

/// <summary>/// Executes a received RPC event/// </summary>protected internal void ExecuteRpc(object[] rpcData, PhotonPlayer sender){if (rpcData == null){Debug.LogError("Malformed RPC; this should never occur. Content: " + LogObjectArray(rpcData));return;}// ts: updated with "flat" event dataint netViewID = (int)rpcData[(byte)0]; // LIMITS PHOTONVIEWS&PLAYERSint otherSidePrefix = 0;    // by default, the prefix is 0 (and this is not being sent)if (rpcData[1] != null){otherSidePrefix = (short)rpcData[(byte)1];}string inMethodName;if (rpcData[5] != null){int rpcIndex = (byte)rpcData[5];  // LIMITS RPC COUNTif (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[3];}object[] inMethodParameters = (object[])rpcData[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.") + " By: " + sender.ID);}else{Debug.LogWarning("Received RPC \"" + inMethodName + "\" for viewID " + netViewID + " but this PhotonView does not exist! Was remote PV." + (ownerSent ? " Owner called." : " Remote called.") + " By: " + sender.ID + " Maybe GO was destroyed but RPC not cleaned up.");}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 nameif (string.IsNullOrEmpty(inMethodName)){Debug.LogError("Malformed RPC; this should never occur. Content: " + LogObjectArray(rpcData));return;}if (PhotonNetwork.logLevel >= PhotonLogLevel.Full)Debug.Log("Received RPC: " + inMethodName);// SetReceiving filteringif (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;if (!PhotonNetwork.UseRpcMonoBehaviourCache || photonNetview.RpcMonoBehaviours == null || photonNetview.RpcMonoBehaviours.Length == 0){photonNetview.RefreshRpcMonoBehaviourCache();}for (int componentsIndex = 0; componentsIndex < photonNetview.RpcMonoBehaviours.Length; componentsIndex++){MonoBehaviour monob = photonNetview.RpcMonoBehaviours[componentsIndex];if (monob == null){Debug.LogError("ERROR You have missing MonoBehaviours on your gameobjects!");continue;}Type type = monob.GetType();// Get [PunRPC] methods from cacheList<MethodInfo> cachedRPCMethods = null;bool methodsOfTypeInCache = this.monoRPCMethodsCache.TryGetValue(type, out cachedRPCMethods);if (!methodsOfTypeInCache){List<MethodInfo> entries = SupportClass.GetMethods(type, typeof(PunRPC));this.monoRPCMethodsCache[type] = entries;cachedRPCMethods = entries;}if (cachedRPCMethods == null){continue;}// Check cache for valid methodname+argumentsfor (int index = 0; index < cachedRPCMethods.Count; index++){MethodInfo mInfo = cachedRPCMethods[index];if (mInfo.Name.Equals(inMethodName)){foundMethods++;ParameterInfo[] pArray = mInfo.GetParameters(); // TODO: this should be cached, too, in best caseif (pArray.Length == argTypes.Length){// Normal, PhotonNetworkMessage left outif (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 lastif (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 handlingif (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){Debug.LogError("PhotonView with ID " + netViewID + " has no method \"" + inMethodName + "\" marked with the [PunRPC](C#) or @PunRPC(JS) property! Args: " + argsString);}else{Debug.LogError("PhotonView with ID " + netViewID + " has no method \"" + inMethodName + "\" that takes " + argTypes.Length + " argument(s): " + argsString);}}else{Debug.LogError("PhotonView with ID " + netViewID + " has " + receivers + " methods \"" + inMethodName + "\" that takes " + argTypes.Length + " argument(s): " + argsString + ". Should be just one?");}}}

这个冗长的代码就是RPC执行调用过程。类型查找,函数解析,函数参数解析,函数调用等等过程。
继续图:

相关参考

https://www.photonengine.com/en/PUN
https://www.photonengine.com/en/OnPremise/Download
http://www.cnblogs.com/liusuqi/archive/2013/05/15/3079686.html
http://www.digiart.com.tw/files/photon/PhotonCloud01.pdf
在使用中摸索,在摸索中使用!
当然若有问题,请随时联系!!!

乌云之上有蓝天

photon Unity RPC 调用流程相关推荐

  1. Java基础之《netty(30)—RPC调用流程分析》

    一.RPC基本介绍 1.RPC(Remote Procedure Call)-远程过程调用,是一个计算机通信协议.该协议允许运行于一台计算机的程序调用另一台计算机的子程序,而程序无需额外的为这个交互作 ...

  2. Dubbo的RPC调用流程

    首先在客户端启动时会从注册中心拉去和订阅对应的服务列表,Cluster会把拉取到的服务列表聚合成一个cluster,每次RPC调用前会通过Directory#list获取providers地址(已经生 ...

  3. RPC 笔记(01)— RPC概念、调用流程、RPC 与 Restful API 区别

    1. 基本概念 PRC 远程过程调用 Remote Procedure Call,其就是一个节点请求另外一个节点提供的服务.当两个物理分离的子系统需要建立逻辑上的关联时,RPC 是牵线搭桥的常见技术手 ...

  4. RPC 框架梳理——RPC使用方的调用流程梳理

    背景 myrpc是基于protobuf开发的远程调用框架,对于rpc服务,在proto文件中的定义如下:    经过protoc编译后,会生成两个类:UserServiceRpc 和 UserServ ...

  5. 【Unity3D插件】Photon Unity Networking(PUN)插件分享《多人联机服务器》

    推荐阅读 CSDN主页 GitHub开源地址 Unity3D插件分享 简书地址 我的个人博客 QQ群:1040082875 一.前言 Photon Unity Networking (PUN)是一种用 ...

  6. 深入剖析通信层和RPC调用的异步化(上)

    <Netty 进阶之路>.<分布式服务框架原理与实践>作者李林锋深入剖析通信层和 RPC 调用的异步化.李林锋此后还将在 InfoQ 上开设 Netty 专题持续出稿,感兴趣的 ...

  7. unity集成openinstall流程

    目的 1.Unity集成openinstall sdk? 最近在使用一个叫openinstall的SDK,通过它实现免填邀请码的功能,集成到unity游戏开发中.对App安装流程的优化,尤其是免填写邀 ...

  8. 开发中的坑:MQ 也能做 RPC 调用?

    hi, 大家好,我是 haohongfan. 最近浏览 帖子[1] 的时候看到一个有意思的吐槽. 大概意思是架构师没有选用 RPC 框架来做服务间调用,而选择用 MQ 来代替.是不是很意外? 当然不出 ...

  9. 怎么看调用的接口_Hadoop RPC调用实例分析

    以ClientProtocol接口中的rename RPC调用进行一次实例分析. rename方法在ClientProtocol接口中定义,它的两个参数是String类型的,不能直接通过网络传输. 我 ...

最新文章

  1. 替换k个字符后最长重复子串
  2. mysql-5.7.20实用下载、安装和配置方法,以及简单操作
  3. 刚登录,有点感觉就想写下来
  4. php csrf攻击 xss区别,XSS与CSRF攻击及防御方法
  5. i12蓝牙耳机使用说明书图片_飞利浦SHB4385 BASS+无线蓝牙耳机晒单 使用体验
  6. 素材路上|专注平面设计素材模板,可能会让你抛弃花瓣!
  7. xampp里mysql的环境变量配置_XAMPP集成环境中MySQL数据库的使用
  8. “云安全+云保护” 谜团技术解析
  9. word排版技巧:论文图表目录制作步骤。
  10. 抖音短视频买的粉丝是真的吗?多少人懂这点
  11. windows10家庭版打开组策略
  12. 移动硬盘如何分区?分区软件推荐:
  13. Python logging log日志写入文件
  14. 怎么能看出来一个人善不善良?
  15. python中的多任务-多线程和多进程
  16. python笔记(tornado初识)
  17. Outlook如何修复.pst数据文件?
  18. JAVA学生信息管理系统——增删查改
  19. 智慧酒店下单管理系统
  20. 超简单、超容易理解的随机数字 + 随机字母生成器,传入要生成的随机数的位数即可(大小写字母 + 数字混合)

热门文章

  1. 数据库系统概论第五版知识大纲
  2. Android 虚拟机进化史
  3. Javaweb的AJAX及Axios框架使用(封装AJAX)
  4. 使用新浪微博-微博API的方法
  5. 童诗白模电--功率放大电路
  6. 利用face-landmark估计pitch, yaw, roll
  7. 打开ms office相关软件如Visio, 发生闪退 ,打不开,无反应问题
  8. 铆接废品产生的原因和防止方法有哪些
  9. java 面试题2 (包括答案)
  10. 2023最新SSM计算机毕业设计选题大全(附源码+LW)之java一起学习吧s77u8