diff --git a/NewHorizons/Builder/Props/ProjectionBuilder.cs b/NewHorizons/Builder/Props/ProjectionBuilder.cs index 7df34b6c..30baf64a 100644 --- a/NewHorizons/Builder/Props/ProjectionBuilder.cs +++ b/NewHorizons/Builder/Props/ProjectionBuilder.cs @@ -140,6 +140,8 @@ 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); @@ -156,22 +158,16 @@ namespace NewHorizons.Builder.Props // We can fit 16 slides max into an atlas var textures = new Texture2D[slidesCount > 16 ? 16 : slidesCount]; - var (invImageLoader, atlasImageLoader, imageLoader) = StartAsyncLoader(mod, info.slides, ref slideCollection, true, true); + // Don't load inverted images if the cache exists, in this case we only load when actively displaying stuff + var (invImageLoader, atlasImageLoader, imageLoader) = StartAsyncLoader(mod, info.slides, ref slideCollection, !CacheExists(mod), true); // If the cache doesn't exist it will be created here, slide reels only use the base image loader for cache creation so delete the images after to free memory imageLoader.deleteTexturesWhenDone = !CacheExists(mod); var key = GetUniqueSlideReelID(mod, info.slides); - if (invImageLoader != null && atlasImageLoader != null) + if (CacheExists(mod) && atlasImageLoader != null) { - // Loading directly from cache - invImageLoader.imageLoadedEvent.AddListener( - (Texture2D tex, int index, string originalPath) => - { - slideCollection.slides[index]._image = tex; - } - ); atlasImageLoader.imageLoadedEvent.AddListener( (Texture2D tex, int _, string originalPath) => { @@ -353,7 +349,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 var (invImageLoader, _, imageLoader) = StartAsyncLoader(mod, info.slides, ref slideCollection, true, false); diff --git a/NewHorizons/Components/EOTE/NHSlideCollection.cs b/NewHorizons/Components/EOTE/NHSlideCollection.cs new file mode 100644 index 00000000..a5e357af --- /dev/null +++ b/NewHorizons/Components/EOTE/NHSlideCollection.cs @@ -0,0 +1,70 @@ +using HarmonyLib; +using NewHorizons.Utility.Files; +using OWML.Common; +using UnityEngine; + +namespace NewHorizons.Components.EOTE; + +[HarmonyPatch] +public class NHSlideCollection : SlideCollection +{ + + public string[] slidePaths; + public IModBehaviour mod; + + public NHSlideCollection(int startArrSize, IModBehaviour mod, string[] slidePaths) : base(startArrSize) + { + this.mod = mod; + this.slidePaths = slidePaths; + } + + /* + [HarmonyPrefix] + [HarmonyPatch(typeof(SlideCollection), nameof(SlideCollection.RequestStreamSlides))] + public static bool SlideCollection_RequestStreamSlides(SlideCollection __instance, int[] slideIndices) + { + if (__instance is NHSlideCollection collection) + { + foreach (var id in slideIndices) + { + collection.slides[id]._image = ImageUtilities.GetTexture(collection.mod, collection.slidePaths[id]); + } + return false; + } + else + { + return true; + } + } + + [HarmonyPrefix] + [HarmonyPatch(typeof(SlideCollection), nameof(SlideCollection.IsStreamedTextureIndexLoaded))] + public static bool SlideCollection_IsStreamedTextureIndexLoaded(SlideCollection __instance, int streamIdx, ref bool __result) + { + if (__instance is NHSlideCollection collection) + { + __result = ImageUtilities.IsTextureLoaded(collection.mod, collection.slidePaths[streamIdx]); + return false; + } + else + { + return true; + } + } + + [HarmonyPrefix] + [HarmonyPatch(typeof(SlideCollection), nameof(SlideCollection.GetStreamingTexture))] + public static bool SlideCollection_GetStreamingTexture(SlideCollection __instance, int id, ref Texture __result) + { + if (__instance is NHSlideCollection collection) + { + __result = ImageUtilities.GetTexture(collection.mod, collection.slidePaths[id]); + return false; + } + else + { + return true; + } + } + */ +} diff --git a/NewHorizons/Components/EOTE/NHSlideCollectionContainer.cs b/NewHorizons/Components/EOTE/NHSlideCollectionContainer.cs index bcf979ec..5ce38910 100644 --- a/NewHorizons/Components/EOTE/NHSlideCollectionContainer.cs +++ b/NewHorizons/Components/EOTE/NHSlideCollectionContainer.cs @@ -1,4 +1,12 @@ using HarmonyLib; +using NewHorizons.Builder.Props; +using NewHorizons.External.Modules.Props.EchoesOfTheEye; +using NewHorizons.Utility.Files; +using OWML.Common; +using System; +using System.IO; +using System.Linq; +using UnityEngine; namespace NewHorizons.Components.EOTE; @@ -7,12 +15,14 @@ public class NHSlideCollectionContainer : SlideCollectionContainer { public string[] conditionsToSet; public string[] persistentConditionsToSet; + public string[] slidePaths; + public IModBehaviour mod; [HarmonyPrefix] [HarmonyPatch(typeof(SlideCollectionContainer), nameof(SlideCollectionContainer.Initialize))] public static bool SlideCollectionContainer_Initialize(SlideCollectionContainer __instance) { - if (__instance is NHSlideCollectionContainer) + if (__instance is NHSlideCollectionContainer container) { if (__instance._initialized) return false; @@ -24,7 +34,7 @@ public class NHSlideCollectionContainer : SlideCollectionContainer __instance._changeSlidesAllowed = true; __instance._initialized = true; __instance._slideCollection.isVision = __instance._owningItem == null; - foreach (var factID in __instance._playWithShipLogFacts) + foreach (var factID in __instance._playWithShipLogFacts ?? Array.Empty()) { var fact = Locator.GetShipLogManager().GetFact(factID); fact?.RegisterSlideCollection(__instance._slideCollection); @@ -59,4 +69,135 @@ public class NHSlideCollectionContainer : SlideCollectionContainer } } } + + [HarmonyPrefix] + [HarmonyPatch(typeof(SlideCollectionContainer), nameof(SlideCollectionContainer.NextSlideAvailable))] + public static bool SlideCollectionContainer_NextSlideAvailable(SlideCollectionContainer __instance, ref bool __result) + { + if (__instance is NHSlideCollectionContainer container) + { + __result = container.IsSlideLoaded(container.slideIndex + 1); + return false; + } + else + { + return true; + } + } + + + [HarmonyPrefix] + [HarmonyPatch(typeof(SlideCollectionContainer), nameof(SlideCollectionContainer.PrevSlideAvailable))] + public static bool SlideCollectionContainer_PrevSlideAvailable(SlideCollectionContainer __instance, ref bool __result) + { + if (__instance is NHSlideCollectionContainer container) + { + __result = container.IsSlideLoaded(container.slideIndex - 1); + return false; + } + else + { + return true; + } + } + + [HarmonyPrefix] + [HarmonyPatch(typeof(SlideCollectionContainer), nameof(SlideCollectionContainer.UnloadStreamingTextures))] + public static bool SlideCollectionContainer_UnloadStreamingTextures(SlideCollectionContainer __instance) + { + if (__instance is NHSlideCollectionContainer container) + { + for (int i = 0; i < container.slidePaths.Length; i++) + { + container.UnloadSlide(i); + } + return false; + } + else + { + return true; + } + } + + [HarmonyPrefix] + [HarmonyPatch(typeof(SlideCollectionContainer), nameof(SlideCollectionContainer.GetStreamingTexture))] + public static bool SlideCollectionContainer_GetStreamingTexture(SlideCollectionContainer __instance, int id, ref Texture __result) + { + if (__instance is NHSlideCollectionContainer container) + { + __result = container.LoadSlide(id); + return false; + } + else + { + return true; + } + } + + [HarmonyPrefix] + [HarmonyPatch(typeof(SlideCollectionContainer), nameof(SlideCollectionContainer.RequestManualStreamSlides))] + public static bool SlideCollectionContainer_RequestManualStreamSlides(SlideCollectionContainer __instance) + { + if (__instance is NHSlideCollectionContainer container) + { + container.LoadSlide(__instance._currentSlideIndex); + return false; + } + else + { + return true; + } + } + + [HarmonyPrefix] + [HarmonyPatch(typeof(SlideCollectionContainer), nameof(SlideCollectionContainer.streamingTexturesAvailable), MethodType.Getter)] + public static bool SlideCollectionContainer_streamingTexturesAvailable(SlideCollectionContainer __instance, ref bool __result) + { + if (__instance is NHSlideCollectionContainer container) + { + __result = container.slidePaths != null && container.slidePaths.Any(); + return false; + } + else + { + 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]); + + var texture = ImageUtilities.GetTexture(mod, path); + this.slideCollection.slides[wrappedIndex]._image = texture; + return texture; + } + 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]); + + if (ImageUtilities.IsTextureLoaded(mod, path)) + { + ImageUtilities.DeleteTexture(mod, path, ImageUtilities.GetTexture(mod, path)); + slideCollection.slides[wrappedIndex]._image = null; + } + } }