diff --git a/NewHorizons/Builder/Props/DetailBuilder.cs b/NewHorizons/Builder/Props/DetailBuilder.cs index 25e22eb2..660956b6 100644 --- a/NewHorizons/Builder/Props/DetailBuilder.cs +++ b/NewHorizons/Builder/Props/DetailBuilder.cs @@ -1,4 +1,3 @@ -using NewHorizons.Builder.General; using NewHorizons.External.Configs; using NewHorizons.External.Modules; using NewHorizons.Handlers; @@ -80,7 +79,7 @@ namespace NewHorizons.Builder.Props } else FixSectoredComponent(component, sector, isTorch); - FixComponent(component, go, prefab.name); + FixComponent(component, go); } prop.transform.position = detail.position == null ? go.transform.position : go.transform.TransformPoint(detail.position); @@ -101,7 +100,6 @@ namespace NewHorizons.Builder.Props prop.transform.localScale = detail.scale != 0 ? Vector3.one * detail.scale : prefab.transform.localScale; - if (!detail.keepLoaded) GroupsBuilder.Make(prop, sector); prop.SetActive(true); if (prop == null) return null; @@ -224,11 +222,11 @@ namespace NewHorizons.Builder.Props return false; } - private static void FixComponent(Component component, GameObject planetGO, string prefab) + private static void FixComponent(Component component, GameObject planetGO) { // Fix other components // I forget why this is here - if (component is GhostIK || component is GhostEffects) + if (component is GhostIK or GhostEffects) { Component.DestroyImmediate(component); return; @@ -280,43 +278,52 @@ namespace NewHorizons.Builder.Props torchItem.mindSlideProjector._mindProjectorImageEffect = SearchUtilities.Find("Player_Body/PlayerCamera").GetComponent(); } - // Fix a bunch of stuff when done loading - Delay.RunWhen(() => Main.IsSystemReady, () => + if (component is Animator animator) animator.enabled = true; + if (component is Collider collider) collider.enabled = true; + if (component is Renderer renderer) renderer.enabled = true; + if (component is Shape shape) shape.enabled = true; + + // fixes sector cull group deactivating renderers on map view enter and fast foward + // TODO: does this actually work? what? how? + if (component is SectorCullGroup sectorCullGroup) { - try + sectorCullGroup._inMapView = false; + sectorCullGroup._isFastForwarding = false; + sectorCullGroup.SetVisible(sectorCullGroup.ShouldBeVisible(), true, false); + } + + // If it's not a moving anglerfish make sure the anim controller is regular + if (component is AnglerfishAnimController && component.GetComponentInParent() == null) + component.gameObject.AddComponent(); + } + + /// + /// Has to happen after AnglerfishAnimController awake to remove the events it has set up. + /// Otherwise results in the anglerfish 1) having its animations controlled by an actual fish 2) randomly having different animations on solarsystem load + /// Can't do delay because it needs to work with scatter (copies a prefab made using MakeDetail). + /// + [RequireComponent(typeof(AnglerfishAnimController))] + private class AnglerAnimFixer : MonoBehaviour + { + private void Start() + { + var angler = GetComponent(); + + Logger.LogVerbose("Fixing anglerfish animation"); + + // Remove any event reference to its angler + if (angler._anglerfishController) { - if (component == null) return; - if (component is Animator animator) animator.enabled = true; - else if (component is Collider collider) collider.enabled = true; - else if (component is Renderer renderer) renderer.enabled = true; - else if (component is Shape shape) shape.enabled = true; - else if (component is SectorCullGroup sectorCullGroup) - { - sectorCullGroup._inMapView = false; - sectorCullGroup._isFastForwarding = false; - sectorCullGroup.SetVisible(sectorCullGroup.ShouldBeVisible(), true, false); - } - // If it's not a moving anglerfish make sure the anim controller is regular - else if (component is AnglerfishAnimController angler && angler.GetComponentInParent() == null) - { - Logger.LogVerbose("Enabling anglerfish animation"); - // Remove any reference to its angler - if (angler._anglerfishController) - { - angler._anglerfishController.OnChangeAnglerState -= angler.OnChangeAnglerState; - angler._anglerfishController.OnAnglerTurn -= angler.OnAnglerTurn; - angler._anglerfishController.OnAnglerSuspended -= angler.OnAnglerSuspended; - angler._anglerfishController.OnAnglerUnsuspended -= angler.OnAnglerUnsuspended; - } - angler.enabled = true; - angler.OnChangeAnglerState(AnglerfishController.AnglerState.Lurking); - } + angler._anglerfishController.OnChangeAnglerState -= angler.OnChangeAnglerState; + angler._anglerfishController.OnAnglerTurn -= angler.OnAnglerTurn; + angler._anglerfishController.OnAnglerSuspended -= angler.OnAnglerSuspended; + angler._anglerfishController.OnAnglerUnsuspended -= angler.OnAnglerUnsuspended; } - catch (Exception e) - { - Logger.LogWarning($"Exception when modifying component [{component.GetType().Name}] on [{planetGO.name}] for prop [{prefab}]:\n{e}"); - } - }); + angler.enabled = true; + angler.OnChangeAnglerState(AnglerfishController.AnglerState.Lurking); + + Destroy(this); + } } } } \ No newline at end of file diff --git a/NewHorizons/Builder/Props/ProjectionBuilder.cs b/NewHorizons/Builder/Props/ProjectionBuilder.cs index f6cb399d..e80d451d 100644 --- a/NewHorizons/Builder/Props/ProjectionBuilder.cs +++ b/NewHorizons/Builder/Props/ProjectionBuilder.cs @@ -4,9 +4,11 @@ using NewHorizons.Utility; using OWML.Common; using System; using System.Collections.Generic; +using System.Threading; using UnityEngine; using static NewHorizons.External.Modules.PropModule; using Logger = NewHorizons.Utility.Logger; + namespace NewHorizons.Builder.Props { public static class ProjectionBuilder @@ -89,19 +91,8 @@ namespace NewHorizons.Builder.Props // The base game ones only have 15 slides max var textures = new Texture2D[slidesCount >= 15 ? 15 : slidesCount]; - var imageLoader = slideReelObj.AddComponent(); - for (int i = 0; i < slidesCount; i++) - { - var slide = new Slide(); - var slideInfo = info.slides[i]; + var imageLoader = AddAsyncLoader(slideReelObj, mod, info.slides, ref slideCollection); - imageLoader.pathsToLoad.Add(mod.ModHelper.Manifest.ModFolderPath + slideInfo.imagePath); - - AddModules(slideInfo, ref slide, mod); - - slideCollection.slides[i] = slide; - } - // this variable just lets us track how many of the first 15 slides have been loaded. // this way as soon as the last one is loaded (due to async loading, this may be // slide 7, or slide 3, or whatever), we can build the slide reel texture. This allows us @@ -113,24 +104,22 @@ namespace NewHorizons.Builder.Props slideCollection.slides[index]._image = ImageUtilities.Invert(tex); // Track the first 15 to put on the slide reel object - if (index < 15) + if (index < textures.Length) { textures[index] = tex; - displaySlidesLoaded++; // threading moment - } + if (Interlocked.Increment(ref displaySlidesLoaded) == textures.Length) + { + // all textures required to build the reel's textures have been loaded + var slidesBack = slideReelObj.transform.Find("Props_IP_SlideReel_7/Slides_Back").GetComponent(); + var slidesFront = slideReelObj.transform.Find("Props_IP_SlideReel_7/Slides_Front").GetComponent(); - if (displaySlidesLoaded >= textures.Length) - { - // all textures required to build the reel's textures have been loaded - var slidesBack = slideReelObj.transform.Find("Props_IP_SlideReel_7/Slides_Back").GetComponent(); - var slidesFront = slideReelObj.transform.Find("Props_IP_SlideReel_7/Slides_Front").GetComponent(); - - // Now put together the textures into a 4x4 thing for the materials - var reelTexture = ImageUtilities.MakeReelTexture(textures); - slidesBack.material.mainTexture = reelTexture; - slidesBack.material.SetTexture(EmissionMap, reelTexture); - slidesFront.material.mainTexture = reelTexture; - slidesFront.material.SetTexture(EmissionMap, reelTexture); + // Now put together the textures into a 4x4 thing for the materials + var reelTexture = ImageUtilities.MakeReelTexture(textures); + slidesBack.material.mainTexture = reelTexture; + slidesBack.material.SetTexture(EmissionMap, reelTexture); + slidesFront.material.mainTexture = reelTexture; + slidesFront.material.SetTexture(EmissionMap, reelTexture); + } } } ); @@ -191,18 +180,7 @@ namespace NewHorizons.Builder.Props int slidesCount = info.slides.Length; var slideCollection = new SlideCollection(slidesCount); - var imageLoader = projectorObj.AddComponent(); - for (int i = 0; i < slidesCount; i++) - { - var slide = new Slide(); - var slideInfo = info.slides[i]; - - imageLoader.pathsToLoad.Add(mod.ModHelper.Manifest.ModFolderPath + slideInfo.imagePath); - - AddModules(slideInfo, ref slide, mod); - - slideCollection.slides[i] = slide; - } + var imageLoader = AddAsyncLoader(projectorObj, mod, info.slides, ref slideCollection); imageLoader.imageLoadedEvent.AddListener((Texture2D tex, int index) => { slideCollection.slides[index]._image = ImageUtilities.Invert(tex); }); slideCollectionContainer.slideCollection = slideCollection; @@ -256,19 +234,7 @@ namespace NewHorizons.Builder.Props var slidesCount = slides.Length; var slideCollection = new SlideCollection(slidesCount); - - var imageLoader = g.AddComponent(); - for (int i = 0; i < slidesCount; i++) - { - var slide = new Slide(); - var slideInfo = slides[i]; - - imageLoader.pathsToLoad.Add(mod.ModHelper.Manifest.ModFolderPath + slideInfo.imagePath); - - AddModules(slideInfo, ref slide, mod); - - slideCollection.slides[i] = slide; - } + var imageLoader = AddAsyncLoader(g, mod, info.slides, ref slideCollection); imageLoader.imageLoadedEvent.AddListener((Texture2D tex, int index) => { slideCollection.slides[index]._image = tex; }); // attach a component to store all the data for the slides that play when a vision torch scans this target @@ -330,19 +296,8 @@ namespace NewHorizons.Builder.Props var slidesCount = slides.Length; var slideCollection = new SlideCollection(slidesCount); - var imageLoader = standingTorch.AddComponent(); - for (int i = 0; i < slidesCount; i++) - { - var slide = new Slide(); - var slideInfo = slides[i]; + var imageLoader = AddAsyncLoader(standingTorch, mod, slides, ref slideCollection); - imageLoader.pathsToLoad.Add(mod.ModHelper.Manifest.ModFolderPath + slideInfo.imagePath); - - AddModules(slideInfo, ref slide, mod); - - slideCollection.slides[i] = slide; - } - // This variable just lets us track how many of the slides have been loaded. // This way as soon as the last one is loaded (due to async loading, this may be // slide 7, or slide 3, or whatever), we can enable the vision torch. This allows us @@ -352,9 +307,8 @@ namespace NewHorizons.Builder.Props (Texture2D tex, int index) => { slideCollection.slides[index]._image = tex; - displaySlidesLoaded++; // threading moment - if (displaySlidesLoaded >= slides.Length) + if (Interlocked.Increment(ref displaySlidesLoaded) == slides.Length) { mindSlideProjector.enabled = true; visionBeamEffect.SetActive(true); @@ -378,6 +332,32 @@ namespace NewHorizons.Builder.Props return standingTorch; } + private static ImageUtilities.AsyncImageLoader AddAsyncLoader(GameObject gameObject, IModBehaviour mod, SlideInfo[] slides, ref SlideCollection slideCollection) + { + var imageLoader = gameObject.AddComponent(); + for (int i = 0; i < slides.Length; i++) + { + var slide = new Slide(); + var slideInfo = slides[i]; + + if (string.IsNullOrEmpty(slideInfo.imagePath)) + { + imageLoader.imageLoadedEvent?.Invoke(Texture2D.blackTexture, i); + } + else + { + // Don't use Path.Combine here else you break the Vision + imageLoader.PathsToLoad.Add((i, mod.ModHelper.Manifest.ModFolderPath + slideInfo.imagePath)); + } + + AddModules(slideInfo, ref slide, mod); + + slideCollection.slides[i] = slide; + } + + return imageLoader; + } + private static void AddModules(PropModule.SlideInfo slideInfo, ref Slide slide, IModBehaviour mod) { var modules = new List(); diff --git a/NewHorizons/Builder/Props/ScatterBuilder.cs b/NewHorizons/Builder/Props/ScatterBuilder.cs index 3ce71605..a92ebd9b 100644 --- a/NewHorizons/Builder/Props/ScatterBuilder.cs +++ b/NewHorizons/Builder/Props/ScatterBuilder.cs @@ -3,6 +3,8 @@ using NewHorizons.External.Modules; using NewHorizons.Utility; using OWML.Common; using System; +using System.Collections.Generic; +using System.Linq; using UnityEngine; using Object = UnityEngine.Object; using Random = UnityEngine.Random; @@ -19,13 +21,20 @@ namespace NewHorizons.Builder.Props { var heightMap = config.HeightMap; - var area = 4f * Mathf.PI * radius * radius; + var makeFibonacciSphere = scatterInfo.Any(x => x.preventOverlap); - // To not use more than 0.5GB of RAM while doing this - // Works up to planets with 575 radius before capping - var numPoints = Math.Min((int)(area * 10), 41666666); + List points = new(); - var points = RandomUtility.FibonacciSphere(numPoints); + if (makeFibonacciSphere) + { + var area = 4f * Mathf.PI * radius * radius; + + // To not use more than 0.5GB of RAM while doing this + // Works up to planets with 575 radius before capping + var numPoints = Math.Min((int)(area * 10), 41666666); + + points = RandomUtility.FibonacciSphere(numPoints); + } Texture2D heightMapTexture = null; if (heightMap != null) @@ -55,13 +64,29 @@ namespace NewHorizons.Builder.Props GameObject prefab; if (propInfo.assetBundle != null) prefab = AssetBundleUtilities.LoadPrefab(propInfo.assetBundle, propInfo.path, mod); else prefab = SearchUtilities.Find(propInfo.path); + + // Run all the make detail stuff on it early and just copy it over and over instead + var detailInfo = new PropModule.DetailInfo() + { + scale = propInfo.scale, + keepLoaded = propInfo.keepLoaded + }; + var scatterPrefab = DetailBuilder.Make(go, sector, prefab, detailInfo); + for (int i = 0; i < propInfo.count; i++) { - // Failsafe - if (points.Count == 0) break; - - var randomInd = (int)Random.Range(0, points.Count - 1); - var point = points[randomInd]; + Vector3 point; + if (propInfo.preventOverlap) + { + if (points.Count == 0) break; + var randomInd = Random.Range(0, points.Count - 1); + point = points[randomInd]; + points.QuickRemoveAt(randomInd); + } + else + { + point = Random.onUnitSphere; + } var height = radius; if (heightMapTexture != null) @@ -92,14 +117,11 @@ namespace NewHorizons.Builder.Props point = Quaternion.Euler(90, 0, 0) * point; } - var detailInfo = new PropModule.DetailInfo() - { - position = point.normalized * height, - scale = propInfo.scale, - keepLoaded = propInfo.keepLoaded, - alignToNormal = true - }; - var prop = DetailBuilder.Make(go, sector, prefab, detailInfo); + var prop = scatterPrefab.InstantiateInactive(); + prop.transform.SetParent(sector?.transform ?? go.transform); + prop.transform.localPosition = go.transform.TransformPoint(point * height); + var up = go.transform.InverseTransformPoint(prop.transform.position).normalized; + prop.transform.rotation = Quaternion.FromToRotation(Vector3.up, up); if (propInfo.offset != null) prop.transform.localPosition += prop.transform.TransformVector(propInfo.offset); if (propInfo.rotation != null) prop.transform.rotation *= Quaternion.Euler(propInfo.rotation); @@ -107,9 +129,10 @@ namespace NewHorizons.Builder.Props // Rotate around normal prop.transform.localRotation *= Quaternion.AngleAxis(Random.Range(0, 360), Vector3.up); - points.QuickRemoveAt(randomInd); - if (points.Count == 0) return; + prop.SetActive(true); } + + GameObject.Destroy(scatterPrefab); } } } diff --git a/NewHorizons/External/Configs/StarSystemConfig.cs b/NewHorizons/External/Configs/StarSystemConfig.cs index ce311174..5d3963aa 100644 --- a/NewHorizons/External/Configs/StarSystemConfig.cs +++ b/NewHorizons/External/Configs/StarSystemConfig.cs @@ -14,6 +14,11 @@ namespace NewHorizons.External.Configs [JsonObject] public class StarSystemConfig { + /// + /// An override value for the far clip plane. Allows you to see farther. + /// + public float farClipPlaneOverride; + /// /// Whether this system can be warped to via the warp drive. If you set factRequiredForWarp, this will be true. /// diff --git a/NewHorizons/External/Modules/PropModule.cs b/NewHorizons/External/Modules/PropModule.cs index b02f762d..1644192d 100644 --- a/NewHorizons/External/Modules/PropModule.cs +++ b/NewHorizons/External/Modules/PropModule.cs @@ -139,6 +139,11 @@ namespace NewHorizons.External.Modules /// The highest height that these objects will be placed at (only relevant if there's a heightmap) /// public float? maxHeight; + + /// + /// Should we try to prevent overlap between the scattered details? True by default. If it's affecting load times turn it off. + /// + [DefaultValue(true)] public bool preventOverlap = true; /// /// Should this detail stay loaded even if you're outside the sector (good for very large props) diff --git a/NewHorizons/Handlers/CreditsHandler.cs b/NewHorizons/Handlers/CreditsHandler.cs index 9d7e7405..f71a73ef 100644 --- a/NewHorizons/Handlers/CreditsHandler.cs +++ b/NewHorizons/Handlers/CreditsHandler.cs @@ -39,7 +39,7 @@ namespace NewHorizons.Handlers private static void AddCreditsSection(string sectionName, string[] entries, ref XmlDocument xml) { - var finalCredits = xml.SelectSingleNode("Credits/section"); + var finalCredits = xml.SelectSingleNode("Credits/section[@name='CreditsFinal']"); /* * Looks bad, would need more customization, complicated, messes up music timing, wont do for now @@ -134,11 +134,8 @@ namespace NewHorizons.Handlers { var rootSection = MakeNode(doc, "section", new Dictionary() { - { "platform", "All" }, - { "type", "Scroll" }, - { "scrollDuration", "214" }, - { "spacing", "12" }, - { "width", "1590" } + { "name", "Custom" }, + { "credits-type", "Final Fast Krazy" } }); var titleLayout = MakeNode(doc, "layout", new Dictionary() diff --git a/NewHorizons/Main.cs b/NewHorizons/Main.cs index b734b29b..f46b6432 100644 --- a/NewHorizons/Main.cs +++ b/NewHorizons/Main.cs @@ -122,7 +122,7 @@ namespace NewHorizons _wasConfigured = true; } - public static void ResetConfigs(bool resetTranslation = true) + public void ResetConfigs(bool resetTranslation = true) { BodyDict.Clear(); SystemDict.Clear(); @@ -161,9 +161,13 @@ namespace NewHorizons } }; - if (!resetTranslation) return; - TranslationHandler.ClearTables(); - TextTranslation.Get().SetLanguage(TextTranslation.Get().GetLanguage()); + if (resetTranslation) + { + TranslationHandler.ClearTables(); + TextTranslation.Get().SetLanguage(TextTranslation.Get().GetLanguage()); + } + + LoadTranslations(Instance.ModHelper.Manifest.ModFolderPath + "Assets/", this); } public void Awake() @@ -213,7 +217,6 @@ namespace NewHorizons OnStarSystemLoaded.AddListener(RichPresenceHandler.OnStarSystemLoaded); OnChangeStarSystem.AddListener(RichPresenceHandler.OnChangeStarSystem); - LoadTranslations(ModHelper.Manifest.ModFolderPath + "Assets/", this); LoadAddonManifest("Assets/addon-manifest.json", this); } diff --git a/NewHorizons/OtherMods/MenuFramework/MenuHandler.cs b/NewHorizons/OtherMods/MenuFramework/MenuHandler.cs index 45682279..bb88e7b4 100644 --- a/NewHorizons/OtherMods/MenuFramework/MenuHandler.cs +++ b/NewHorizons/OtherMods/MenuFramework/MenuHandler.cs @@ -4,9 +4,7 @@ using NewHorizons.Utility; using OWML.Common; using System.Collections.Generic; using System.Linq; -using System.Net.Mail; using UnityEngine; -using static UnityEngine.InputSystem.InputRemoting; using Logger = NewHorizons.Utility.Logger; namespace NewHorizons.OtherMods.MenuFramework diff --git a/NewHorizons/Patches/MapControllerPatches.cs b/NewHorizons/Patches/MapControllerPatches.cs index dd53f603..3c13673e 100644 --- a/NewHorizons/Patches/MapControllerPatches.cs +++ b/NewHorizons/Patches/MapControllerPatches.cs @@ -1,4 +1,5 @@ using HarmonyLib; +using UnityEngine; using UnityEngine.SceneManagement; namespace NewHorizons.Patches @@ -10,11 +11,11 @@ namespace NewHorizons.Patches [HarmonyPatch(typeof(MapController), nameof(MapController.Awake))] public static void MapController_Awake(MapController __instance) { - __instance._maxPanDistance = Main.FurthestOrbit * 1.5f; + __instance._maxPanDistance = Mathf.Max(__instance._maxPanDistance, Main.FurthestOrbit * 1.5f); __instance._maxZoomDistance *= 6f; __instance._minPitchAngle = -90f; __instance._zoomSpeed *= 4f; - __instance._mapCamera.farClipPlane = Main.FurthestOrbit * 10f; + __instance._mapCamera.farClipPlane = Mathf.Max(__instance._mapCamera.farClipPlane, Main.FurthestOrbit * 10f); } [HarmonyPostfix] diff --git a/NewHorizons/Patches/OWCameraPatch.cs b/NewHorizons/Patches/OWCameraPatch.cs index 863b56bd..ccdafafc 100644 --- a/NewHorizons/Patches/OWCameraPatch.cs +++ b/NewHorizons/Patches/OWCameraPatch.cs @@ -1,4 +1,4 @@ -using HarmonyLib; +using HarmonyLib; namespace NewHorizons.Patches { [HarmonyPatch] @@ -8,25 +8,12 @@ namespace NewHorizons.Patches [HarmonyPatch(typeof(OWCamera), nameof(OWCamera.Awake))] public static void OnOWCameraAwake(OWCamera __instance) { - // var oldDist = __instance.farClipPlane; - // var newDist = __instance.farClipPlane * 10f; - // if (__instance.useFarCamera) Mathf.Clamp(newDist, oldDist, 50000f); - // else newDist = Mathf.Clamp(newDist, oldDist, 10000000f); - // __instance.farClipPlane = newDist; - // __instance.farCameraDistance = newDist; - // __instance.mainCamera.farClipPlane = newDist; + if (Main.SystemDict.TryGetValue(Main.Instance.CurrentStarSystem, out var system) && system?.Config?.farClipPlaneOverride != 0f) + { + __instance.farClipPlane = system.Config.farClipPlaneOverride; + __instance.farCameraDistance = system.Config.farClipPlaneOverride; + __instance.mainCamera.farClipPlane = system.Config.farClipPlaneOverride; + } } - - // [HarmonyPrefix] - // [HarmonyPatch(typeof(OWCamera), nameof(OWCamera.RebuildSkybox))] - // public static bool OnOWCameraRebuildSkybox(OWCamera __instance) - // { - // __instance._skyboxCommandBuffer = new CommandBuffer(); - // __instance._skyboxCommandBuffer.name = "Skybox"; - // var camera = __instance._useFarCamera && !SystemInfo.usesReversedZBuffer ? __instance._farCamera : __instance._mainCamera; - // CameraEvent evt = CameraEvent.BeforeSkybox; - // camera.AddCommandBuffer(evt, __instance._skyboxCommandBuffer); - // return false; - // } } } diff --git a/NewHorizons/Schemas/body_schema.json b/NewHorizons/Schemas/body_schema.json index 5d000e07..a3d243d1 100644 --- a/NewHorizons/Schemas/body_schema.json +++ b/NewHorizons/Schemas/body_schema.json @@ -1395,6 +1395,11 @@ "description": "The highest height that these objects will be placed at (only relevant if there's a heightmap)", "format": "float" }, + "preventOverlap": { + "type": "boolean", + "description": "Should we try to prevent overlap between the scattered details? True by default. If it's affecting load times turn it off.", + "default": true + }, "keepLoaded": { "type": "boolean", "description": "Should this detail stay loaded even if you're outside the sector (good for very large props)" diff --git a/NewHorizons/Schemas/star_system_schema.json b/NewHorizons/Schemas/star_system_schema.json index 032fb8f1..f1f8785e 100644 --- a/NewHorizons/Schemas/star_system_schema.json +++ b/NewHorizons/Schemas/star_system_schema.json @@ -5,6 +5,11 @@ "description": "Configuration for a specific star system", "additionalProperties": false, "properties": { + "farClipPlaneOverride": { + "type": "number", + "description": "An override value for the far clip plane. Allows you to see farther.", + "format": "float" + }, "canEnterViaWarpDrive": { "type": "boolean", "description": "Whether this system can be warped to via the warp drive. If you set factRequiredForWarp, this will be true.", diff --git a/NewHorizons/Utility/DebugUtilities/DebugReload.cs b/NewHorizons/Utility/DebugUtilities/DebugReload.cs index b8a513c9..1bb6e639 100644 --- a/NewHorizons/Utility/DebugUtilities/DebugReload.cs +++ b/NewHorizons/Utility/DebugUtilities/DebugReload.cs @@ -31,7 +31,7 @@ namespace NewHorizons.Utility.DebugUtilities { Logger.Log("Begin reload of config files..."); - Main.ResetConfigs(); + Main.Instance.ResetConfigs(); try { diff --git a/NewHorizons/Utility/ImageUtilities.cs b/NewHorizons/Utility/ImageUtilities.cs index e875341f..cf884938 100644 --- a/NewHorizons/Utility/ImageUtilities.cs +++ b/NewHorizons/Utility/ImageUtilities.cs @@ -3,10 +3,10 @@ using System; using System.Collections; using System.Collections.Generic; using System.IO; +using System.Linq; using UnityEngine; using UnityEngine.Events; using UnityEngine.Networking; -using UnityEngine.UIElements; namespace NewHorizons.Utility { @@ -128,7 +128,7 @@ namespace NewHorizons.Utility var texture = (new Texture2D(size * 4, size * 4, TextureFormat.ARGB32, false)); texture.name = "SlideReelAtlas"; - Color[] fillPixels = new Color[size * size * 4 * 4]; + var fillPixels = new Color[size * size * 4 * 4]; for (int xIndex = 0; xIndex < 4; xIndex++) { for (int yIndex = 0; yIndex < 4; yIndex++) @@ -276,8 +276,8 @@ namespace NewHorizons.Utility { var tex = (new Texture2D(1, 1, TextureFormat.ARGB32, false)); tex.name = "Clear"; - Color fillColor = Color.clear; - Color[] fillPixels = new Color[tex.width * tex.height]; + var fillColor = Color.clear; + var fillPixels = new Color[tex.width * tex.height]; for (int i = 0; i < fillPixels.Length; i++) { fillPixels[i] = fillColor; @@ -296,7 +296,7 @@ namespace NewHorizons.Utility { var tex = (new Texture2D(width, height, TextureFormat.ARGB32, false)); tex.name = src.name + "CanvasScaled"; - Color[] fillPixels = new Color[tex.width * tex.height]; + var fillPixels = new Color[tex.width * tex.height]; for (int i = 0; i < tex.width; i++) { for (int j = 0; j < tex.height; j++) @@ -339,14 +339,14 @@ namespace NewHorizons.Utility } public static Texture2D MakeSolidColorTexture(int width, int height, Color color) { - Color[] pixels = new Color[width*height]; + var pixels = new Color[width*height]; for(int i = 0; i < pixels.Length; i++) { pixels[i] = color; } - Texture2D newTexture = new Texture2D(width, height); + var newTexture = new Texture2D(width, height); newTexture.SetPixels(pixels); newTexture.Apply(); return newTexture; @@ -364,10 +364,15 @@ namespace NewHorizons.Utility // Modified from https://stackoverflow.com/a/69141085/9643841 public class AsyncImageLoader : MonoBehaviour { - public List pathsToLoad = new List(); + public List<(int index, string path)> PathsToLoad { get; private set; } = new (); public class ImageLoadedEvent : UnityEvent { } - public ImageLoadedEvent imageLoadedEvent = new ImageLoadedEvent(); + public ImageLoadedEvent imageLoadedEvent = new (); + + private readonly object _lockObj = new(); + + public bool FinishedLoading { get; private set; } + private int _loadedCount = 0; // TODO: set up an optional “StartLoading” and “StartUnloading” condition on AsyncTextureLoader, // and make use of that for at least for projector stuff (require player to be in the same sector as the slides @@ -375,39 +380,59 @@ namespace NewHorizons.Utility void Start() { - for (int i = 0; i < pathsToLoad.Count; i++) + imageLoadedEvent.AddListener(OnImageLoaded); + foreach (var (index, path) in PathsToLoad) { - StartCoroutine(DownloadTexture(pathsToLoad[i], i)); + StartCoroutine(DownloadTexture(path, index)); + } + } + + private void OnImageLoaded(Texture texture, int index) + { + lock (_lockObj) + { + _loadedCount++; + + if (_loadedCount >= PathsToLoad.Count) + { + Logger.LogVerbose($"Finished loading all textures for {gameObject.name} (one was {PathsToLoad.FirstOrDefault()}"); + FinishedLoading = true; + } } } IEnumerator DownloadTexture(string url, int index) { - if (_loadedTextures.ContainsKey(url)) + lock(_loadedTextures) { - Logger.LogVerbose($"Already loaded image at path: {url}"); - var texture = _loadedTextures[url]; - imageLoadedEvent.Invoke(texture, index); - yield break; + if (_loadedTextures.ContainsKey(url)) + { + Logger.LogVerbose($"Already loaded image {index}:{url}"); + var texture = _loadedTextures[url]; + imageLoadedEvent?.Invoke(texture, index); + yield break; + } } - using (UnityWebRequest uwr = UnityWebRequestTexture.GetTexture(url)) + using UnityWebRequest uwr = UnityWebRequestTexture.GetTexture(url); + + yield return uwr.SendWebRequest(); + + var hasError = uwr.error != null && uwr.error != ""; + + if (hasError) { - yield return uwr.SendWebRequest(); + Logger.LogError($"Failed to load {index}:{url} - {uwr.error}"); + } + else + { + var texture = DownloadHandlerTexture.GetContent(uwr); - var hasError = uwr.error != null && uwr.error != ""; - - if (hasError) // (uwr.result != UnityWebRequest.Result.Success) + lock(_loadedTextures) { - Debug.Log(uwr.error); - } - else - { - var texture = DownloadHandlerTexture.GetContent(uwr); - if (_loadedTextures.ContainsKey(url)) { - Logger.LogVerbose($"Already loaded image at path: {url}"); + Logger.LogVerbose($"Already loaded image {index}:{url}"); Destroy(texture); texture = _loadedTextures[url]; } @@ -416,7 +441,7 @@ namespace NewHorizons.Utility _loadedTextures.Add(url, texture); } - imageLoadedEvent.Invoke(texture, index); + imageLoadedEvent?.Invoke(texture, index); } } }