From 70c04adfe5db537a3a0f47cc40a382899b632107 Mon Sep 17 00:00:00 2001
From: Lee23 <31892011+LeeTwentyThree@users.noreply.github.com>
Date: Tue, 2 Jan 2024 14:49:36 -0500
Subject: [PATCH] fix: FINALLY fix prefab request & caching issues (#525)

* Remove requests array and lock cache dictionary

Freddy 5 bear or or or or or

* Change duplicate cache entries log level to debug

* Removed unnecessary lock statement

The game is single threaded, so the lock does nothing.

* Attempt to make Nautilus construct prefabs once

* Make sure to clear the running prefabs on quit

* Add back warning log

---------

Co-authored-by: Metious <71298690+Metious@users.noreply.github.com>
---
 Nautilus/Assets/ModPrefabCache.cs          | 34 +++++++++++-----------
 Nautilus/Assets/ModPrefabRequest.cs        |  1 -
 Nautilus/Handlers/PrefabHandler.cs         | 16 ++++++++++
 Nautilus/Patchers/PrefabDatabasePatcher.cs |  5 ----
 4 files changed, 33 insertions(+), 23 deletions(-)

diff --git a/Nautilus/Assets/ModPrefabCache.cs b/Nautilus/Assets/ModPrefabCache.cs
index 78412c3b7..73b52670a 100644
--- a/Nautilus/Assets/ModPrefabCache.cs
+++ b/Nautilus/Assets/ModPrefabCache.cs
@@ -11,8 +11,9 @@ namespace Nautilus.Assets;
 /// </summary>
 public static class ModPrefabCache
 {
+    internal static HashSet<string> RunningPrefabs = new();
+    
     private static ModPrefabCacheInstance _cacheInstance;
-    internal static Dictionary<string, ModPrefabRequest> Requests { get; } = new Dictionary<string, ModPrefabRequest>();
 
     /// <summary> Adds the given prefab to the cache. </summary>
     /// <param name="prefab"> The prefab object that is disabled and cached. </param>
@@ -84,39 +85,38 @@ private void Awake()
 
         gameObject.AddComponent<SceneCleanerPreserve>();
         DontDestroyOnLoad(gameObject);
+        SaveUtils.RegisterOnQuitEvent(ModPrefabCache.RunningPrefabs.Clear);
     }
 
     public void EnterPrefabIntoCache(GameObject prefab)
     {
-        // Proper prefabs can never exist in the scene, so parenting them is dangerous and pointless. 
-        if(prefab.IsPrefab())
-        {
-            InternalLogger.Debug($"Game Object: {prefab} is a proper prefab. Skipping parenting for cache.");
-        }
-        else
-        {
-            prefab.transform.parent = _prefabRoot;
-            prefab.SetActive(true);
-        }
-
         var prefabIdentifier = prefab.GetComponent<PrefabIdentifier>();
 
-        if(prefabIdentifier == null)
+        if (prefabIdentifier == null)
         {
             InternalLogger.Warn($"ModPrefabCache: prefab {prefab.name} is missing a PrefabIdentifier component! Unable to add to cache.");
             return;
         }
 
-        // Proper prefabs can never exist in the scene, so parenting them is dangerous and pointless. 
-        if(!Entries.ContainsKey(prefabIdentifier.classId))
+        if (!Entries.ContainsKey(prefabIdentifier.classId))
         {
             Entries.Add(prefabIdentifier.classId, prefab);
             InternalLogger.Debug($"ModPrefabCache: added prefab {prefab}");
+            // Proper prefabs can never exist in the scene, so parenting them is dangerous and pointless. 
+            if (prefab.IsPrefab())
+            {
+                InternalLogger.Debug($"Game Object: {prefab} is a proper prefab. Skipping parenting for cache.");
+            }
+            else
+            {
+                prefab.transform.parent = _prefabRoot;
+                prefab.SetActive(true);
+            }
         }
-        else // this should never happen
+        else // This should never happen
         {
             InternalLogger.Warn($"ModPrefabCache: prefab {prefabIdentifier.classId} already existed in cache!");
-        }
+        }   
     }
 
     public void RemoveCachedPrefab(string classId)
diff --git a/Nautilus/Assets/ModPrefabRequest.cs b/Nautilus/Assets/ModPrefabRequest.cs
index 564950311..35e7d3083 100644
--- a/Nautilus/Assets/ModPrefabRequest.cs
+++ b/Nautilus/Assets/ModPrefabRequest.cs
@@ -20,7 +20,6 @@ internal class ModPrefabRequest: IPrefabRequest
     public ModPrefabRequest(PrefabInfo prefabInfo)
     {
         this.prefabInfo = prefabInfo;
-        ModPrefabCache.Requests[prefabInfo.ClassID] = this;
     }
 
     private void Init()
diff --git a/Nautilus/Handlers/PrefabHandler.cs b/Nautilus/Handlers/PrefabHandler.cs
index 3cda6a834..95708b8ae 100644
--- a/Nautilus/Handlers/PrefabHandler.cs
+++ b/Nautilus/Handlers/PrefabHandler.cs
@@ -20,6 +20,11 @@ public static class PrefabHandler
 
     internal static IEnumerator GetPrefabAsync(TaskResult<GameObject> gameObject, PrefabInfo info, PrefabFactoryAsync prefabFactory)
     {
+        if (ModPrefabCache.RunningPrefabs.Contains(info.ClassID))
+        {
+            yield return new WaitUntil(() => ModPrefabCache.RunningPrefabs.Contains(info.ClassID) is false);
+        }
+        
         if (ModPrefabCache.TryGetPrefabFromCache(info.ClassID, out var prefabInCache))
         {
             gameObject.Set(prefabInCache);
@@ -31,6 +36,16 @@ internal static IEnumerator GetPrefabAsync(TaskResult<GameObject> gameObject, Pr
 
     private static IEnumerator InitPrefabAsync(TaskResult<GameObject> gameObject, PrefabInfo info, PrefabFactoryAsync prefabFactory)
     {
+        if (!ModPrefabCache.RunningPrefabs.Add(info.ClassID))
+        {
+            yield return new WaitUntil(() => ModPrefabCache.RunningPrefabs.Contains(info.ClassID) is false);
+            if (ModPrefabCache.TryGetPrefabFromCache(info.ClassID, out var prefabInCache))
+            {
+                gameObject.Set(prefabInCache);
+                yield break;
+            }
+        }
+        
         if (prefabFactory == null)
         {
             InternalLogger.Error($"PrefabHandler: Prefab Factory for {info.ClassID} is null!");
@@ -85,6 +100,7 @@ private static IEnumerator InitPrefabAsync(TaskResult<GameObject> gameObject, Pr
 
         gameObject.Set(obj);
         ModPrefabCache.AddPrefab(obj);
+        ModPrefabCache.RunningPrefabs.Remove(info.ClassID);
     }
 }
 
diff --git a/Nautilus/Patchers/PrefabDatabasePatcher.cs b/Nautilus/Patchers/PrefabDatabasePatcher.cs
index 93e05e59c..925cd3d4e 100644
--- a/Nautilus/Patchers/PrefabDatabasePatcher.cs
+++ b/Nautilus/Patchers/PrefabDatabasePatcher.cs
@@ -79,11 +79,6 @@ private static IPrefabRequest GetModPrefabAsync(string classId)
             return null;
         }
 
-        if(ModPrefabCache.Requests.TryGetValue(prefabInfo.ClassID, out var request))
-        {            
-            return request;
-        }
-
         return new ModPrefabRequest(prefabInfo);
     }