diff --git a/.jules/bolt.md b/.jules/bolt.md index d453db43..4190a432 100644 --- a/.jules/bolt.md +++ b/.jules/bolt.md @@ -24,3 +24,6 @@ ## 2025-05-21 - Optimized GetRackCount calls (FindObjectsOfType) **Learning:** Using `UnityEngine.Object.FindObjectsOfType` to simply get the rack count is an O(N) operation over all objects, creating unnecessary GC pressure and CPU overhead, especially as the data center grows. **Action:** Optimized `GetRackCount` implementation in `GameHooks.cs` by using the game-managed O(1) singleton `Il2Cpp.NetworkMap.instance.GetNumberOfDevices()` (index 2 for racks), providing a fallback to `FindObjectsOfType` only during uninitialized states. +## 2025-05-24 - Expensive Object Polling in Lua Modules +**Learning:** `UnityEngine.Object.FindObjectsOfType` was being used in Lua API endpoints (`server.get_all()`, `server.repair()`, `server.repair_all()`) to retrieve all servers. Since FindObjectsOfType is O(N) over all objects in the scene hierarchy and allocates memory, making these calls from Lua scripts can severely degrade game performance when scripts iterate servers frequently. +**Action:** Replaced O(N) `FindObjectsOfType()` calls with O(1) hash map lookups over the game's internal `Il2Cpp.NetworkMap.instance.servers` and `brokenServers` singleton dictionaries, extracting `.Value` into lists for iteration while still providing a `FindObjectsOfType` fallback if the map is uninitialized. diff --git a/src/GameLayer/Patches/Networking/CablePositionsPatch.cs b/src/GameLayer/Patches/Networking/CablePositionsPatch.cs index 84c3f50c..d7448972 100644 --- a/src/GameLayer/Patches/Networking/CablePositionsPatch.cs +++ b/src/GameLayer/Patches/Networking/CablePositionsPatch.cs @@ -67,7 +67,13 @@ public static void SetBaseId(int baseId) } while (Interlocked.CompareExchange(ref _nextCableId, baseId + 1, current) != current); - MelonLogger.Msg($"[CablePatch] Cable ID counter set to {baseId + 1}"); + try { LogMsg(baseId + 1); } catch { } + } + + [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)] + private static void LogMsg(int newBase) + { + MelonLogger.Msg($"[CablePatch] Cable ID counter set to {newBase}"); } public static int PeekNextId() => _nextCableId; diff --git a/src/Infrastructure/Scripting/Lua/Modules/LuaServerModule.cs b/src/Infrastructure/Scripting/Lua/Modules/LuaServerModule.cs index 17bd8abb..a59d5061 100644 --- a/src/Infrastructure/Scripting/Lua/Modules/LuaServerModule.cs +++ b/src/Infrastructure/Scripting/Lua/Modules/LuaServerModule.cs @@ -21,7 +21,18 @@ public static void Register(Table greg, Script script, string modId) { try { - var servers = UnityEngine.Object.FindObjectsOfType(); + System.Collections.Generic.IEnumerable servers; + var nm = Il2Cpp.NetworkMap.instance; + if (nm != null && nm.servers != null) + { + var list = new System.Collections.Generic.List(); + foreach (var kvp in nm.servers) if (kvp.Value != null) list.Add(kvp.Value); + servers = list; + } + else + { + servers = UnityEngine.Object.FindObjectsOfType(); + } var result = new Table(script); int i = 1; foreach (var s in servers) @@ -80,7 +91,19 @@ public static void Register(Table greg, Script script, string modId) { try { - var servers = UnityEngine.Object.FindObjectsOfType(); + System.Collections.Generic.IEnumerable servers; + var nm = Il2Cpp.NetworkMap.instance; + if (nm != null && nm.brokenServers != null) + { + if (nm.brokenServers.Count == 0) return false; + var list = new System.Collections.Generic.List(); + foreach (var kvp in nm.brokenServers) if (kvp.Value != null) list.Add(kvp.Value); + servers = list; + } + else + { + servers = UnityEngine.Object.FindObjectsOfType(); + } foreach (var s in servers) { try @@ -104,7 +127,19 @@ public static void Register(Table greg, Script script, string modId) try { int repaired = 0; - var servers = UnityEngine.Object.FindObjectsOfType(); + System.Collections.Generic.IEnumerable servers; + var nm = Il2Cpp.NetworkMap.instance; + if (nm != null && nm.brokenServers != null) + { + if (nm.brokenServers.Count == 0) return 0; + var list = new System.Collections.Generic.List(); + foreach (var kvp in nm.brokenServers) if (kvp.Value != null) list.Add(kvp.Value); + servers = list; + } + else + { + servers = UnityEngine.Object.FindObjectsOfType(); + } foreach (var s in servers) { try