From 3fbe75239541ce23e1c31a6a22bdd2c9a27b166b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter-Mikha=C3=ABl=20Richard?= Date: Mon, 30 Jun 2025 18:47:18 +0200 Subject: [PATCH 01/11] Added security to ScatterBuilder.cs Prevent prop positioning loop going infinite when there are too much constraint on height --- NewHorizons/Builder/Props/ScatterBuilder.cs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/NewHorizons/Builder/Props/ScatterBuilder.cs b/NewHorizons/Builder/Props/ScatterBuilder.cs index 862f0629..9f08d403 100644 --- a/NewHorizons/Builder/Props/ScatterBuilder.cs +++ b/NewHorizons/Builder/Props/ScatterBuilder.cs @@ -80,6 +80,15 @@ namespace NewHorizons.Builder.Props }; var scatterPrefab = DetailBuilder.Make(go, sector, mod, prefab, detailInfo); + bool reasonableHeightConstraints = true; + if (!propInfo.preventOverlap && (heightMapTexture != null) && (propInfo.minHeight != null || propInfo.maxHeight != null)) // If caution is relevant + { + var maxHeight = (propInfo.minHeight != null ? Math.Min(propInfo.maxHeight, heightMap.maxHeight) : heightMap.maxHeight); + var minHeight = (propInfo.minHeight != null ? Math.Max(propInfo.minHeight, heightMap.minHeight) : heightMap.minHeight); + if ((maxHeight - minHeight) / (heightMap.maxHeight - heightMap.minHeight) < 0.001) // If height roll has less than 0.1% chance of being valid + reasonableHeightConstraints = false; // Ignore propInfo.min/maxHeight to prevent infinite rerolls + // That way, even if often not valid, it still won't loop much more than propInfo.count * 1000 per prop + } for (int i = 0; i < propInfo.count; i++) { Vector3 point; @@ -113,7 +122,7 @@ namespace NewHorizons.Builder.Props float relativeHeight = heightMapTexture.GetPixel((int)sampleX, (int)sampleY).r; height = (relativeHeight * (heightMap.maxHeight - heightMap.minHeight) + heightMap.minHeight); - if ((propInfo.minHeight != null && height < propInfo.minHeight) || (propInfo.maxHeight != null && height > propInfo.maxHeight)) + if (reasonableHeightConstraints && ((propInfo.minHeight != null && height < propInfo.minHeight) || (propInfo.maxHeight != null && height > propInfo.maxHeight))) { // Try this point again i--; From 5391e4a5555c451c27ce94182fdce82c13d4f85b Mon Sep 17 00:00:00 2001 From: coderCleric <56094451+coderCleric@users.noreply.github.com> Date: Tue, 29 Jul 2025 18:15:36 -0600 Subject: [PATCH 02/11] Add Nomai Text Printer to the docs --- docs/src/content/docs/guides/nomai-text.md | 4 +++- docs/src/content/docs/start-here/helpful-resources.md | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/src/content/docs/guides/nomai-text.md b/docs/src/content/docs/guides/nomai-text.md index 959aeeb4..df6fb82b 100644 --- a/docs/src/content/docs/guides/nomai-text.md +++ b/docs/src/content/docs/guides/nomai-text.md @@ -23,4 +23,6 @@ To unlock ship logs after reading each text block, add a `` n In your planet config, you must define where the Nomai text is positioned. See [the translator text json schema](/schemas/body-schema/defs/translatortextinfo/) for more info. -You can input a `seed` for a wall of text which will randomly generate the position of each arc. To test out different combinations, just keep incrementing the number and then hit "Reload Configs" from the pause menu with debug mode on. This seed ensures the same positioning each time the mod is played. Alternatively, you can use `arcInfo` to set the position and rotation of all text arcs, as well as determining their types (adult, teenager, child, or Stranger). The various age stages make the text look messier, while Stranger allows you to make a translatable version of the DLC text. \ No newline at end of file +You can input a `seed` for a wall of text which will randomly generate the position of each arc. To test out different combinations, just keep incrementing the number and then hit "Reload Configs" from the pause menu with debug mode on. This seed ensures the same positioning each time the mod is played. Alternatively, you can use `arcInfo` to set the position and rotation of all text arcs, as well as determining their types (adult, teenager, child, or Stranger). The various age stages make the text look messier, while Stranger allows you to make a translatable version of the DLC text. + +If you decide to arrange text manually in your mod, the [Unity Explorer](https://outerwildsmods.com/mods/unityexplorer/) and [Nomai Text Printer](https://github.com/coderCleric/NomaiTextPrinter) mods can make that much more convenient. \ No newline at end of file diff --git a/docs/src/content/docs/start-here/helpful-resources.md b/docs/src/content/docs/start-here/helpful-resources.md index 0ca13791..4ba3f2c8 100644 --- a/docs/src/content/docs/start-here/helpful-resources.md +++ b/docs/src/content/docs/start-here/helpful-resources.md @@ -56,6 +56,7 @@ These mods are useful when developing your addon - [Save Editor](https://outerwildsmods.com/mods/saveeditor) - Useful when creating a custom [ship log](/ship-log), can be used to reveal all custom facts so you can see them in the ship's computer. - [Time Saver](https://outerwildsmods.com/mods/timesaver/) - Lets you skip some repeated cutscenes and get into the game faster. - [The Examples Mod](https://github.com/Outer-Wilds-New-Horizons/nh-examples) - A mod that contains examples of how to use New Horizons features. +- [Nomai Text Printer](https://github.com/coderCleric/NomaiTextPrinter) - Useful for saving text changes (such as moving arcs with Unity Explorer) to your json files. ## Helpful Tools From f7c9685457840db9f809bd8ba16ba9963ece2d18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter-Mikha=C3=ABl=20Richard?= Date: Thu, 31 Jul 2025 06:21:48 +0200 Subject: [PATCH 03/11] Update ScatterBuilder.cs --- NewHorizons/Builder/Props/ScatterBuilder.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NewHorizons/Builder/Props/ScatterBuilder.cs b/NewHorizons/Builder/Props/ScatterBuilder.cs index 9f08d403..b47d6ab0 100644 --- a/NewHorizons/Builder/Props/ScatterBuilder.cs +++ b/NewHorizons/Builder/Props/ScatterBuilder.cs @@ -83,7 +83,7 @@ namespace NewHorizons.Builder.Props bool reasonableHeightConstraints = true; if (!propInfo.preventOverlap && (heightMapTexture != null) && (propInfo.minHeight != null || propInfo.maxHeight != null)) // If caution is relevant { - var maxHeight = (propInfo.minHeight != null ? Math.Min(propInfo.maxHeight, heightMap.maxHeight) : heightMap.maxHeight); + var maxHeight = (propInfo.maxHeight != null ? Math.Min(propInfo.maxHeight, heightMap.maxHeight) : heightMap.maxHeight); var minHeight = (propInfo.minHeight != null ? Math.Max(propInfo.minHeight, heightMap.minHeight) : heightMap.minHeight); if ((maxHeight - minHeight) / (heightMap.maxHeight - heightMap.minHeight) < 0.001) // If height roll has less than 0.1% chance of being valid reasonableHeightConstraints = false; // Ignore propInfo.min/maxHeight to prevent infinite rerolls From 38ae757f58ddc5562ef9dc9782b36994995ff918 Mon Sep 17 00:00:00 2001 From: Noah Pilarski Date: Mon, 4 Aug 2025 19:00:57 -0400 Subject: [PATCH 04/11] add log --- NewHorizons/Builder/Props/ScatterBuilder.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/NewHorizons/Builder/Props/ScatterBuilder.cs b/NewHorizons/Builder/Props/ScatterBuilder.cs index b47d6ab0..ee33e2f9 100644 --- a/NewHorizons/Builder/Props/ScatterBuilder.cs +++ b/NewHorizons/Builder/Props/ScatterBuilder.cs @@ -86,7 +86,10 @@ namespace NewHorizons.Builder.Props var maxHeight = (propInfo.maxHeight != null ? Math.Min(propInfo.maxHeight, heightMap.maxHeight) : heightMap.maxHeight); var minHeight = (propInfo.minHeight != null ? Math.Max(propInfo.minHeight, heightMap.minHeight) : heightMap.minHeight); if ((maxHeight - minHeight) / (heightMap.maxHeight - heightMap.minHeight) < 0.001) // If height roll has less than 0.1% chance of being valid + { + NHLogger.LogError($"Ignoring minHeight/maxHeight for scatter of [{scatterPrefab.name}] to prevent infinite rerolls."); reasonableHeightConstraints = false; // Ignore propInfo.min/maxHeight to prevent infinite rerolls + } // That way, even if often not valid, it still won't loop much more than propInfo.count * 1000 per prop } for (int i = 0; i < propInfo.count; i++) From 201a310e2bd6291bb735e95e6a0b2a1626b42670 Mon Sep 17 00:00:00 2001 From: Noah Pilarski Date: Mon, 4 Aug 2025 19:02:27 -0400 Subject: [PATCH 05/11] extend a little --- NewHorizons/Builder/Props/ScatterBuilder.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NewHorizons/Builder/Props/ScatterBuilder.cs b/NewHorizons/Builder/Props/ScatterBuilder.cs index ee33e2f9..0df720d6 100644 --- a/NewHorizons/Builder/Props/ScatterBuilder.cs +++ b/NewHorizons/Builder/Props/ScatterBuilder.cs @@ -87,7 +87,7 @@ namespace NewHorizons.Builder.Props var minHeight = (propInfo.minHeight != null ? Math.Max(propInfo.minHeight, heightMap.minHeight) : heightMap.minHeight); if ((maxHeight - minHeight) / (heightMap.maxHeight - heightMap.minHeight) < 0.001) // If height roll has less than 0.1% chance of being valid { - NHLogger.LogError($"Ignoring minHeight/maxHeight for scatter of [{scatterPrefab.name}] to prevent infinite rerolls."); + NHLogger.LogError($"Ignoring minHeight/maxHeight for scatter of [{scatterPrefab.name}] to prevent infinite rerolls from too much constraint on height."); reasonableHeightConstraints = false; // Ignore propInfo.min/maxHeight to prevent infinite rerolls } // That way, even if often not valid, it still won't loop much more than propInfo.count * 1000 per prop From 8089de358a992d3e4095eba6db5b3cda7ba929ce Mon Sep 17 00:00:00 2001 From: xen-42 <22628069+xen-42@users.noreply.github.com> Date: Mon, 4 Aug 2025 21:12:00 -0400 Subject: [PATCH 06/11] Just expect 32 signals max instead of constantly refreshing the array --- NewHorizons/Builder/Props/Audio/SignalBuilder.cs | 3 --- NewHorizons/Patches/SignalPatches/SignalscopePatches.cs | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/NewHorizons/Builder/Props/Audio/SignalBuilder.cs b/NewHorizons/Builder/Props/Audio/SignalBuilder.cs index e3ba5aed..e0167b41 100644 --- a/NewHorizons/Builder/Props/Audio/SignalBuilder.cs +++ b/NewHorizons/Builder/Props/Audio/SignalBuilder.cs @@ -113,9 +113,6 @@ namespace NewHorizons.Builder.Props.Audio NumberOfFrequencies = EnumUtils.GetValues().Length; - // This stuff happens after the signalscope is Awake so we have to change the number of frequencies now - GameObject.FindObjectOfType()._strongestSignals = new AudioSignal[NumberOfFrequencies + 1]; - return freq; } diff --git a/NewHorizons/Patches/SignalPatches/SignalscopePatches.cs b/NewHorizons/Patches/SignalPatches/SignalscopePatches.cs index 2b91dc72..97760b56 100644 --- a/NewHorizons/Patches/SignalPatches/SignalscopePatches.cs +++ b/NewHorizons/Patches/SignalPatches/SignalscopePatches.cs @@ -11,7 +11,7 @@ namespace NewHorizons.Patches.SignalPatches [HarmonyPatch(nameof(Signalscope.Awake))] public static void Signalscope_Awake(Signalscope __instance) { - __instance._strongestSignals = new AudioSignal[8]; + __instance._strongestSignals = new AudioSignal[32]; } [HarmonyPrefix] From 831a94cdbc45113d26cede9605da8f3e1836d1b3 Mon Sep 17 00:00:00 2001 From: xen-42 <22628069+xen-42@users.noreply.github.com> Date: Mon, 4 Aug 2025 21:44:18 -0400 Subject: [PATCH 07/11] Fixed a floating point rounding error --- NewHorizons/Builder/Props/Audio/SignalBuilder.cs | 4 ++-- NewHorizons/Patches/SignalPatches/AudioSignalPatches.cs | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/NewHorizons/Builder/Props/Audio/SignalBuilder.cs b/NewHorizons/Builder/Props/Audio/SignalBuilder.cs index e0167b41..b3ef42bb 100644 --- a/NewHorizons/Builder/Props/Audio/SignalBuilder.cs +++ b/NewHorizons/Builder/Props/Audio/SignalBuilder.cs @@ -100,8 +100,6 @@ namespace NewHorizons.Builder.Props.Audio var freq = CollectionUtilities.KeyByValue(_customFrequencyNames, str); if (freq != default) return freq; - NHLogger.Log($"Registering new frequency name [{str}]"); - if (NumberOfFrequencies == 31) { NHLogger.LogWarning($"Can't store any more frequencies, skipping [{str}]"); @@ -111,6 +109,8 @@ namespace NewHorizons.Builder.Props.Audio freq = EnumUtilities.Create(str); _customFrequencyNames.Add(freq, str); + NHLogger.Log($"Registered new frequency name [{str}] with value [{(int)freq}] and index [{AudioSignal.FrequencyToIndex(freq)}]"); + NumberOfFrequencies = EnumUtils.GetValues().Length; return freq; diff --git a/NewHorizons/Patches/SignalPatches/AudioSignalPatches.cs b/NewHorizons/Patches/SignalPatches/AudioSignalPatches.cs index a886b827..e9ce164b 100644 --- a/NewHorizons/Patches/SignalPatches/AudioSignalPatches.cs +++ b/NewHorizons/Patches/SignalPatches/AudioSignalPatches.cs @@ -45,7 +45,9 @@ namespace NewHorizons.Patches.SignalPatches SignalFrequency.HideAndSeek => 5, SignalFrequency.Radio => 6, SignalFrequency.Statue => 7, - _ => (int)(Mathf.Log((float)frequency) / Mathf.Log(2f)),// Frequencies are in powers of 2 + // Can't cast to int because floating point error, it was doing 12.9999999 -> 12 + // Frequencies are in powers of 2 + _ => Mathf.RoundToInt(Mathf.Log((float)frequency) / Mathf.Log(2f)), }; return false; } From 8af363f8f806d91433f2715f53f447f8f1fd8768 Mon Sep 17 00:00:00 2001 From: xen-42 <22628069+xen-42@users.noreply.github.com> Date: Mon, 4 Aug 2025 21:44:43 -0400 Subject: [PATCH 08/11] Update manifest.json --- NewHorizons/manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NewHorizons/manifest.json b/NewHorizons/manifest.json index 75cd8f6b..b617161e 100644 --- a/NewHorizons/manifest.json +++ b/NewHorizons/manifest.json @@ -4,7 +4,7 @@ "author": "xen, Bwc9876, JohnCorby, MegaPiggy, and friends", "name": "New Horizons", "uniqueName": "xen.NewHorizons", - "version": "1.28.5", + "version": "1.28.6", "owmlVersion": "2.12.1", "dependencies": [ "JohnCorby.VanillaFix", "xen.CommonCameraUtility", "dgarro.CustomShipLogModes" ], "conflicts": [ "PacificEngine.OW_CommonResources" ], From 696bce2f3a719f9f23a7b15357672378d5793ac9 Mon Sep 17 00:00:00 2001 From: xen-42 <22628069+xen-42@users.noreply.github.com> Date: Mon, 4 Aug 2025 21:46:33 -0400 Subject: [PATCH 09/11] Revert "Add a security check to ScatterBuilder (#1109)" This reverts commit ced49c6606e88fb7a40b8cecb8fb7c753cd24214, reversing changes made to 4c3d92a4a3f90c981420eacac1d048a0f44da303. --- NewHorizons/Builder/Props/ScatterBuilder.cs | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/NewHorizons/Builder/Props/ScatterBuilder.cs b/NewHorizons/Builder/Props/ScatterBuilder.cs index 0df720d6..862f0629 100644 --- a/NewHorizons/Builder/Props/ScatterBuilder.cs +++ b/NewHorizons/Builder/Props/ScatterBuilder.cs @@ -80,18 +80,6 @@ namespace NewHorizons.Builder.Props }; var scatterPrefab = DetailBuilder.Make(go, sector, mod, prefab, detailInfo); - bool reasonableHeightConstraints = true; - if (!propInfo.preventOverlap && (heightMapTexture != null) && (propInfo.minHeight != null || propInfo.maxHeight != null)) // If caution is relevant - { - var maxHeight = (propInfo.maxHeight != null ? Math.Min(propInfo.maxHeight, heightMap.maxHeight) : heightMap.maxHeight); - var minHeight = (propInfo.minHeight != null ? Math.Max(propInfo.minHeight, heightMap.minHeight) : heightMap.minHeight); - if ((maxHeight - minHeight) / (heightMap.maxHeight - heightMap.minHeight) < 0.001) // If height roll has less than 0.1% chance of being valid - { - NHLogger.LogError($"Ignoring minHeight/maxHeight for scatter of [{scatterPrefab.name}] to prevent infinite rerolls from too much constraint on height."); - reasonableHeightConstraints = false; // Ignore propInfo.min/maxHeight to prevent infinite rerolls - } - // That way, even if often not valid, it still won't loop much more than propInfo.count * 1000 per prop - } for (int i = 0; i < propInfo.count; i++) { Vector3 point; @@ -125,7 +113,7 @@ namespace NewHorizons.Builder.Props float relativeHeight = heightMapTexture.GetPixel((int)sampleX, (int)sampleY).r; height = (relativeHeight * (heightMap.maxHeight - heightMap.minHeight) + heightMap.minHeight); - if (reasonableHeightConstraints && ((propInfo.minHeight != null && height < propInfo.minHeight) || (propInfo.maxHeight != null && height > propInfo.maxHeight))) + if ((propInfo.minHeight != null && height < propInfo.minHeight) || (propInfo.maxHeight != null && height > propInfo.maxHeight)) { // Try this point again i--; From 94ff93d597151d17976e06907b47eab6e31b1d11 Mon Sep 17 00:00:00 2001 From: xen-42 <22628069+xen-42@users.noreply.github.com> Date: Mon, 4 Aug 2025 21:47:18 -0400 Subject: [PATCH 10/11] Reapply "Add a security check to ScatterBuilder (#1109)" This reverts commit 696bce2f3a719f9f23a7b15357672378d5793ac9. --- NewHorizons/Builder/Props/ScatterBuilder.cs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/NewHorizons/Builder/Props/ScatterBuilder.cs b/NewHorizons/Builder/Props/ScatterBuilder.cs index 862f0629..0df720d6 100644 --- a/NewHorizons/Builder/Props/ScatterBuilder.cs +++ b/NewHorizons/Builder/Props/ScatterBuilder.cs @@ -80,6 +80,18 @@ namespace NewHorizons.Builder.Props }; var scatterPrefab = DetailBuilder.Make(go, sector, mod, prefab, detailInfo); + bool reasonableHeightConstraints = true; + if (!propInfo.preventOverlap && (heightMapTexture != null) && (propInfo.minHeight != null || propInfo.maxHeight != null)) // If caution is relevant + { + var maxHeight = (propInfo.maxHeight != null ? Math.Min(propInfo.maxHeight, heightMap.maxHeight) : heightMap.maxHeight); + var minHeight = (propInfo.minHeight != null ? Math.Max(propInfo.minHeight, heightMap.minHeight) : heightMap.minHeight); + if ((maxHeight - minHeight) / (heightMap.maxHeight - heightMap.minHeight) < 0.001) // If height roll has less than 0.1% chance of being valid + { + NHLogger.LogError($"Ignoring minHeight/maxHeight for scatter of [{scatterPrefab.name}] to prevent infinite rerolls from too much constraint on height."); + reasonableHeightConstraints = false; // Ignore propInfo.min/maxHeight to prevent infinite rerolls + } + // That way, even if often not valid, it still won't loop much more than propInfo.count * 1000 per prop + } for (int i = 0; i < propInfo.count; i++) { Vector3 point; @@ -113,7 +125,7 @@ namespace NewHorizons.Builder.Props float relativeHeight = heightMapTexture.GetPixel((int)sampleX, (int)sampleY).r; height = (relativeHeight * (heightMap.maxHeight - heightMap.minHeight) + heightMap.minHeight); - if ((propInfo.minHeight != null && height < propInfo.minHeight) || (propInfo.maxHeight != null && height > propInfo.maxHeight)) + if (reasonableHeightConstraints && ((propInfo.minHeight != null && height < propInfo.minHeight) || (propInfo.maxHeight != null && height > propInfo.maxHeight))) { // Try this point again i--; From 0b419b66c4d8c56ad1197505920bf0043fe25941 Mon Sep 17 00:00:00 2001 From: xen-42 <22628069+xen-42@users.noreply.github.com> Date: Mon, 4 Aug 2025 21:50:11 -0400 Subject: [PATCH 11/11] Revert "Add a security check to ScatterBuilder (#1109)" This reverts commit ced49c6606e88fb7a40b8cecb8fb7c753cd24214, reversing changes made to 4c3d92a4a3f90c981420eacac1d048a0f44da303. --- NewHorizons/Builder/Props/ScatterBuilder.cs | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/NewHorizons/Builder/Props/ScatterBuilder.cs b/NewHorizons/Builder/Props/ScatterBuilder.cs index 0df720d6..862f0629 100644 --- a/NewHorizons/Builder/Props/ScatterBuilder.cs +++ b/NewHorizons/Builder/Props/ScatterBuilder.cs @@ -80,18 +80,6 @@ namespace NewHorizons.Builder.Props }; var scatterPrefab = DetailBuilder.Make(go, sector, mod, prefab, detailInfo); - bool reasonableHeightConstraints = true; - if (!propInfo.preventOverlap && (heightMapTexture != null) && (propInfo.minHeight != null || propInfo.maxHeight != null)) // If caution is relevant - { - var maxHeight = (propInfo.maxHeight != null ? Math.Min(propInfo.maxHeight, heightMap.maxHeight) : heightMap.maxHeight); - var minHeight = (propInfo.minHeight != null ? Math.Max(propInfo.minHeight, heightMap.minHeight) : heightMap.minHeight); - if ((maxHeight - minHeight) / (heightMap.maxHeight - heightMap.minHeight) < 0.001) // If height roll has less than 0.1% chance of being valid - { - NHLogger.LogError($"Ignoring minHeight/maxHeight for scatter of [{scatterPrefab.name}] to prevent infinite rerolls from too much constraint on height."); - reasonableHeightConstraints = false; // Ignore propInfo.min/maxHeight to prevent infinite rerolls - } - // That way, even if often not valid, it still won't loop much more than propInfo.count * 1000 per prop - } for (int i = 0; i < propInfo.count; i++) { Vector3 point; @@ -125,7 +113,7 @@ namespace NewHorizons.Builder.Props float relativeHeight = heightMapTexture.GetPixel((int)sampleX, (int)sampleY).r; height = (relativeHeight * (heightMap.maxHeight - heightMap.minHeight) + heightMap.minHeight); - if (reasonableHeightConstraints && ((propInfo.minHeight != null && height < propInfo.minHeight) || (propInfo.maxHeight != null && height > propInfo.maxHeight))) + if ((propInfo.minHeight != null && height < propInfo.minHeight) || (propInfo.maxHeight != null && height > propInfo.maxHeight)) { // Try this point again i--;