From daef166a399e932d768fb16a68fa94d83d604ab5 Mon Sep 17 00:00:00 2001 From: xen-42 Date: Thu, 13 Feb 2025 15:48:28 -0500 Subject: [PATCH] Make slide reels work on ship log projector --- .../Builder/Props/ProjectionBuilder.cs | 4 +- .../Components/EOTE/NHSlideCollection.cs | 136 +++++++++++++++++- .../EOTE/NHSlideCollectionContainer.cs | 113 +-------------- .../ShipLogPatches/ShipLogSlideReelPatches.cs | 21 +++ 4 files changed, 159 insertions(+), 115 deletions(-) create mode 100644 NewHorizons/Patches/ShipLogPatches/ShipLogSlideReelPatches.cs diff --git a/NewHorizons/Builder/Props/ProjectionBuilder.cs b/NewHorizons/Builder/Props/ProjectionBuilder.cs index ab146dda..ad43a058 100644 --- a/NewHorizons/Builder/Props/ProjectionBuilder.cs +++ b/NewHorizons/Builder/Props/ProjectionBuilder.cs @@ -140,8 +140,6 @@ namespace NewHorizons.Builder.Props var toDestroy = slideReelObj.GetComponent(); var slideCollectionContainer = slideReelObj.AddComponent(); - slideCollectionContainer.slidePaths = info.slides.Select(x => x.imagePath).ToArray(); - slideCollectionContainer.mod = mod; slideReel._slideCollectionContainer = slideCollectionContainer; Component.DestroyImmediate(toDestroy); @@ -152,7 +150,7 @@ namespace NewHorizons.Builder.Props // Now we replace the slides int slidesCount = info.slides.Length; - var slideCollection = new SlideCollection(slidesCount); + SlideCollection slideCollection = new NHSlideCollection(slidesCount, mod, info.slides.Select(x => x.imagePath).ToArray()); slideCollection.streamingAssetIdentifier = string.Empty; // NREs if null // We can fit 16 slides max into an atlas diff --git a/NewHorizons/Components/EOTE/NHSlideCollection.cs b/NewHorizons/Components/EOTE/NHSlideCollection.cs index a5e357af..0eed0393 100644 --- a/NewHorizons/Components/EOTE/NHSlideCollection.cs +++ b/NewHorizons/Components/EOTE/NHSlideCollection.cs @@ -1,16 +1,31 @@ using HarmonyLib; +using NewHorizons.Builder.Props; +using NewHorizons.Utility; using NewHorizons.Utility.Files; +using NewHorizons.Utility.OWML; using OWML.Common; +using System.Collections.Generic; +using System.IO; +using System.Linq; using UnityEngine; +using UnityEngine.SceneManagement; namespace NewHorizons.Components.EOTE; [HarmonyPatch] public class NHSlideCollection : SlideCollection { - public string[] slidePaths; public IModBehaviour mod; + private HashSet _pathsBeingLoaded = new(); + public static Dictionary> _slidesRequiringPath = new(); + + private ShipLogSlideProjector _shipLogSlideProjector; + + static NHSlideCollection() + { + SceneManager.sceneUnloaded += (_) => _slidesRequiringPath.Clear(); + } public NHSlideCollection(int startArrSize, IModBehaviour mod, string[] slidePaths) : base(startArrSize) { @@ -18,7 +33,6 @@ public class NHSlideCollection : SlideCollection this.slidePaths = slidePaths; } - /* [HarmonyPrefix] [HarmonyPatch(typeof(SlideCollection), nameof(SlideCollection.RequestStreamSlides))] public static bool SlideCollection_RequestStreamSlides(SlideCollection __instance, int[] slideIndices) @@ -27,7 +41,25 @@ public class NHSlideCollection : SlideCollection { foreach (var id in slideIndices) { - collection.slides[id]._image = ImageUtilities.GetTexture(collection.mod, collection.slidePaths[id]); + collection.LoadSlide(id); + } + return false; + } + else + { + return true; + } + } + + [HarmonyPrefix] + [HarmonyPatch(typeof(SlideCollection), nameof(SlideCollection.RequestRelease))] + public static bool SlideCollection_RequestRelease(SlideCollection __instance, int[] slideIndices) + { + if (__instance is NHSlideCollection collection) + { + foreach (var id in slideIndices) + { + collection.UnloadSlide(id); } return false; } @@ -43,7 +75,7 @@ public class NHSlideCollection : SlideCollection { if (__instance is NHSlideCollection collection) { - __result = ImageUtilities.IsTextureLoaded(collection.mod, collection.slidePaths[streamIdx]); + __result = collection.IsSlideLoaded(streamIdx); return false; } else @@ -58,7 +90,7 @@ public class NHSlideCollection : SlideCollection { if (__instance is NHSlideCollection collection) { - __result = ImageUtilities.GetTexture(collection.mod, collection.slidePaths[id]); + __result = collection.LoadSlide(id); return false; } else @@ -66,5 +98,97 @@ public class NHSlideCollection : SlideCollection return true; } } - */ + + public Texture LoadSlide(int index) + { + Texture LoadSlideInt(int index) + { + var wrappedIndex = (index + slides.Length) % 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); + } + + if (ImageUtilities.IsTextureLoaded(mod, path)) + { + var texture = ImageUtilities.GetTexture(mod, path); + slides[wrappedIndex]._image = texture; + return texture; + } + else if (!_pathsBeingLoaded.Contains(path)) + { + var loader = new SlideReelAsyncImageLoader(); + loader.PathsToLoad.Add((wrappedIndex, path)); + loader.Start(true, false); + loader.imageLoadedEvent.AddListener((Texture2D tex, int index, string originalPath) => + { + slides[wrappedIndex]._image = tex; + _pathsBeingLoaded.Remove(path); + if (_shipLogSlideProjector == null) + { + _shipLogSlideProjector = GameObject.FindObjectOfType(); + } + if (_shipLogSlideProjector != null) + { + _shipLogSlideProjector._slideDirty = true; + } + else + { + NHLogger.LogVerbose("No ship log slide reel projector exists"); + } + }); + _pathsBeingLoaded.Add(path); + return null; + } + else + { + // It is being loaded so we just wait + return null; + } + } + var texture = LoadSlideInt(index); + LoadSlideInt(index - 1); + LoadSlideInt(index + 1); + + return texture; + } + + public bool IsSlideLoaded(int index) + { + var wrappedIndex = (index + slides.Length) % slides.Length; + var path = Path.Combine(mod.ModHelper.Manifest.ModFolderPath, ProjectionBuilder.InvertedSlideReelCacheFolder, slidePaths[wrappedIndex]); + return ImageUtilities.IsTextureLoaded(mod, path); + } + + public void UnloadSlide(int index) + { + var wrappedIndex = (index + slides.Length) % 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)) + { + 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)); + slides[wrappedIndex]._image = null; + } + } + } } diff --git a/NewHorizons/Components/EOTE/NHSlideCollectionContainer.cs b/NewHorizons/Components/EOTE/NHSlideCollectionContainer.cs index 8b0fb6d7..1f9f0361 100644 --- a/NewHorizons/Components/EOTE/NHSlideCollectionContainer.cs +++ b/NewHorizons/Components/EOTE/NHSlideCollectionContainer.cs @@ -1,15 +1,7 @@ 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,16 +10,6 @@ public class NHSlideCollectionContainer : SlideCollectionContainer { public string[] conditionsToSet; public string[] persistentConditionsToSet; - public string[] slidePaths; - public IModBehaviour mod; - - private HashSet _pathsBeingLoaded = new(); - - public static Dictionary> _slidesRequiringPath = new(); - static NHSlideCollectionContainer() - { - SceneManager.sceneUnloaded += (_) => _slidesRequiringPath.Clear(); - } [HarmonyPrefix] [HarmonyPatch(typeof(SlideCollectionContainer), nameof(SlideCollectionContainer.Initialize))] @@ -87,7 +69,7 @@ public class NHSlideCollectionContainer : SlideCollectionContainer { if (__instance is NHSlideCollectionContainer container) { - __result = container.IsSlideLoaded(container.slideIndex + 1); + __result = (container.slideCollection as NHSlideCollection).IsSlideLoaded(container.slideIndex + 1); return false; } else @@ -103,7 +85,7 @@ public class NHSlideCollectionContainer : SlideCollectionContainer { if (__instance is NHSlideCollectionContainer container) { - __result = container.IsSlideLoaded(container.slideIndex - 1); + __result = (container.slideCollection as NHSlideCollection).IsSlideLoaded(container.slideIndex - 1); return false; } else @@ -118,9 +100,9 @@ public class NHSlideCollectionContainer : SlideCollectionContainer { if (__instance is NHSlideCollectionContainer container) { - for (int i = 0; i < container.slidePaths.Length; i++) + for (int i = 0; i < (container.slideCollection as NHSlideCollection).slidePaths.Length; i++) { - container.UnloadSlide(i); + (container.slideCollection as NHSlideCollection).UnloadSlide(i); } return false; } @@ -136,7 +118,7 @@ public class NHSlideCollectionContainer : SlideCollectionContainer { if (__instance is NHSlideCollectionContainer container) { - __result = container.LoadSlide(id); + __result = (container.slideCollection as NHSlideCollection).LoadSlide(id); return false; } else @@ -151,7 +133,7 @@ public class NHSlideCollectionContainer : SlideCollectionContainer { if (__instance is NHSlideCollectionContainer container) { - container.LoadSlide(__instance._currentSlideIndex); + (container.slideCollection as NHSlideCollection).LoadSlide(__instance._currentSlideIndex); return false; } else @@ -166,7 +148,7 @@ public class NHSlideCollectionContainer : SlideCollectionContainer { if (__instance is NHSlideCollectionContainer container) { - __result = container.slidePaths != null && container.slidePaths.Any(); + __result = (container.slideCollection as NHSlideCollection).slidePaths != null && (container.slideCollection as NHSlideCollection).slidePaths.Any(); return false; } else @@ -174,85 +156,4 @@ public class NHSlideCollectionContainer : SlideCollectionContainer return true; } } - - public Texture LoadSlide(int index) - { - Texture LoadSlideInt(int index) - { - 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); - } - - if (ImageUtilities.IsTextureLoaded(mod, path)) - { - var texture = ImageUtilities.GetTexture(mod, path); - this.slideCollection.slides[wrappedIndex]._image = texture; - return texture; - } - else if (!_pathsBeingLoaded.Contains(path)) - { - var loader = new SlideReelAsyncImageLoader(); - loader.PathsToLoad.Add((wrappedIndex, path)); - loader.Start(true, false); - loader.imageLoadedEvent.AddListener((Texture2D tex, int index, string originalPath) => - { - slideCollection.slides[wrappedIndex]._image = tex; - _pathsBeingLoaded.Remove(path); - }); - _pathsBeingLoaded.Add(path); - return null; - } - else - { - // It is being loaded so we just wait - return null; - } - } - var texture = LoadSlideInt(index); - LoadSlideInt(index - 1); - LoadSlideInt(index + 1); - - return texture; - } - - public bool IsSlideLoaded(int index) - { - var wrappedIndex = (index + this.slideCollection.slides.Length) % this.slideCollection.slides.Length; - var path = Path.Combine(mod.ModHelper.Manifest.ModFolderPath, ProjectionBuilder.InvertedSlideReelCacheFolder, slidePaths[wrappedIndex]); - return ImageUtilities.IsTextureLoaded(mod, path); - } - - public void UnloadSlide(int index) - { - 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)) - { - 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/Patches/ShipLogPatches/ShipLogSlideReelPatches.cs b/NewHorizons/Patches/ShipLogPatches/ShipLogSlideReelPatches.cs new file mode 100644 index 00000000..390a4e79 --- /dev/null +++ b/NewHorizons/Patches/ShipLogPatches/ShipLogSlideReelPatches.cs @@ -0,0 +1,21 @@ +using HarmonyLib; +using NewHorizons.Components.EOTE; + +namespace NewHorizons.Patches.ShipLogPatches; + +[HarmonyPatch] +public static class ShipLogSlideReelPatches +{ + [HarmonyPrefix] + [HarmonyPatch(typeof(ShipLogSlideProjector), nameof(ShipLogSlideProjector.CheckStreamingTexturesAvailable))] + public static bool ShipLogSlideProjector_CheckStreamingTexturesAvailable(ShipLogSlideProjector __instance, ref bool __result) + { + if (__instance._collectionIndex >= 0 && __instance._collectionIndex < __instance._slideCollections.Count && + __instance._slideCollections[__instance._collectionIndex] is NHSlideCollection) + { + __result = true; + return false; + } + return true; + } +}