diff --git a/NewHorizons/Builder/Props/ProjectionBuilder.cs b/NewHorizons/Builder/Props/ProjectionBuilder.cs index a8e42c0f..2d25948d 100644 --- a/NewHorizons/Builder/Props/ProjectionBuilder.cs +++ b/NewHorizons/Builder/Props/ProjectionBuilder.cs @@ -513,7 +513,7 @@ namespace NewHorizons.Builder.Props { NHLogger.LogVerbose($"The atlas cache for slide reel containing [{slides.FirstOrDefault(x => !string.IsNullOrEmpty(x.imagePath))?.imagePath}] is {atlasKey}"); // Load the atlas texture used to draw onto the physical slide reel object - atlasImageLoader.PathsToLoad.Add((0, Path.Combine(mod.ModHelper.Manifest.ModFolderPath, ATLAS_SLIDE_CACHE_FOLDER, $"{atlasKey}.png"))); + atlasImageLoader.PathsToLoad.Add((0, Path.Combine(mod.ModHelper.Manifest.ModFolderPath, ATLAS_SLIDE_CACHE_FOLDER, $"{atlasKey}.png"), false)); } for (int i = 0; i < slides.Length; i++) @@ -527,11 +527,12 @@ namespace NewHorizons.Builder.Props if (useInvertedCache && cacheExists) { // Load the inverted images used when displaying slide reels to a screen - invertedImageLoader.PathsToLoad.Add((i, Path.Combine(Instance.ModHelper.Manifest.ModFolderPath, "Assets/textures/inverted_blank_slide_reel.png"))); + invertedImageLoader.PathsToLoad.Add((i, Path.Combine(Instance.ModHelper.Manifest.ModFolderPath, "Assets/textures/inverted_blank_slide_reel.png"), false)); } else { - imageLoader.PathsToLoad.Add((i, Path.Combine(Instance.ModHelper.Manifest.ModFolderPath, "Assets/textures/blank_slide_reel.png"))); + // Used to then make cached stuff + imageLoader.PathsToLoad.Add((i, Path.Combine(Instance.ModHelper.Manifest.ModFolderPath, "Assets/textures/blank_slide_reel.png"), useInvertedCache)); } } else @@ -539,11 +540,11 @@ namespace NewHorizons.Builder.Props if (useInvertedCache && cacheExists) { // Load the inverted images used when displaying slide reels to a screen - invertedImageLoader.PathsToLoad.Add((i, Path.Combine(mod.ModHelper.Manifest.ModFolderPath, INVERTED_SLIDE_CACHE_FOLDER, slideInfo.imagePath))); + invertedImageLoader.PathsToLoad.Add((i, Path.Combine(mod.ModHelper.Manifest.ModFolderPath, INVERTED_SLIDE_CACHE_FOLDER, slideInfo.imagePath), false)); } else { - imageLoader.PathsToLoad.Add((i, Path.Combine(mod.ModHelper.Manifest.ModFolderPath, slideInfo.imagePath))); + imageLoader.PathsToLoad.Add((i, Path.Combine(mod.ModHelper.Manifest.ModFolderPath, slideInfo.imagePath), useInvertedCache)); } } @@ -556,16 +557,16 @@ namespace NewHorizons.Builder.Props { if (useAtlasCache) { - atlasImageLoader.Start(false); + atlasImageLoader.Start(false, false); } // When using the inverted cache we never need the regular images if (useInvertedCache) { - invertedImageLoader.Start(true); + invertedImageLoader.Start(true, false); } else { - imageLoader.Start(true); + imageLoader.Start(true, false); } return (invertedImageLoader, atlasImageLoader, imageLoader); @@ -573,7 +574,8 @@ namespace NewHorizons.Builder.Props else { // Will be slow and create the cache if needed - imageLoader.Start(true); + // Will run sequentially to ensure we don't run out of memory + imageLoader.Start(true, true); return (null, null, imageLoader); } diff --git a/NewHorizons/Utility/Files/ImageUtilities.cs b/NewHorizons/Utility/Files/ImageUtilities.cs index c6ef49da..5d0c4d2f 100644 --- a/NewHorizons/Utility/Files/ImageUtilities.cs +++ b/NewHorizons/Utility/Files/ImageUtilities.cs @@ -72,6 +72,11 @@ namespace NewHorizons.Utility.Files { var path = Path.Combine(mod.ModHelper.Manifest.ModFolderPath, filename); var key = GetKey(path); + DeleteTexture(key, texture); + } + + public static void DeleteTexture(string key, Texture2D texture) + { if (_textureCache.ContainsKey(key)) { if (_textureCache[key] == texture) diff --git a/NewHorizons/Utility/Files/SlideReelAsyncImageLoader.cs b/NewHorizons/Utility/Files/SlideReelAsyncImageLoader.cs index 58b9db92..8897c927 100644 --- a/NewHorizons/Utility/Files/SlideReelAsyncImageLoader.cs +++ b/NewHorizons/Utility/Files/SlideReelAsyncImageLoader.cs @@ -15,7 +15,7 @@ namespace NewHorizons.Utility.Files; /// public class SlideReelAsyncImageLoader { - public List<(int index, string path)> PathsToLoad { get; private set; } = new(); + public List<(int index, string path, bool deleteImmediately)> PathsToLoad { get; private set; } = new(); public class ImageLoadedEvent : UnityEvent { } public ImageLoadedEvent imageLoadedEvent = new(); @@ -31,7 +31,7 @@ public class SlideReelAsyncImageLoader private bool _started; private bool _clamp; - public void Start(bool clamp) + public void Start(bool clamp, bool sequential) { if (_started) return; @@ -46,7 +46,7 @@ public class SlideReelAsyncImageLoader NHLogger.LogVerbose("Loading new slide reel"); imageLoadedEvent.AddListener(OnImageLoaded); - SingletonSlideReelAsyncImageLoader.Instance.Load(this); + SingletonSlideReelAsyncImageLoader.Instance.Load(this, sequential); } private void OnImageLoaded(Texture texture, int index, string originalPath) @@ -60,7 +60,17 @@ public class SlideReelAsyncImageLoader } } - private IEnumerator DownloadTexture(string url, int index) + private IEnumerator DownloadTextures() + { + foreach (var (index, path, deleteImmediately) in PathsToLoad) + { + NHLogger.LogVerbose($"Loaded slide reel {index} of {PathsToLoad.Count}"); + + yield return DownloadTexture(path, index, deleteImmediately); + } + } + + private IEnumerator DownloadTexture(string url, int index, bool deleteImmediately) { var key = ImageUtilities.GetKey(url); if (ImageUtilities.CheckCachedTexture(key, out var existingTexture)) @@ -107,6 +117,12 @@ public class SlideReelAsyncImageLoader var time = DateTime.Now; imageLoadedEvent?.Invoke(texture, index, url); + + // For when its an image loaded only to create a new cacheable image + if (deleteImmediately) + { + ImageUtilities.DeleteTexture(key, texture); + } NHLogger.LogVerbose($"Slide reel event took: {(DateTime.Now - time).TotalMilliseconds}ms"); } } @@ -115,6 +131,10 @@ public class SlideReelAsyncImageLoader { public static SingletonSlideReelAsyncImageLoader Instance { get; private set; } + private Queue _loaders = new(); + + private bool _isLoading; + public void Awake() { Instance = this; @@ -124,20 +144,48 @@ public class SlideReelAsyncImageLoader private void OnSceneUnloaded(Scene _) { StopAllCoroutines(); + _loaders.Clear(); + _isLoading = false; } - public void Load(SlideReelAsyncImageLoader loader) + public void Load(SlideReelAsyncImageLoader loader, bool sequential) { // Delay at least one frame to let things subscribe to the event before it fires Delay.FireOnNextUpdate(() => { - foreach (var (index, path) in loader.PathsToLoad) + if (sequential) { - NHLogger.LogVerbose($"Loaded slide reel {index} of {loader.PathsToLoad.Count}"); + // Sequential + _loaders.Enqueue(loader); + if (!_isLoading) + { + StartCoroutine(LoadAllSequential()); + } + } + else + { + foreach (var (index, path, deleteImmediately) in loader.PathsToLoad) + { + NHLogger.LogVerbose($"Loaded slide reel {index} of {loader.PathsToLoad.Count}"); - StartCoroutine(loader.DownloadTexture(path, index)); + StartCoroutine(loader.DownloadTexture(path, index, deleteImmediately)); + } } }); } + + private IEnumerator LoadAllSequential() + { + NHLogger.Log("Loading slide reels"); + _isLoading = true; + while (_loaders.Count > 0) + { + var loader = _loaders.Dequeue(); + yield return loader.DownloadTextures(); + NHLogger.Log($"Finished a slide reel, {_loaders.Count} left"); + } + _isLoading = false; + NHLogger.Log("Done loading slide reels"); + } } } \ No newline at end of file