Photon自定义加载Resource之外的资源
2019-01-16 13:39 独孤残云 阅读(696) 评论(0) 编辑 收藏 举报PhotonNetwork.cs 结尾添加如下代码:
#region >>> Photon自定义异步加载GameObject public delegate void CustomLoader(string prefabName, Action<UnityEngine.Object> ac); public static CustomLoader _loader; public static void RegisterCustomLoaderToPhoton(CustomLoader loader) { _loader = loader; } public static bool InstantiateCustom(string prefabName, Vector3 position, Quaternion rotation, byte group, object[] data, Action<GameObject> callback) { if (!connected || (InstantiateInRoomOnly && !inRoom)) { Debug.LogError("Failed to Instantiate prefab: " + prefabName + ". Client should be in a room. Current connectionStateDetailed: " + PhotonNetwork.connectionStateDetailed); return false; } GameObject prefabGo; if (!UsePrefabCache || !PrefabCache.TryGetValue(prefabName, out prefabGo)) { _loader(prefabName, (ab) => { prefabGo = (GameObject)(ab); if (UsePrefabCache) { PrefabCache.Add(prefabName, prefabGo); } if (prefabGo == null) { Debug.LogError("Failed to Instantiate prefab: " + prefabName + ". Verify the Prefab is in a Resources folder (and not in a subfolder)"); callback.Invoke(null); } // a scene object instantiated with network visibility has to contain a PhotonView if (prefabGo.GetComponent<PhotonView>() == null) { Debug.LogError("Failed to Instantiate prefab:" + prefabName + ". Prefab must have a PhotonView component."); callback.Invoke(null); } Component[] views = (Component[])prefabGo.GetPhotonViewsInChildren(); int[] viewIDs = new int[views.Length]; for (int i = 0; i < viewIDs.Length; i++) { //Debug.Log("Instantiate prefabName: " + prefabName + " player.ID: " + player.ID); viewIDs[i] = AllocateViewID(player.ID); } // Send to others, create info Hashtable instantiateEvent = networkingPeer.SendInstantiate(prefabName, position, rotation, group, viewIDs, data, false); // Instantiate the GO locally (but the same way as if it was done via event). This will also cache the instantiationId callback.Invoke(networkingPeer.DoInstantiate(instantiateEvent, networkingPeer.LocalPlayer, prefabGo)); }); return true; } if (prefabGo != null) { // a scene object instantiated with network visibility has to contain a PhotonView if (prefabGo.GetComponent<PhotonView>() == null) { Debug.LogError("Failed to Instantiate prefab:" + prefabName + ". Prefab must have a PhotonView component."); callback.Invoke(null); } Component[] views = (Component[])prefabGo.GetPhotonViewsInChildren(); int[] viewIDs = new int[views.Length]; for (int i = 0; i < viewIDs.Length; i++) { //Debug.Log("Instantiate prefabName: " + prefabName + " player.ID: " + player.ID); viewIDs[i] = AllocateViewID(player.ID); } // Send to others, create info Hashtable instantiateEvent = networkingPeer.SendInstantiate(prefabName, position, rotation, group, viewIDs, data, false); callback.Invoke(networkingPeer.DoInstantiate(instantiateEvent, networkingPeer.LocalPlayer, prefabGo)); return true; } return false; } #endregion
NetworkingPeer.cs 结尾添加如下代码:
#region >>> Photon自定义异步加载GameObject public delegate void CustomInstantiatedHandler(PhotonPlayer photonPlayer, GameObject go); public static event CustomInstantiatedHandler OnCustomInstantiated; internal void DoInstantiateCustom(Hashtable evData, PhotonPlayer photonPlayer, GameObject resourceGameObject, Action<GameObject> callback) { // some values always present: string prefabName = (string)evData[(byte)0]; int serverTime = (int)evData[(byte)6]; int instantiationId = (int)evData[(byte)7]; Vector3 position; if (evData.ContainsKey((byte)1)) { position = (Vector3)evData[(byte)1]; } else { position = Vector3.zero; } Quaternion rotation = Quaternion.identity; if (evData.ContainsKey((byte)2)) { rotation = (Quaternion)evData[(byte)2]; } byte group = 0; if (evData.ContainsKey((byte)3)) { group = (byte)evData[(byte)3]; } short objLevelPrefix = 0; if (evData.ContainsKey((byte)8)) { objLevelPrefix = (short)evData[(byte)8]; } int[] viewsIDs; if (evData.ContainsKey((byte)4)) { viewsIDs = (int[])evData[(byte)4]; } else { viewsIDs = new int[1] { instantiationId }; } object[] incomingInstantiationData; if (evData.ContainsKey((byte)5)) { incomingInstantiationData = (object[])evData[(byte)5]; } else { incomingInstantiationData = null; } // SetReceiving filtering if (group != 0 && !this.allowedReceivingGroups.Contains(group)) { if (callback != null) { callback.Invoke(null); } return; // Ignore group } if (ObjectPool != null) // 使用对象池的情况 { GameObject go = ObjectPool.Instantiate(prefabName, position, rotation); PhotonView[] photonViews = go.GetPhotonViewsInChildren(); if (photonViews.Length != viewsIDs.Length) { throw new Exception("Error in Instantiation! The resource's PhotonView count is not the same as in incoming data."); } for (int i = 0; i < photonViews.Length; i++) { photonViews[i].didAwake = false; photonViews[i].viewID = 0; photonViews[i].prefix = objLevelPrefix; photonViews[i].instantiationId = instantiationId; photonViews[i].isRuntimeInstantiated = true; photonViews[i].instantiationDataField = incomingInstantiationData; photonViews[i].didAwake = true; photonViews[i].viewID = viewsIDs[i]; // with didAwake true and viewID == 0, this will also register the view } // Send OnPhotonInstantiate callback to newly created GO. // GO will be enabled when instantiated from Prefab and it does not matter if the script is enabled or disabled. go.SendMessage(OnPhotonInstantiateString, new PhotonMessageInfo(photonPlayer, serverTime, null), SendMessageOptions.DontRequireReceiver); if (callback != null) { callback.Invoke(go); if (OnCustomInstantiated != null) { OnCustomInstantiated.Invoke(photonPlayer, go); } } return; } else { // load prefab, if it wasn't loaded before (calling methods might do this) if (resourceGameObject == null) { if (!NetworkingPeer.UsePrefabCache || !NetworkingPeer.PrefabCache.TryGetValue(prefabName, out resourceGameObject)) { //resourceGameObject = (GameObject)Resources.Load(prefabName, typeof(GameObject)); PhotonNetwork._loader(prefabName, (ab) => { resourceGameObject = (GameObject)ab; if (NetworkingPeer.UsePrefabCache) { NetworkingPeer.PrefabCache.Add(prefabName, resourceGameObject); } if (resourceGameObject == null) { Debug.LogError("PhotonNetwork error: Could not find the bundle [" + prefabName + "]. Please verify you have this gameobject in a StreamingAssets/Res folder."); if (callback != null) { callback.Invoke(null); } return; } // now modify the loaded "blueprint" object before it becomes a part of the scene (by instantiating it) PhotonView[] resourcePVs = resourceGameObject.GetPhotonViewsInChildren(); if (resourcePVs.Length != viewsIDs.Length) { throw new Exception("Error in Instantiation! The resource's PhotonView count is not the same as in incoming data."); } for (int i = 0; i < viewsIDs.Length; i++) { // NOTE instantiating the loaded resource will keep the viewID but would not copy instantiation data, so it's set below // so we only set the viewID and instantiationId now. the instantiationData can be fetched resourcePVs[i].viewID = viewsIDs[i]; resourcePVs[i].prefix = objLevelPrefix; resourcePVs[i].instantiationId = instantiationId; resourcePVs[i].isRuntimeInstantiated = true; } this.StoreInstantiationData(instantiationId, incomingInstantiationData); // load the resource and set it's values before instantiating it: GameObject go = (GameObject)GameObject.Instantiate(resourceGameObject, position, rotation); for (int i = 0; i < viewsIDs.Length; i++) { // NOTE instantiating the loaded resource will keep the viewID but would not copy instantiation data, so it's set below // so we only set the viewID and instantiationId now. the instantiationData can be fetched resourcePVs[i].viewID = 0; resourcePVs[i].prefix = -1; resourcePVs[i].prefixBackup = -1; resourcePVs[i].instantiationId = -1; resourcePVs[i].isRuntimeInstantiated = false; } this.RemoveInstantiationData(instantiationId); // Send OnPhotonInstantiate callback to newly created GO. // GO will be enabled when instantiated from Prefab and it does not matter if the script is enabled or disabled. go.SendMessage(OnPhotonInstantiateString, new PhotonMessageInfo(photonPlayer, serverTime, null), SendMessageOptions.DontRequireReceiver); if (callback != null) { callback.Invoke(go); if (OnCustomInstantiated != null) { OnCustomInstantiated.Invoke(photonPlayer, go); } } return; }); } else { // now modify the loaded "blueprint" object before it becomes a part of the scene (by instantiating it) PhotonView[] resourcePVs = resourceGameObject.GetPhotonViewsInChildren(); if (resourcePVs.Length != viewsIDs.Length) { throw new Exception("Error in Instantiation! The resource's PhotonView count is not the same as in incoming data."); } for (int i = 0; i < viewsIDs.Length; i++) { // NOTE instantiating the loaded resource will keep the viewID but would not copy instantiation data, so it's set below // so we only set the viewID and instantiationId now. the instantiationData can be fetched resourcePVs[i].viewID = viewsIDs[i]; resourcePVs[i].prefix = objLevelPrefix; resourcePVs[i].instantiationId = instantiationId; resourcePVs[i].isRuntimeInstantiated = true; } this.StoreInstantiationData(instantiationId, incomingInstantiationData); // load the resource and set it's values before instantiating it: GameObject go = (GameObject)GameObject.Instantiate(resourceGameObject, position, rotation); for (int i = 0; i < viewsIDs.Length; i++) { // NOTE instantiating the loaded resource will keep the viewID but would not copy instantiation data, so it's set below // so we only set the viewID and instantiationId now. the instantiationData can be fetched resourcePVs[i].viewID = 0; resourcePVs[i].prefix = -1; resourcePVs[i].prefixBackup = -1; resourcePVs[i].instantiationId = -1; resourcePVs[i].isRuntimeInstantiated = false; } this.RemoveInstantiationData(instantiationId); // Send OnPhotonInstantiate callback to newly created GO. // GO will be enabled when instantiated from Prefab and it does not matter if the script is enabled or disabled. go.SendMessage(OnPhotonInstantiateString, new PhotonMessageInfo(photonPlayer, serverTime, null), SendMessageOptions.DontRequireReceiver); if (callback != null) { callback.Invoke(go); if (OnCustomInstantiated != null) { OnCustomInstantiated.Invoke(photonPlayer, go); } } return; } } } } #endregion
NetworkingPeer.cs 第2598行:
屏蔽掉原有的 DoInstantiate 调用,改为 DoInstantiateCustom 调用
//this.DoInstantiate((Hashtable)photonEvent[ParameterCode.Data], originatingPlayer, null); this.DoInstantiateCustom((Hashtable)photonEvent[ParameterCode.Data], originatingPlayer, null, (go) => { SendMonoMessage(PhotonNetworkingMessage.OnPhotonInstantiate, new PhotonMessageInfo(originatingPlayer, 0, go.GetComponent<PhotonView>())); });
回调的意义在于你可以在初始Photon.MonoBehaviour中捕获全局的OnPhotonInstantiate网络物体初始回调,同样的你也可以通过OnCustomInstantiated事件来自定义回调事件行为
之后记得调用 PhotonNetwork.RegisterCustomLoaderToPhoton 注册一个自定义的默认异步资源加载方法给 Photon 即可