代码改变世界

Photon自定义加载Resource之外的资源

  独孤残云  阅读(698)  评论(0编辑  收藏  举报

PhotonNetwork.cs 结尾添加如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
#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 结尾添加如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
#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 调用

1
2
3
4
//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 即可

 

编辑推荐:
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· .NET Core 托管堆内存泄露/CPU异常的常见思路
· PostgreSQL 和 SQL Server 在统计信息维护中的关键差异
· C++代码改造为UTF-8编码问题的总结
· DeepSeek 解答了困扰我五年的技术问题
阅读排行:
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 清华大学推出第四讲使用 DeepSeek + DeepResearch 让科研像聊天一样简单!
· 实操Deepseek接入个人知识库
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
点击右上角即可分享
微信分享提示