diff --git a/NewHorizons/Assets/translations/english.json b/NewHorizons/Assets/translations/english.json
index 48df51ee..6eed88c3 100644
--- a/NewHorizons/Assets/translations/english.json
+++ b/NewHorizons/Assets/translations/english.json
@@ -22,7 +22,8 @@
"DEBUG_PLACE_TEXT": "Place Nomai Text",
"DEBUG_UNDO": "Undo",
"DEBUG_REDO": "Redo",
- "Vessel": "Vessel"
+ "Vessel": "Vessel",
+ "DLC_REQUIRED": "WARNING\n\nYou have addons (like {0}) installed which require the DLC but it is not enabled.\n\nYour mods may not function as intended."
},
"OtherDictionary": {
"NOMAI_SHUTTLE_COMPUTER": "The shuttle]]> is currently resting at {0}]]>."
diff --git a/NewHorizons/Assets/translations/french.json b/NewHorizons/Assets/translations/french.json
index c268d415..ed7d553b 100644
--- a/NewHorizons/Assets/translations/french.json
+++ b/NewHorizons/Assets/translations/french.json
@@ -17,7 +17,8 @@
"RICH_PRESENCE_WARPING": "En route vers {0}.",
"OUTDATED_VERSION_WARNING": "AVERTISSEMENT\n\nNew Horizons fonctionne seulement sur la version {0} ou plus récente. Vous êtes sur la version {1}.\n\nVeuillez mettre à jour votre jeu ou désinstaller NH.",
"JSON_FAILED_TO_LOAD": "Fichier(s) invalide(s): {0}",
- "Vessel": "Vaisseau"
+ "Vessel": "Vaisseau",
+ "DLC_REQUIRED": "AVERTISSEMENT\n\nVous avez installé des addons (par exemple, {0}) qui nécessitent le DLC mais il n'est pas activé.\n\nVos mods peuvent ne pas fonctionner."
},
"AchievementTranslations": {
"NH_EATEN_OUTSIDE_BRAMBLE": {
diff --git a/NewHorizons/External/Configs/AddonConfig.cs b/NewHorizons/External/Configs/AddonConfig.cs
index 54d8cf0e..cfcc731b 100644
--- a/NewHorizons/External/Configs/AddonConfig.cs
+++ b/NewHorizons/External/Configs/AddonConfig.cs
@@ -31,5 +31,17 @@ namespace NewHorizons.External.Configs
/// If popupMessage is set, should it repeat every time the game starts or only once
///
public bool repeatPopup;
+
+ ///
+ /// These asset bundles will be loaded on the title screen and stay loaded. Will improve initial load time at the cost of increased memory use.
+ /// The path is the relative directory of the asset bundle in the mod folder.
+ ///
+ public string[] preloadAssetBundles;
+
+ ///
+ /// The path to the addons subtitle for the main menu.
+ /// Defaults to "subtitle.png".
+ ///
+ public string subtitlePath = "subtitle.png";
}
}
diff --git a/NewHorizons/External/NewHorizonBody.cs b/NewHorizons/External/NewHorizonBody.cs
index fa80de75..590c5b91 100644
--- a/NewHorizons/External/NewHorizonBody.cs
+++ b/NewHorizons/External/NewHorizonBody.cs
@@ -26,6 +26,15 @@ namespace NewHorizons.External
public GameObject Object;
+ public bool RequiresDLC()
+ {
+ var detailPaths = Config.Props.details.Select(x => x.path);
+ return Config.Cloak != null
+ || Config.Props?.rafts != null
+ || Config.Props?.slideShows != null
+ || detailPaths.Any(x => x.StartsWith("Ringworld") || x.StartsWith("Dreamworld"));
+ }
+
#region Cache
public void LoadCache()
{
diff --git a/NewHorizons/Handlers/PlayerSpawnHandler.cs b/NewHorizons/Handlers/PlayerSpawnHandler.cs
index 2b32cd69..22380665 100644
--- a/NewHorizons/Handlers/PlayerSpawnHandler.cs
+++ b/NewHorizons/Handlers/PlayerSpawnHandler.cs
@@ -2,6 +2,7 @@ using NewHorizons.Builder.General;
using NewHorizons.Utility;
using NewHorizons.Utility.OWML;
using System.Collections;
+using System.Linq;
using UnityEngine;
namespace NewHorizons.Handlers
@@ -76,7 +77,44 @@ namespace NewHorizons.Handlers
pos += SpawnPointBuilder.ShipSpawn.transform.TransformDirection(SpawnPointBuilder.ShipSpawnOffset);
}
+ // #748 Before moving the ship, reset all its landing pad sensors
+ // Else they might think its still touching TH
+ // Doing this before moving the ship so that if they start contacting in the new spawn point then that gets preserved
+ foreach (var landingPadSensor in ship.GetComponentsInChildren())
+ {
+ landingPadSensor._contactBody = null;
+ }
+
SpawnBody(ship.GetAttachedOWRigidbody(), SpawnPointBuilder.ShipSpawn, pos);
+
+ // Bug affecting mods with massive stars (8600m+ radius)
+ // TH has an orbital radius of 8600m, meaning the base game ship spawn ends up inside the star
+ // This places the ship into the star's fluid volumes (destruction volume and atmosphere)
+ // When the ship is teleported out, it doesn't update it's detected fluid volumes and gets affected by drag forever
+ // Can fix by turning the volumes off and on again
+ // Done after re-positioning else it'd just get re-added to the old volumes
+
+ // .ToList is because it makes a copy of the array, else it errors:
+ // "InvalidOperationException: Collection was modified; enumeration operation may not execute."
+ foreach (var volume in ship.GetComponentInChildren()._activeVolumes.ToList())
+ {
+ if (volume.gameObject.activeInHierarchy)
+ {
+ volume.gameObject.SetActive(false);
+ volume.gameObject.SetActive(true);
+ }
+ }
+ // Also applies to force volumes
+ foreach (var volume in ship.GetComponentInChildren()._activeVolumes.ToList())
+ {
+ if (volume.gameObject.activeInHierarchy)
+ {
+ volume.gameObject.SetActive(false);
+ volume.gameObject.SetActive(true);
+ }
+ }
+ // For some reason none of this seems to apply to the Player.
+ // If somebody ever makes a sound volume thats somehow always applying to the player tho then itd probably be this
}
}
else if (Main.Instance.CurrentStarSystem != "SolarSystem" && !Main.Instance.IsWarpingFromShip)
diff --git a/NewHorizons/Handlers/SubtitlesHandler.cs b/NewHorizons/Handlers/SubtitlesHandler.cs
index fc4bfe94..de283b54 100644
--- a/NewHorizons/Handlers/SubtitlesHandler.cs
+++ b/NewHorizons/Handlers/SubtitlesHandler.cs
@@ -61,9 +61,17 @@ namespace NewHorizons.Handlers
private void AddSubtitles()
{
- foreach (var mod in Main.MountedAddons.Where(mod => File.Exists($"{mod.ModHelper.Manifest.ModFolderPath}subtitle.png")))
+ foreach (var mod in Main.MountedAddons)
{
- AddSubtitle(mod, "subtitle.png");
+ if (Main.AddonConfigs.TryGetValue(mod, out var addonConfig) && File.Exists(Path.Combine(mod.ModHelper.Manifest.ModFolderPath, addonConfig.subtitlePath)))
+ {
+ AddSubtitle(mod, addonConfig.subtitlePath);
+ }
+ // Else default to subtitle.png
+ else if (File.Exists(Path.Combine(mod.ModHelper.Manifest.ModFolderPath, "subtitle.png")))
+ {
+ AddSubtitle(mod, "subtitle.png");
+ }
}
}
diff --git a/NewHorizons/Main.cs b/NewHorizons/Main.cs
index 5d438e9d..ee07514f 100644
--- a/NewHorizons/Main.cs
+++ b/NewHorizons/Main.cs
@@ -50,9 +50,10 @@ namespace NewHorizons
private static bool _wasConfigured = false;
private static string _defaultSystemOverride;
- public static Dictionary SystemDict = new Dictionary();
- public static Dictionary> BodyDict = new Dictionary>();
- public static List MountedAddons = new List();
+ public static Dictionary SystemDict = new();
+ public static Dictionary> BodyDict = new();
+ public static List MountedAddons = new();
+ public static Dictionary AddonConfigs = new();
public static float SecondsElapsedInLoop = -1;
@@ -99,6 +100,8 @@ namespace NewHorizons
public bool PlayerSpawned { get; set; }
public bool ForceClearCaches { get; set; } // for reloading configs
+ public bool FlagDLCRequired { get; set; }
+
public ShipWarpController ShipWarpController { get; private set; }
// API events
@@ -690,6 +693,14 @@ namespace NewHorizons
var relativeDirectory = file.Replace(folder, "");
var body = LoadConfig(mod, relativeDirectory);
+ // Only bother checking if they need the DLC if they don't have it
+ if (!HasDLC && !FlagDLCRequired && body.RequiresDLC())
+ {
+ FlagDLCRequired = true;
+ var popupText = TranslationHandler.GetTranslation("DLC_REQUIRED", TranslationHandler.TextType.UI).Replace("{0}", mod.ModHelper.Manifest.Name);
+ MenuHandler.RegisterOneTimePopup(this, popupText, true);
+ }
+
if (body != null)
{
// Wanna track the spawn point of each system
@@ -737,6 +748,15 @@ namespace NewHorizons
{
MenuHandler.RegisterOneTimePopup(mod, TranslationHandler.GetTranslation(addonConfig.popupMessage, TranslationHandler.TextType.UI), addonConfig.repeatPopup);
}
+ if (addonConfig.preloadAssetBundles != null)
+ {
+ foreach (var bundle in addonConfig.preloadAssetBundles)
+ {
+ AssetBundleUtilities.PreloadBundle(bundle, mod);
+ }
+ }
+
+ AddonConfigs[mod] = addonConfig;
}
private void LoadTranslations(string folder, IModBehaviour mod)
@@ -921,8 +941,15 @@ namespace NewHorizons
{
CurrentStarSystem = _defaultSystemOverride;
- // Sometimes the override will not support spawning regularly, so always warp in
- IsWarpingFromShip = true;
+ if (BodyDict.TryGetValue(_defaultSystemOverride, out var bodies) && bodies.Any(x => x.Config?.Spawn?.shipSpawn != null))
+ {
+ // #738 - Sometimes the override will not support spawning regularly, so always warp in if possible
+ IsWarpingFromShip = true;
+ }
+ else
+ {
+ IsWarpingFromShip = false;
+ }
}
else
{
diff --git a/NewHorizons/NewHorizonsApi.cs b/NewHorizons/NewHorizonsApi.cs
index e5507abc..a96673d5 100644
--- a/NewHorizons/NewHorizonsApi.cs
+++ b/NewHorizons/NewHorizonsApi.cs
@@ -28,7 +28,6 @@ using static NewHorizons.External.Modules.ShipLogModule;
namespace NewHorizons
{
-
public class NewHorizonsApi : INewHorizons
{
[Obsolete("Create(Dictionary config) is deprecated, please use LoadConfigs(IModBehaviour mod) instead")]
diff --git a/NewHorizons/Patches/EyeScenePatches/SubmitActionLoadScenePatches.cs b/NewHorizons/Patches/EyeScenePatches/SubmitActionLoadScenePatches.cs
index 9feba169..891f439c 100644
--- a/NewHorizons/Patches/EyeScenePatches/SubmitActionLoadScenePatches.cs
+++ b/NewHorizons/Patches/EyeScenePatches/SubmitActionLoadScenePatches.cs
@@ -1,4 +1,5 @@
using HarmonyLib;
+using NewHorizons.Utility.Files;
using NewHorizons.Utility.OWML;
namespace NewHorizons.Patches.EyeScenePatches
@@ -6,10 +7,18 @@ namespace NewHorizons.Patches.EyeScenePatches
[HarmonyPatch(typeof(SubmitActionLoadScene))]
public static class SubmitActionLoadScenePatches
{
+ // To call the base method
+ [HarmonyReversePatch]
+ [HarmonyPatch(typeof(SubmitActionConfirm), nameof(SubmitActionConfirm.ConfirmSubmit))]
+ public static void SubmitActionConfirm_ConfirmSubmit(SubmitActionConfirm instance) { }
+
+
[HarmonyPrefix]
[HarmonyPatch(nameof(SubmitActionLoadScene.ConfirmSubmit))]
- public static void SubmitActionLoadScene_ConfirmSubmit(SubmitActionLoadScene __instance)
+ public static bool SubmitActionLoadScene_ConfirmSubmit(SubmitActionLoadScene __instance)
{
+ if (__instance._receivedSubmitAction) return false;
+
// Title screen can warp you to eye and cause problems.
if (__instance._sceneToLoad == SubmitActionLoadScene.LoadableScenes.EYE)
{
@@ -17,6 +26,44 @@ namespace NewHorizons.Patches.EyeScenePatches
Main.Instance.IsWarpingBackToEye = true;
__instance._sceneToLoad = SubmitActionLoadScene.LoadableScenes.GAME;
}
+
+ // modified from patched function
+ SubmitActionConfirm_ConfirmSubmit(__instance);
+ __instance._receivedSubmitAction = true;
+ Locator.GetMenuInputModule().DisableInputs();
+
+ Delay.RunWhen(() =>
+ {
+ // update text. just use 0%
+ __instance.ResetStringBuilder();
+ __instance._nowLoadingSB.Append(UITextLibrary.GetString(UITextType.LoadingMessage));
+ __instance._nowLoadingSB.Append(0.ToString("P0"));
+ __instance._loadingText.text = __instance._nowLoadingSB.ToString();
+
+ return AssetBundleUtilities.AreRequiredAssetsLoaded();
+ }, () =>
+ {
+ switch (__instance._sceneToLoad)
+ {
+ case SubmitActionLoadScene.LoadableScenes.GAME:
+ LoadManager.LoadSceneAsync(OWScene.SolarSystem, false, LoadManager.FadeType.ToBlack, 1f, false);
+ __instance.ResetStringBuilder();
+ __instance._waitingOnStreaming = true;
+ break;
+ case SubmitActionLoadScene.LoadableScenes.EYE:
+ LoadManager.LoadSceneAsync(OWScene.EyeOfTheUniverse, true, LoadManager.FadeType.ToBlack, 1f, false);
+ __instance.ResetStringBuilder();
+ break;
+ case SubmitActionLoadScene.LoadableScenes.TITLE:
+ LoadManager.LoadScene(OWScene.TitleScreen, LoadManager.FadeType.ToBlack, 2f, true);
+ break;
+ case SubmitActionLoadScene.LoadableScenes.CREDITS:
+ LoadManager.LoadScene(OWScene.Credits_Fast, LoadManager.FadeType.ToBlack, 1f, false);
+ break;
+ }
+ });
+
+ return false;
}
}
}
diff --git a/NewHorizons/Schemas/addon_manifest_schema.json b/NewHorizons/Schemas/addon_manifest_schema.json
index aada816a..dec9022f 100644
--- a/NewHorizons/Schemas/addon_manifest_schema.json
+++ b/NewHorizons/Schemas/addon_manifest_schema.json
@@ -27,6 +27,17 @@
"type": "boolean",
"description": "If popupMessage is set, should it repeat every time the game starts or only once"
},
+ "preloadAssetBundles": {
+ "type": "array",
+ "description": "These asset bundles will be loaded on the title screen and stay loaded. Will improve initial load time at the cost of increased memory use.\nThe path is the relative directory of the asset bundle in the mod folder.",
+ "items": {
+ "type": "string"
+ }
+ },
+ "subtitlePath": {
+ "type": "string",
+ "description": "The path to the addons subtitle for the main menu.\nDefaults to \"subtitle.png\"."
+ },
"$schema": {
"type": "string",
"description": "The schema to validate with"
diff --git a/NewHorizons/Utility/Files/AssetBundleUtilities.cs b/NewHorizons/Utility/Files/AssetBundleUtilities.cs
index 182826ba..104d7393 100644
--- a/NewHorizons/Utility/Files/AssetBundleUtilities.cs
+++ b/NewHorizons/Utility/Files/AssetBundleUtilities.cs
@@ -3,24 +3,57 @@ using OWML.Common;
using System;
using System.Collections.Generic;
using System.IO;
+using System.Linq;
using UnityEngine;
namespace NewHorizons.Utility.Files
{
public static class AssetBundleUtilities
{
- public static Dictionary AssetBundles = new Dictionary();
+ public static Dictionary AssetBundles = new();
+
+ private static readonly List _loadingBundles = new();
public static void ClearCache()
{
foreach (var pair in AssetBundles)
{
- if (pair.Value == null) NHLogger.LogError($"The asset bundle for {pair.Key} was null when trying to unload");
- else pair.Value.Unload(true);
+ if (!pair.Value.keepLoaded)
+ {
+ if (pair.Value.bundle == null)
+ {
+ NHLogger.LogError($"The asset bundle for {pair.Key} was null when trying to unload");
+ }
+ else
+ {
+ pair.Value.bundle.Unload(true);
+ }
+ }
+
}
- AssetBundles.Clear();
+ AssetBundles = AssetBundles.Where(x => x.Value.keepLoaded).ToDictionary(x => x.Key, x => x.Value);
}
+ public static void PreloadBundle(string assetBundleRelativeDir, IModBehaviour mod)
+ {
+ string key = Path.GetFileName(assetBundleRelativeDir);
+ var completePath = Path.Combine(mod.ModHelper.Manifest.ModFolderPath, assetBundleRelativeDir);
+ var request = AssetBundle.LoadFromFileAsync(completePath);
+ _loadingBundles.Add(request);
+ NHLogger.Log($"Preloading bundle {assetBundleRelativeDir} - {_loadingBundles.Count} left");
+ request.completed += _ =>
+ {
+ _loadingBundles.Remove(request);
+ NHLogger.Log($"Finshed preloading bundle {assetBundleRelativeDir} - {_loadingBundles.Count} left");
+ AssetBundles[key] = (request.assetBundle, true);
+ };
+ }
+
+ ///
+ /// are preloaded bundles done loading?
+ ///
+ public static bool AreRequiredAssetsLoaded() => _loadingBundles.Count == 0;
+
public static T Load(string assetBundleRelativeDir, string pathInBundle, IModBehaviour mod) where T : UnityEngine.Object
{
string key = Path.GetFileName(assetBundleRelativeDir);
@@ -32,7 +65,7 @@ namespace NewHorizons.Utility.Files
if (AssetBundles.ContainsKey(key))
{
- bundle = AssetBundles[key];
+ bundle = AssetBundles[key].bundle;
}
else
{
@@ -44,7 +77,7 @@ namespace NewHorizons.Utility.Files
return null;
}
- AssetBundles[key] = bundle;
+ AssetBundles[key] = (bundle, false);
}
obj = bundle.LoadAsset(pathInBundle);
@@ -124,4 +157,4 @@ namespace NewHorizons.Utility.Files
}
}
}
-}
+}
\ No newline at end of file
diff --git a/NewHorizons/manifest.json b/NewHorizons/manifest.json
index 30dd04ed..c75c1b1c 100644
--- a/NewHorizons/manifest.json
+++ b/NewHorizons/manifest.json
@@ -4,7 +4,7 @@
"author": "xen, Bwc9876, clay, MegaPiggy, John, Trifid, Hawkbar, Book",
"name": "New Horizons",
"uniqueName": "xen.NewHorizons",
- "version": "1.18.3",
+ "version": "1.18.4",
"owmlVersion": "2.9.8",
"dependencies": [ "JohnCorby.VanillaFix", "_nebula.MenuFramework", "xen.CommonCameraUtility", "dgarro.CustomShipLogModes" ],
"conflicts": [ "Raicuparta.QuantumSpaceBuddies", "PacificEngine.OW_CommonResources" ],