zoukankan      html  css  js  c++  java
  • photon Unity RPC 调用流程

    本文章由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 Handling
    
        public 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 warning
                    if (method.IsDefined(typeof (RPC), false))
                    {
                        countOldRpcs++;
                        isOldRpc = true;
                    }
                    #pragma warning restore 618
    
                    if (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 COUNT
                if (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 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[1] != null)
            {
                otherSidePrefix = (short)rpcData[(byte)1];
            }
    
    
            string inMethodName;
            if (rpcData[5] != null)
            {
                int rpcIndex = (byte)rpcData[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[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 name
            if (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 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;
            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 cache
                List<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+arguments
                for (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 case
                        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)
                    {
                        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执行调用过程。类型查找,函数解析,函数参数解析,函数调用等等过程。
    继续图:
    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
    在使用中摸索,在摸索中使用!
    当然若有问题,请随时联系!!!

    乌云之上有蓝天

    need a rest

  • 相关阅读:
    忘记自己的密码了!
    MySQL ('root'@'%') does not exist的问题
    用视觉的差异和统一来表现界面信息(转)
    Localhost 本地mysql启动2013错误(windows系统下)
    修改SQL Server2005 sa密码方法
    .net中禁用TextBox和Input框的粘贴功能
    使用Visual Studio的搜索功能时间简单的代码量统计
    visifire3.6.4 以上版本去水印的办法
    网页设计的配色和排版(转)
    小米科技增设电商业务线,大家注意到没
  • 原文地址:https://www.cnblogs.com/qitian1/p/6461909.html
Copyright © 2011-2022 走看看