using FishNet.Documenting; using System.Collections.Generic; using UnityEngine; using GameKit.Dependencies.Utilities; using System.Text; #if UNITY_EDITOR using UnityEditor; #endif using FishNet.Object; namespace FishNet.Managing.Object { [APIExclude] // [CreateAssetMenu(fileName = "New DefaultPrefabObjects", menuName = "FishNet/Spawnable Prefabs/Default Prefab Objects")] public class DefaultPrefabObjects : SinglePrefabObjects { /// /// Used for version rebuilding. /// private StringBuilder _stringBuilder = new(); /// /// Sets asset path hashes for prefabs starting at index, or if missing. /// Returns true if one or more NetworkObjects were updated. internal bool SetAssetPathHashes(int index) { #if UNITY_EDITOR bool dirtied = false; int count = base.GetObjectCount(); if (count == 0) return false; if (index < 0 || index >= count) { Debug.LogError($"Index {index} is out of range when trying to set asset path hashes. Collection length is {count}. Defaulf prefabs may need to be rebuilt."); return false; } for (int i = 0; i < count; i++) { NetworkObject n = Prefabs[i]; if (i < index) continue; string pathAndName = $"{AssetDatabase.GetAssetPath(n.gameObject)}{n.gameObject.name}".Trim().ToLowerInvariant(); _stringBuilder.Clear(); foreach (char c in pathAndName) { if ((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9')) _stringBuilder.Append(c); } ulong hashcode = _stringBuilder.ToString().GetStableHashU64(); // Already set. if (n.AssetPathHash == hashcode) continue; n.SetAssetPathHash(hashcode); EditorUtility.SetDirty(n); dirtied = true; } //Check for conflicts. Dictionary hashesAndPaths = new(); for (int i = 0; i < count; i++) { NetworkObject n = Prefabs[i]; string pathAndName = $"{AssetDatabase.GetAssetPath(n.gameObject)}{n.gameObject.name}"; if (hashesAndPaths.TryGetValueIL2CPP(n.AssetPathHash, out string path)) { Debug.LogError($"Assets {pathAndName} and {path} have the same assetPath hash of {n.AssetPathHash}. Please modify the prefab name of either to resolve."); dirtied = false; } else { hashesAndPaths.Add(n.AssetPathHash, pathAndName); } } return dirtied; #else return false; #endif } /// /// Sorts prefabs by name and path hashcode. /// internal void Sort() { if (base.GetObjectCount() == 0) return; Dictionary hashcodesAndNobs = new(); List hashcodes = new(); bool error = false; foreach (NetworkObject n in Prefabs) { hashcodes.Add(n.AssetPathHash); // If hashcode is 0 something is wrong if (n.AssetPathHash == 0) { error = true; Debug.LogError($"AssetPathHash is not set for GameObject {n.name}."); } hashcodesAndNobs.Add(n.AssetPathHash, n); } // An error occured, no reason to continue. if (error) { Debug.LogError($"One or more NetworkObject prefabs did not have their AssetPathHash set. This usually occurs when a prefab cannot be saved. Check the specified prefabs for missing scripts or serialization errors and correct them, then use Fish-Networking -> Refresh Default Prefabs."); return; } // Once all hashes have been made re-add them to prefabs sorted. hashcodes.Sort(); // Build to a new list using sorted hashcodes. List sortedNobs = new(); foreach (ulong hc in hashcodes) sortedNobs.Add(hashcodesAndNobs[hc]); base.Clear(); base.AddObjects(sortedNobs, checkForDuplicates: false, initializeAdded: false); } } }