using FishNet.Managing; using FishNet.Object; using GameKit.Dependencies.Utilities; using System.Collections.Generic; using UnityEngine; using UnityEngine.SceneManagement; namespace FishNet.Utility.Extension { public static class Scenes { /// /// Gets all NetworkObjects in a scene. /// /// Scene to get objects in. /// True to only return the first NetworkObject within an object chain. False will return nested NetworkObjects. /// public static void GetSceneNetworkObjects(Scene s, bool firstOnly, bool errorOnDuplicates, bool ignoreUnsetSceneIds, ref List result) { List nobCacheA = CollectionCaches.RetrieveList(); List nobCacheB = CollectionCaches.RetrieveList(); List gameObjectCache = CollectionCaches.RetrieveList(); Dictionary sceneIds = CollectionCaches.RetrieveDictionary(); //Iterate all root objects for the scene. s.GetRootGameObjects(gameObjectCache); foreach (GameObject go in gameObjectCache) { //Get NetworkObjects within children of each root. go.GetComponentsInChildren(true, nobCacheA); //If network objects are found. if (nobCacheA.Count > 0) { //Add only the first networkobject if (firstOnly) { /* The easiest way to see if a nob is nested is to * get nobs in parent and if the count is greater than 1, then * it is nested. The technique used here isn't exactly fast but * it will only occur during scene loads, so I'm trading off speed * for effort and readability. */ foreach (NetworkObject nob in nobCacheA) { if (ignoreUnsetSceneIds && !nob.IsSceneObject) continue; nob.GetComponentsInParent(true, nobCacheB); //No extra nobs, only this one. if (nobCacheB.Count == 1 && !TryDisplayDuplicateError(nob)) result.Add(nob); } } //Not first only, add them all. else { foreach (NetworkObject item in nobCacheA) { if (ignoreUnsetSceneIds && !item.IsSceneObject) continue; if (!TryDisplayDuplicateError(item)) result.Add(item); } } } } CollectionCaches.Store(sceneIds); bool TryDisplayDuplicateError(NetworkObject nob) { if (!errorOnDuplicates) return false; ulong id = nob.SceneId; //There is a duplicate. if (sceneIds.TryGetValue(id, out NetworkObject originalNob)) { string err = $"Object {nob.name} and {originalNob.name} in scene {nob.gameObject.scene.name} have the same sceneId of {id}. This will result in spawning errors. Exit play mode and use the Fish-Networking menu to reserialize sceneIds for scene {nob.gameObject.scene.name}."; NetworkManagerExtensions.LogError(err); return true; } else { sceneIds[id] = nob; return false; } } } } }