From 853e03cc997c6b85dab68da6927159ac27250693 Mon Sep 17 00:00:00 2001 From: xen-42 Date: Thu, 13 Feb 2025 14:54:14 -0500 Subject: [PATCH] Only unload textures once nobody is using them anymore --- .../EOTE/NHSlideCollectionContainer.cs | 36 +++++++++++++++++-- NewHorizons/Utility/Files/ImageUtilities.cs | 3 ++ 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/NewHorizons/Components/EOTE/NHSlideCollectionContainer.cs b/NewHorizons/Components/EOTE/NHSlideCollectionContainer.cs index 5ce38910..edc954ca 100644 --- a/NewHorizons/Components/EOTE/NHSlideCollectionContainer.cs +++ b/NewHorizons/Components/EOTE/NHSlideCollectionContainer.cs @@ -2,11 +2,14 @@ using HarmonyLib; using NewHorizons.Builder.Props; using NewHorizons.External.Modules.Props.EchoesOfTheEye; using NewHorizons.Utility.Files; +using NewHorizons.Utility.OWML; using OWML.Common; using System; +using System.Collections.Generic; using System.IO; using System.Linq; using UnityEngine; +using UnityEngine.SceneManagement; namespace NewHorizons.Components.EOTE; @@ -18,6 +21,12 @@ public class NHSlideCollectionContainer : SlideCollectionContainer public string[] slidePaths; public IModBehaviour mod; + public static Dictionary> _slidesRequiringPath = new(); + static NHSlideCollectionContainer() + { + SceneManager.sceneUnloaded += (_) => _slidesRequiringPath.Clear(); + } + [HarmonyPrefix] [HarmonyPatch(typeof(SlideCollectionContainer), nameof(SlideCollectionContainer.Initialize))] public static bool SlideCollectionContainer_Initialize(SlideCollectionContainer __instance) @@ -171,6 +180,22 @@ public class NHSlideCollectionContainer : SlideCollectionContainer var wrappedIndex = (index + this.slideCollection.slides.Length) % this.slideCollection.slides.Length; var path = Path.Combine(mod.ModHelper.Manifest.ModFolderPath, ProjectionBuilder.InvertedSlideReelCacheFolder, slidePaths[wrappedIndex]); + // We are the first slide collection container to try and load this image + var key = ImageUtilities.GetKey(mod, path); + if (!_slidesRequiringPath.ContainsKey(key)) + { + // Something else has loaded this image i.e., AutoProjector or Vision torch. We want to ensure we do not delete it + if (ImageUtilities.IsTextureLoaded(mod, path)) + { + _slidesRequiringPath[key] = new() { null }; + } + else + { + _slidesRequiringPath[key] = new(); + } + _slidesRequiringPath[key].Add(this); + } + var texture = ImageUtilities.GetTexture(mod, path); this.slideCollection.slides[wrappedIndex]._image = texture; return texture; @@ -194,10 +219,17 @@ public class NHSlideCollectionContainer : SlideCollectionContainer var wrappedIndex = (index + this.slideCollection.slides.Length) % this.slideCollection.slides.Length; var path = Path.Combine(mod.ModHelper.Manifest.ModFolderPath, ProjectionBuilder.InvertedSlideReelCacheFolder, slidePaths[wrappedIndex]); + // Only unload textures that we were the ones to load in if (ImageUtilities.IsTextureLoaded(mod, path)) { - ImageUtilities.DeleteTexture(mod, path, ImageUtilities.GetTexture(mod, path)); - slideCollection.slides[wrappedIndex]._image = null; + var key = ImageUtilities.GetKey(mod, path); + _slidesRequiringPath[key].Remove(this); + if (!_slidesRequiringPath[key].Any()) + { + NHLogger.LogVerbose($"Slide reel deleting {key} since nobody is using it anymore"); + ImageUtilities.DeleteTexture(mod, path, ImageUtilities.GetTexture(mod, path)); + slideCollection.slides[wrappedIndex]._image = null; + } } } } diff --git a/NewHorizons/Utility/Files/ImageUtilities.cs b/NewHorizons/Utility/Files/ImageUtilities.cs index 2e660d17..cc258967 100644 --- a/NewHorizons/Utility/Files/ImageUtilities.cs +++ b/NewHorizons/Utility/Files/ImageUtilities.cs @@ -15,6 +15,9 @@ namespace NewHorizons.Utility.Files public static bool CheckCachedTexture(string key, out Texture existingTexture) => _textureCache.TryGetValue(key, out existingTexture); public static void TrackCachedTexture(string key, Texture texture) => _textureCache.Add(key, texture); // dont reinsert cuz that causes memory leak! + public static string GetKey(IModBehaviour mod, string filename) + => GetKey(Path.Combine(mod.ModHelper.Manifest.ModFolderPath, filename)); + public static string GetKey(string path) => path.Substring(Main.Instance.ModHelper.OwmlConfig.ModsPath.Length + 1).Replace('\\', '/');