mirror of
https://github.com/Outer-Wilds-New-Horizons/new-horizons.git
synced 2025-12-11 20:15:44 +01:00
## Major features - Nomai warp pads! You can build transmitters (like the towers on Ash Twin) and receivers on other planets. Can also be used to just make permanent teleportation pads if the alignment window is set to 360 degrees. Receivers also take in position arguments for a Nomai computer which will display the departure and arrival times.
851 lines
36 KiB
C#
851 lines
36 KiB
C#
using HarmonyLib;
|
|
using NewHorizons.Builder.Atmosphere;
|
|
using NewHorizons.Builder.Body;
|
|
using NewHorizons.Builder.General;
|
|
using NewHorizons.Builder.Props;
|
|
using NewHorizons.Builder.Props.TranslatorText;
|
|
using NewHorizons.Components;
|
|
using NewHorizons.Components.Fixers;
|
|
using NewHorizons.Components.SizeControllers;
|
|
using NewHorizons.External;
|
|
using NewHorizons.External.Configs;
|
|
using NewHorizons.Handlers;
|
|
using NewHorizons.OtherMods.AchievementsPlus;
|
|
using NewHorizons.OtherMods.MenuFramework;
|
|
using NewHorizons.OtherMods.OWRichPresence;
|
|
using NewHorizons.OtherMods.VoiceActing;
|
|
using NewHorizons.Utility;
|
|
using NewHorizons.Utility.DebugMenu;
|
|
using NewHorizons.Utility.DebugUtilities;
|
|
using NewHorizons.Utility.OWMLUtilities;
|
|
using NewHorizons.Utility.OWUtilities;
|
|
using OWML.Common;
|
|
using OWML.ModHelper;
|
|
using OWML.Utils;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
using UnityEngine;
|
|
using UnityEngine.Events;
|
|
using UnityEngine.SceneManagement;
|
|
using Logger = NewHorizons.Utility.Logger;
|
|
|
|
namespace NewHorizons
|
|
{
|
|
|
|
public class Main : ModBehaviour
|
|
{
|
|
public static AssetBundle NHAssetBundle { get; private set; }
|
|
public static AssetBundle NHPrivateAssetBundle { get; private set; }
|
|
public static Main Instance { get; private set; }
|
|
|
|
// Settings
|
|
public static bool Debug { get; private set; }
|
|
public static bool VerboseLogs { get; private set; }
|
|
private static bool _useCustomTitleScreen;
|
|
private static bool _wasConfigured = false;
|
|
private static string _defaultSystemOverride;
|
|
|
|
public static Dictionary<string, NewHorizonsSystem> SystemDict = new Dictionary<string, NewHorizonsSystem>();
|
|
public static Dictionary<string, List<NewHorizonsBody>> BodyDict = new Dictionary<string, List<NewHorizonsBody>>();
|
|
public static List<IModBehaviour> MountedAddons = new List<IModBehaviour>();
|
|
|
|
public static float SecondsElapsedInLoop = -1;
|
|
|
|
public static bool IsSystemReady { get; private set; }
|
|
public static float FurthestOrbit { get; set; } = 50000f;
|
|
|
|
public string DefaultStarSystem => SystemDict.ContainsKey(_defaultSystemOverride) ? _defaultSystemOverride : _defaultStarSystem;
|
|
public string CurrentStarSystem => _currentStarSystem;
|
|
public bool TimeLoopEnabled => SystemDict[CurrentStarSystem]?.Config?.enableTimeLoop ?? true;
|
|
public bool IsWarpingFromShip { get; private set; } = false;
|
|
public bool IsWarpingFromVessel { get; private set; } = false;
|
|
public bool IsWarpingBackToEye { get; internal set; } = false;
|
|
public bool DidWarpFromVessel { get; private set; } = false;
|
|
public bool WearingSuit { get; private set; } = false;
|
|
|
|
public bool IsChangingStarSystem { get; private set; } = false;
|
|
|
|
public static bool HasWarpDrive { get; private set; } = false;
|
|
|
|
private string _defaultStarSystem = "SolarSystem";
|
|
internal string _currentStarSystem = "SolarSystem";
|
|
private bool _firstLoad = true;
|
|
private ShipWarpController _shipWarpController;
|
|
|
|
// API events
|
|
public class StarSystemEvent : UnityEvent<string> { }
|
|
public StarSystemEvent OnChangeStarSystem = new();
|
|
public StarSystemEvent OnStarSystemLoaded = new();
|
|
public StarSystemEvent OnPlanetLoaded = new();
|
|
|
|
public static bool HasDLC { get => EntitlementsManager.IsDlcOwned() == EntitlementsManager.AsyncOwnershipStatus.Owned; }
|
|
|
|
public override object GetApi()
|
|
{
|
|
return new NewHorizonsApi();
|
|
}
|
|
|
|
public override void Configure(IModConfig config)
|
|
{
|
|
Logger.LogVerbose("Settings changed");
|
|
|
|
var currentScene = SceneManager.GetActiveScene().name;
|
|
|
|
Debug = config.GetSettingsValue<bool>("Debug");
|
|
VerboseLogs = config.GetSettingsValue<bool>("Verbose Logs");
|
|
|
|
if (currentScene == "SolarSystem")
|
|
{
|
|
DebugReload.UpdateReloadButton();
|
|
DebugMenu.UpdatePauseMenuButton();
|
|
}
|
|
|
|
if (VerboseLogs) Logger.UpdateLogLevel(Logger.LogType.Verbose);
|
|
else if (Debug) Logger.UpdateLogLevel(Logger.LogType.Log);
|
|
else Logger.UpdateLogLevel(Logger.LogType.Error);
|
|
|
|
_defaultSystemOverride = config.GetSettingsValue<string>("Default System Override");
|
|
|
|
// Else it doesn't get set idk
|
|
if (currentScene == "TitleScreen" && SystemDict.ContainsKey(_defaultSystemOverride))
|
|
{
|
|
_currentStarSystem = _defaultSystemOverride;
|
|
}
|
|
|
|
var wasUsingCustomTitleScreen = _useCustomTitleScreen;
|
|
_useCustomTitleScreen = config.GetSettingsValue<bool>("Custom title screen");
|
|
// Reload the title screen if this was updated on it
|
|
// Don't reload if we haven't configured yet (called on game start)
|
|
if (wasUsingCustomTitleScreen != _useCustomTitleScreen && SceneManager.GetActiveScene().name == "TitleScreen" && _wasConfigured)
|
|
{
|
|
Logger.LogVerbose("Reloading");
|
|
SceneManager.LoadScene("TitleScreen", LoadSceneMode.Single);
|
|
}
|
|
|
|
_wasConfigured = true;
|
|
}
|
|
|
|
public void ResetConfigs(bool resetTranslation = true)
|
|
{
|
|
BodyDict.Clear();
|
|
SystemDict.Clear();
|
|
|
|
BodyDict["SolarSystem"] = new List<NewHorizonsBody>();
|
|
BodyDict["EyeOfTheUniverse"] = new List<NewHorizonsBody>(); // Keep this empty tho fr
|
|
SystemDict["SolarSystem"] = new NewHorizonsSystem("SolarSystem", new StarSystemConfig(), "", Instance)
|
|
{
|
|
Config =
|
|
{
|
|
destroyStockPlanets = false,
|
|
Vessel = new StarSystemConfig.VesselModule()
|
|
{
|
|
coords = new StarSystemConfig.NomaiCoordinates
|
|
{
|
|
x = new int[5]{ 0,3,2,1,5 },
|
|
y = new int[5]{ 4,5,3,2,1 },
|
|
z = new int[5]{ 4,1,2,5,0 }
|
|
}
|
|
}
|
|
}
|
|
};
|
|
SystemDict["EyeOfTheUniverse"] = new NewHorizonsSystem("EyeOfTheUniverse", new StarSystemConfig(), "", Instance)
|
|
{
|
|
Config =
|
|
{
|
|
destroyStockPlanets = false,
|
|
factRequiredForWarp = "OPC_EYE_COORDINATES_X1",
|
|
Vessel = new StarSystemConfig.VesselModule()
|
|
{
|
|
coords = new StarSystemConfig.NomaiCoordinates
|
|
{
|
|
x = new int[3] { 1, 5, 4 },
|
|
y = new int[4] { 3, 0, 1, 4 },
|
|
z = new int[6] { 1, 2, 3, 0, 5, 4 }
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
if (resetTranslation)
|
|
{
|
|
TranslationHandler.ClearTables();
|
|
TextTranslation.Get().SetLanguage(TextTranslation.Get().GetLanguage());
|
|
}
|
|
|
|
LoadTranslations(Path.Combine(Instance.ModHelper.Manifest.ModFolderPath, "Assets/"), this);
|
|
}
|
|
|
|
public void Awake()
|
|
{
|
|
Instance = this;
|
|
}
|
|
|
|
public void Start()
|
|
{
|
|
// Patches
|
|
Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly());
|
|
|
|
SceneManager.sceneLoaded += OnSceneLoaded;
|
|
SceneManager.sceneUnloaded += OnSceneUnloaded;
|
|
|
|
GlobalMessenger<DeathType>.AddListener("PlayerDeath", OnDeath);
|
|
|
|
GlobalMessenger.AddListener("WakeUp", OnWakeUp);
|
|
NHAssetBundle = ModHelper.Assets.LoadBundle("Assets/newhorizons_public");
|
|
NHPrivateAssetBundle = ModHelper.Assets.LoadBundle("Assets/newhorizons_private");
|
|
VesselWarpHandler.Initialize();
|
|
|
|
ResetConfigs(resetTranslation: false);
|
|
|
|
Logger.Log("Begin load of config files...");
|
|
|
|
try
|
|
{
|
|
LoadConfigs(this);
|
|
}
|
|
catch (Exception)
|
|
{
|
|
Logger.LogWarning("Couldn't find planets folder");
|
|
}
|
|
|
|
Delay.FireOnNextUpdate(() => OnSceneLoaded(SceneManager.GetActiveScene(), LoadSceneMode.Single));
|
|
Delay.FireOnNextUpdate(() => _firstLoad = false);
|
|
Instance.ModHelper.Menus.PauseMenu.OnInit += DebugReload.InitializePauseMenu;
|
|
|
|
MenuHandler.Init();
|
|
AchievementHandler.Init();
|
|
VoiceHandler.Init();
|
|
RichPresenceHandler.Init();
|
|
OnStarSystemLoaded.AddListener(RichPresenceHandler.OnStarSystemLoaded);
|
|
OnChangeStarSystem.AddListener(RichPresenceHandler.OnChangeStarSystem);
|
|
|
|
LoadAddonManifest("Assets/addon-manifest.json", this);
|
|
}
|
|
|
|
public void OnDestroy()
|
|
{
|
|
Logger.Log($"Destroying NewHorizons");
|
|
SceneManager.sceneLoaded -= OnSceneLoaded;
|
|
GlobalMessenger<DeathType>.RemoveListener("PlayerDeath", OnDeath);
|
|
GlobalMessenger.RemoveListener("WakeUp", new Callback(OnWakeUp));
|
|
|
|
AchievementHandler.OnDestroy();
|
|
}
|
|
|
|
private static void OnWakeUp()
|
|
{
|
|
IsSystemReady = true;
|
|
}
|
|
|
|
private void OnSceneUnloaded(Scene scene)
|
|
{
|
|
SearchUtilities.ClearCache();
|
|
ImageUtilities.ClearCache();
|
|
AudioUtilities.ClearCache();
|
|
AssetBundleUtilities.ClearCache();
|
|
EnumUtilities.ClearCache();
|
|
IsSystemReady = false;
|
|
}
|
|
|
|
private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
|
|
{
|
|
Logger.Log($"Scene Loaded: {scene.name} {mode} OWScene.{LoadManager.NameToScene(scene.name)}");
|
|
|
|
var isTitleScreen = scene.name == LoadManager.SceneToName(OWScene.TitleScreen);
|
|
var isSolarSystem = scene.name == LoadManager.SceneToName(OWScene.SolarSystem);
|
|
var isEyeOfTheUniverse = scene.name == LoadManager.SceneToName(OWScene.EyeOfTheUniverse);
|
|
var isCreditsFast = scene.name == LoadManager.SceneToName(OWScene.Credits_Fast);
|
|
var isCreditsFinal = scene.name == LoadManager.SceneToName(OWScene.Credits_Final);
|
|
var isPostCredits = scene.name == LoadManager.SceneToName(OWScene.PostCreditsScene);
|
|
|
|
if (isSolarSystem)
|
|
{
|
|
try
|
|
{
|
|
AtmosphereBuilder.InitPrefabs();
|
|
BrambleDimensionBuilder.InitPrefabs();
|
|
BrambleNodeBuilder.InitPrefabs();
|
|
CloudsBuilder.InitPrefabs();
|
|
CometTailBuilder.InitPrefab();
|
|
DetectorBuilder.InitPrefabs();
|
|
EffectsBuilder.InitPrefabs();
|
|
FogBuilder.InitPrefabs();
|
|
FunnelBuilder.InitPrefabs();
|
|
GeometryBuilder.InitPrefab();
|
|
GeyserBuilder.InitPrefab();
|
|
LavaBuilder.InitPrefabs();
|
|
|
|
// Backwards compat
|
|
#pragma warning disable 612, 618
|
|
NomaiTextBuilder.InitPrefabs();
|
|
#pragma warning restore 612, 618
|
|
TranslatorTextBuilder.InitPrefabs();
|
|
RemoteBuilder.InitPrefabs();
|
|
SandBuilder.InitPrefabs();
|
|
SingularityBuilder.InitPrefabs();
|
|
StarBuilder.InitPrefabs();
|
|
StarEvolutionController.Init();
|
|
SupernovaEffectBuilder.InitPrefabs();
|
|
TornadoBuilder.InitPrefabs();
|
|
VolcanoBuilder.InitPrefab();
|
|
VolumesBuilder.InitPrefabs();
|
|
WaterBuilder.InitPrefabs();
|
|
|
|
ProjectionBuilder.InitPrefabs();
|
|
CloakBuilder.InitPrefab();
|
|
RaftBuilder.InitPrefab();
|
|
|
|
WarpPadBuilder.InitPrefabs();
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Logger.LogError($"Couldn't init prefabs:\n{e}");
|
|
}
|
|
}
|
|
|
|
if (isEyeOfTheUniverse)
|
|
{
|
|
_currentStarSystem = "EyeOfTheUniverse";
|
|
}
|
|
else if (IsWarpingBackToEye)
|
|
{
|
|
IsWarpingBackToEye = false;
|
|
OWTime.Pause(OWTime.PauseType.Loading);
|
|
LoadManager.LoadSceneImmediate(OWScene.EyeOfTheUniverse);
|
|
OWTime.Unpause(OWTime.PauseType.Loading);
|
|
return;
|
|
}
|
|
|
|
if (!SystemDict.ContainsKey(_currentStarSystem) || !BodyDict.ContainsKey(_currentStarSystem))
|
|
{
|
|
Logger.LogError($"System \"{_currentStarSystem}\" does not exist!");
|
|
_currentStarSystem = DefaultStarSystem;
|
|
}
|
|
|
|
// Set time loop stuff if its enabled and if we're warping to a new place
|
|
if (IsChangingStarSystem && (SystemDict[_currentStarSystem].Config.enableTimeLoop || _currentStarSystem == "SolarSystem") && SecondsElapsedInLoop > 0f)
|
|
{
|
|
TimeLoopUtilities.SetSecondsElapsed(SecondsElapsedInLoop);
|
|
// Prevent the OPC from firing
|
|
var launchController = GameObject.FindObjectOfType<OrbitalProbeLaunchController>();
|
|
if (launchController != null)
|
|
{
|
|
GlobalMessenger<int>.RemoveListener("StartOfTimeLoop", launchController.OnStartOfTimeLoop);
|
|
foreach (var fakeDebris in launchController._fakeDebrisBodies)
|
|
{
|
|
fakeDebris.gameObject.SetActive(false);
|
|
}
|
|
launchController.enabled = false;
|
|
}
|
|
var nomaiProbe = SearchUtilities.Find("NomaiProbe_Body");
|
|
if (nomaiProbe != null) nomaiProbe.gameObject.SetActive(false);
|
|
}
|
|
|
|
// Reset this
|
|
SecondsElapsedInLoop = -1;
|
|
|
|
IsChangingStarSystem = false;
|
|
|
|
if (isTitleScreen && _useCustomTitleScreen)
|
|
{
|
|
TitleSceneHandler.DisplayBodyOnTitleScreen(BodyDict.Values.ToList().SelectMany(x => x).ToList());
|
|
TitleSceneHandler.InitSubtitles();
|
|
}
|
|
|
|
// EOTU fixes
|
|
if (isEyeOfTheUniverse)
|
|
{
|
|
EyeSceneHandler.OnSceneLoad();
|
|
}
|
|
|
|
if (isSolarSystem || isEyeOfTheUniverse)
|
|
{
|
|
IsSystemReady = false;
|
|
|
|
NewHorizonsData.Load();
|
|
|
|
// If the vessel is forcing the player to spawn there, allow it to override
|
|
IsWarpingFromVessel = VesselWarpHandler.ShouldSpawnAtVessel();
|
|
|
|
// Some builders have to be reset each loop
|
|
SignalBuilder.Init();
|
|
BrambleDimensionBuilder.Init();
|
|
AstroObjectLocator.Init();
|
|
StreamingHandler.Init();
|
|
AudioTypeHandler.Init();
|
|
InterferenceHandler.Init();
|
|
RemoteHandler.Init();
|
|
SingularityBuilder.Init();
|
|
AtmosphereBuilder.Init();
|
|
BrambleNodeBuilder.Init(BodyDict[CurrentStarSystem].Select(x => x.Config).Where(x => x.Bramble?.dimension != null).ToArray());
|
|
|
|
if (isSolarSystem)
|
|
{
|
|
foreach (var supernovaPlanetEffectController in GameObject.FindObjectsOfType<SupernovaPlanetEffectController>())
|
|
{
|
|
SupernovaEffectBuilder.ReplaceVanillaWithNH(supernovaPlanetEffectController);
|
|
}
|
|
}
|
|
|
|
PlanetCreationHandler.Init(BodyDict[CurrentStarSystem]);
|
|
VesselWarpHandler.LoadVessel();
|
|
SystemCreationHandler.LoadSystem(SystemDict[CurrentStarSystem]);
|
|
|
|
StarChartHandler.Init(SystemDict.Values.ToArray());
|
|
|
|
if (isSolarSystem)
|
|
{
|
|
// Warp drive
|
|
HasWarpDrive = StarChartHandler.CanWarp();
|
|
if (_shipWarpController == null)
|
|
{
|
|
_shipWarpController = SearchUtilities.Find("Ship_Body").AddComponent<ShipWarpController>();
|
|
_shipWarpController.Init();
|
|
}
|
|
if (HasWarpDrive == true) EnableWarpDrive();
|
|
|
|
var shouldWarpInFromShip = IsWarpingFromShip && _shipWarpController != null;
|
|
var shouldWarpInFromVessel = IsWarpingFromVessel && VesselWarpHandler.VesselSpawnPoint != null;
|
|
Delay.RunWhen(() => IsSystemReady, () => OnSystemReady(shouldWarpInFromShip, shouldWarpInFromVessel));
|
|
|
|
IsWarpingFromShip = false;
|
|
IsWarpingFromVessel = false;
|
|
DidWarpFromVessel = shouldWarpInFromVessel;
|
|
|
|
var map = GameObject.FindObjectOfType<MapController>();
|
|
if (map != null) map._maxPanDistance = FurthestOrbit * 1.5f;
|
|
|
|
// Fix the map satellite
|
|
SearchUtilities.Find("HearthianMapSatellite_Body", false).AddComponent<MapSatelliteOrbitFix>();
|
|
|
|
|
|
// Sector changes (so that projection pools actually turn off proxies and cull groups on these moons)
|
|
|
|
//Fix attlerock vanilla sector components (they were set to timber hearth's sector)
|
|
var thm = SearchUtilities.Find("Moon_Body/Sector_THM").GetComponent<Sector>();
|
|
foreach (var component in thm.GetComponentsInChildren<Component>(true))
|
|
{
|
|
if (component is ISectorGroup sectorGroup)
|
|
{
|
|
sectorGroup.SetSector(thm);
|
|
}
|
|
|
|
if (component is SectoredMonoBehaviour behaviour)
|
|
{
|
|
behaviour.SetSector(thm);
|
|
}
|
|
}
|
|
var thm_ss_obj = new GameObject("Sector_Streaming");
|
|
thm_ss_obj.transform.SetParent(thm.transform, false);
|
|
var thm_ss = thm_ss_obj.AddComponent<SectorStreaming>();
|
|
thm_ss._streamingGroup = SearchUtilities.Find("TimberHearth_Body/StreamingGroup_TH").GetComponent<StreamingGroup>();
|
|
thm_ss.SetSector(thm);
|
|
|
|
|
|
//Fix hollow's lantern vanilla sector components (they were set to brittle hollow's sector)
|
|
var vm = SearchUtilities.Find("VolcanicMoon_Body/Sector_VM").GetComponent<Sector>();
|
|
foreach (var component in vm.GetComponentsInChildren<Component>(true))
|
|
{
|
|
if (component is ISectorGroup sectorGroup)
|
|
{
|
|
sectorGroup.SetSector(vm);
|
|
}
|
|
|
|
if (component is SectoredMonoBehaviour behaviour)
|
|
{
|
|
behaviour.SetSector(vm);
|
|
}
|
|
}
|
|
var vm_ss_obj = new GameObject("Sector_Streaming");
|
|
vm_ss_obj.transform.SetParent(vm.transform, false);
|
|
var vm_ss = vm_ss_obj.AddComponent<SectorStreaming>();
|
|
vm_ss._streamingGroup = SearchUtilities.Find("BrittleHollow_Body/StreamingGroup_BH").GetComponent<StreamingGroup>();
|
|
vm_ss.SetSector(vm);
|
|
|
|
//Fix brittle hollow north pole projection platform
|
|
var northPoleSurface = SearchUtilities.Find("BrittleHollow_Body/Sector_BH/Sector_NorthHemisphere/Sector_NorthPole/Sector_NorthPoleSurface").GetComponent<Sector>();
|
|
var remoteViewer = SearchUtilities.Find("BrittleHollow_Body/Sector_BH/Sector_NorthHemisphere/Sector_NorthPole/Sector_NorthPoleSurface/Interactables_NorthPoleSurface/LowBuilding/Prefab_NOM_RemoteViewer").GetComponent<NomaiRemoteCameraPlatform>();
|
|
remoteViewer._visualSector = northPoleSurface;
|
|
}
|
|
else if (isEyeOfTheUniverse)
|
|
{
|
|
// There is no wake up in eye scene
|
|
Delay.FireOnNextUpdate(() =>
|
|
{
|
|
IsSystemReady = true;
|
|
OnSystemReady(false, false);
|
|
});
|
|
|
|
IsWarpingFromShip = false;
|
|
IsWarpingFromVessel = false;
|
|
DidWarpFromVessel = false;
|
|
}
|
|
|
|
//Stop starfield from disappearing when there is no lights
|
|
var playerBody = SearchUtilities.Find("Player_Body");
|
|
var playerLight = playerBody.AddComponent<Light>();
|
|
playerLight.innerSpotAngle = 0;
|
|
playerLight.spotAngle = 179;
|
|
playerLight.range = 1;
|
|
playerLight.intensity = 0.001f;
|
|
|
|
//Do the same for map
|
|
var solarSystemRoot = SearchUtilities.Find("SolarSystemRoot");
|
|
var ssrLight = solarSystemRoot.AddComponent<Light>();
|
|
ssrLight.innerSpotAngle = 0;
|
|
ssrLight.spotAngle = 179;
|
|
ssrLight.range = Main.FurthestOrbit * (4f / 3f);
|
|
ssrLight.intensity = 0.001f;
|
|
|
|
var fluid = playerBody.FindChild("PlayerDetector").GetComponent<DynamicFluidDetector>();
|
|
fluid._splashEffects = fluid._splashEffects.AddToArray(new SplashEffect
|
|
{
|
|
fluidType = FluidVolume.Type.PLASMA,
|
|
ignoreSphereAligment = false,
|
|
minImpactSpeed = 15,
|
|
splashPrefab = SearchUtilities.Find("Probe_Body/ProbeDetector").GetComponent<FluidDetector>()._splashEffects.FirstOrDefault(sfx => sfx.fluidType == FluidVolume.Type.PLASMA).splashPrefab,
|
|
triggerEvent = SplashEffect.TriggerEvent.OnEntry
|
|
});
|
|
|
|
try
|
|
{
|
|
Logger.Log($"Star system finished loading [{Instance.CurrentStarSystem}]");
|
|
Instance.OnStarSystemLoaded?.Invoke(Instance.CurrentStarSystem);
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Logger.LogError($"Exception thrown when invoking star system loaded event with parameter [{Instance.CurrentStarSystem}]:\n{e}");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Reset back to original solar system after going to main menu.
|
|
// If the override is a valid system then we go there
|
|
if (SystemDict.ContainsKey(_defaultSystemOverride))
|
|
{
|
|
_currentStarSystem = _defaultSystemOverride;
|
|
IsWarpingFromShip = true; // always do this else sometimes the spawn gets messed up
|
|
}
|
|
else
|
|
{
|
|
_currentStarSystem = _defaultStarSystem;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Had a bunch of separate unity things firing stuff when the system is ready so I moved it all to here
|
|
private void OnSystemReady(bool shouldWarpInFromShip, bool shouldWarpInFromVessel)
|
|
{
|
|
Locator.GetPlayerBody().gameObject.AddComponent<DebugRaycaster>();
|
|
Locator.GetPlayerBody().gameObject.AddComponent<DebugPropPlacer>();
|
|
Locator.GetPlayerBody().gameObject.AddComponent<DebugMenu>();
|
|
// DebugArrow.CreateArrow(Locator.GetPlayerBody().gameObject); // This is for NH devs mostly. It shouldn't be active in debug mode for now. Someone should make a dev tools submenu for it though.
|
|
|
|
if (shouldWarpInFromShip) _shipWarpController.WarpIn(WearingSuit);
|
|
else if (shouldWarpInFromVessel) VesselWarpHandler.TeleportToVessel();
|
|
else FindObjectOfType<PlayerSpawner>().DebugWarp(SystemDict[_currentStarSystem].SpawnPoint);
|
|
|
|
VesselCoordinatePromptHandler.RegisterPrompts(SystemDict.Where(system => system.Value.Config.Vessel?.coords != null).Select(x => x.Value).ToList());
|
|
}
|
|
|
|
public void EnableWarpDrive()
|
|
{
|
|
Logger.LogVerbose("Setting up warp drive");
|
|
PlanetCreationHandler.LoadBody(LoadConfig(this, "Assets/WarpDriveConfig.json"));
|
|
HasWarpDrive = true;
|
|
}
|
|
|
|
|
|
#region Load
|
|
public void LoadConfigs(IModBehaviour mod)
|
|
{
|
|
try
|
|
{
|
|
if (_firstLoad)
|
|
{
|
|
MountedAddons.Add(mod);
|
|
}
|
|
var folder = mod.ModHelper.Manifest.ModFolderPath;
|
|
|
|
var systemsFolder = Path.Combine(folder, "systems");
|
|
var planetsFolder = Path.Combine(folder, "planets");
|
|
|
|
// Load systems first so that when we load bodies later we can check for missing ones
|
|
if (Directory.Exists(systemsFolder))
|
|
{
|
|
var systemFiles = Directory.GetFiles(systemsFolder, "*.json", SearchOption.AllDirectories)
|
|
.Concat(Directory.GetFiles(systemsFolder, "*.jsonc", SearchOption.AllDirectories))
|
|
.ToArray();
|
|
|
|
if(systemFiles.Length == 0)
|
|
{
|
|
Logger.LogVerbose($"Found no JSON files in systems folder: {systemsFolder}");
|
|
}
|
|
|
|
foreach (var file in systemFiles)
|
|
{
|
|
var name = Path.GetFileNameWithoutExtension(file);
|
|
|
|
Logger.LogVerbose($"Loading system {name}");
|
|
|
|
var relativePath = file.Replace(folder, "");
|
|
var starSystemConfig = mod.ModHelper.Storage.Load<StarSystemConfig>(relativePath, false);
|
|
starSystemConfig.Migrate();
|
|
starSystemConfig.FixCoordinates();
|
|
|
|
if (starSystemConfig.startHere)
|
|
{
|
|
// We always want to allow mods to overwrite setting the main SolarSystem as default but not the other way around
|
|
if (name != "SolarSystem")
|
|
{
|
|
SetDefaultSystem(name);
|
|
_currentStarSystem = name;
|
|
}
|
|
}
|
|
|
|
if (SystemDict.ContainsKey(name))
|
|
{
|
|
if (string.IsNullOrEmpty(SystemDict[name].Config.travelAudio) && SystemDict[name].Config.Skybox == null)
|
|
SystemDict[name].Mod = mod;
|
|
SystemDict[name].Config.Merge(starSystemConfig);
|
|
}
|
|
else
|
|
{
|
|
SystemDict[name] = new NewHorizonsSystem(name, starSystemConfig, relativePath, mod);
|
|
}
|
|
}
|
|
}
|
|
if (Directory.Exists(planetsFolder))
|
|
{
|
|
var planetFiles = Directory.GetFiles(planetsFolder, "*.json", SearchOption.AllDirectories)
|
|
.Concat(Directory.GetFiles(planetsFolder, "*.jsonc", SearchOption.AllDirectories))
|
|
.ToArray();
|
|
|
|
if(planetFiles.Length == 0)
|
|
{
|
|
Logger.LogVerbose($"Found no JSON files in planets folder: {planetsFolder}");
|
|
}
|
|
|
|
foreach (var file in planetFiles)
|
|
{
|
|
var relativeDirectory = file.Replace(folder, "");
|
|
var body = LoadConfig(mod, relativeDirectory);
|
|
|
|
if (body != null)
|
|
{
|
|
// Wanna track the spawn point of each system
|
|
if (body.Config.Spawn != null) SystemDict[body.Config.starSystem].Spawn = body.Config.Spawn;
|
|
|
|
// Add the new planet to the planet dictionary
|
|
if (!BodyDict.ContainsKey(body.Config.starSystem)) BodyDict[body.Config.starSystem] = new List<NewHorizonsBody>();
|
|
BodyDict[body.Config.starSystem].Add(body);
|
|
}
|
|
}
|
|
}
|
|
// Has to go before translations for achievements
|
|
if (File.Exists(Path.Combine(folder, "addon-manifest.json")))
|
|
{
|
|
LoadAddonManifest("addon-manifest.json", mod);
|
|
}
|
|
if (Directory.Exists(Path.Combine(folder, "translations")))
|
|
{
|
|
LoadTranslations(folder, mod);
|
|
}
|
|
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Logger.LogError(ex.ToString());
|
|
}
|
|
}
|
|
|
|
private void LoadAddonManifest(string file, IModBehaviour mod)
|
|
{
|
|
Logger.LogVerbose($"Loading addon manifest for {mod.ModHelper.Manifest.Name}");
|
|
|
|
var addonConfig = mod.ModHelper.Storage.Load<AddonConfig>(file, false);
|
|
|
|
if (addonConfig.achievements != null)
|
|
{
|
|
AchievementHandler.RegisterAddon(addonConfig, mod as ModBehaviour);
|
|
}
|
|
if (addonConfig.credits != null)
|
|
{
|
|
var translatedCredits = addonConfig.credits.Select(x => TranslationHandler.GetTranslation(x, TranslationHandler.TextType.UI)).ToArray();
|
|
CreditsHandler.RegisterCredits(mod.ModHelper.Manifest.Name, translatedCredits);
|
|
}
|
|
if (!string.IsNullOrEmpty(addonConfig.popupMessage))
|
|
{
|
|
MenuHandler.RegisterOneTimePopup(mod, TranslationHandler.GetTranslation(addonConfig.popupMessage, TranslationHandler.TextType.UI));
|
|
}
|
|
}
|
|
|
|
private void LoadTranslations(string folder, IModBehaviour mod)
|
|
{
|
|
var foundFile = false;
|
|
foreach (TextTranslation.Language language in EnumUtils.GetValues<TextTranslation.Language>())
|
|
{
|
|
if (language is TextTranslation.Language.UNKNOWN or TextTranslation.Language.TOTAL) continue;
|
|
|
|
var relativeFile = Path.Combine("translations", language.ToString().ToLower() + ".json");
|
|
|
|
if (File.Exists(Path.Combine(folder, relativeFile)))
|
|
{
|
|
Logger.LogVerbose($"Registering {language} translation from {mod.ModHelper.Manifest.Name} from {relativeFile}");
|
|
|
|
var config = new TranslationConfig(Path.Combine(folder, relativeFile));
|
|
|
|
foundFile = true;
|
|
|
|
TranslationHandler.RegisterTranslation(language, config);
|
|
|
|
if (AchievementHandler.Enabled)
|
|
{
|
|
AchievementHandler.RegisterTranslationsFromFiles(mod as ModBehaviour, "translations");
|
|
}
|
|
}
|
|
}
|
|
if (!foundFile) Logger.LogWarning($"{mod.ModHelper.Manifest.Name} has a folder for translations but none were loaded");
|
|
}
|
|
|
|
public NewHorizonsBody LoadConfig(IModBehaviour mod, string relativePath)
|
|
{
|
|
NewHorizonsBody body = null;
|
|
try
|
|
{
|
|
var config = mod.ModHelper.Storage.Load<PlanetConfig>(relativePath, false);
|
|
if (config == null)
|
|
{
|
|
Logger.LogError($"Couldn't load {relativePath}. Is your Json formatted correctly?");
|
|
MenuHandler.RegisterFailedConfig(Path.GetFileName(relativePath));
|
|
return null;
|
|
}
|
|
|
|
Logger.LogVerbose($"Loaded {config.name}");
|
|
|
|
if (!SystemDict.ContainsKey(config.starSystem))
|
|
{
|
|
// Since we didn't load it earlier there shouldn't be a star system config
|
|
var starSystemConfig = mod.ModHelper.Storage.Load<StarSystemConfig>(Path.Combine("systems", config.starSystem + ".json"), false);
|
|
if (starSystemConfig == null) starSystemConfig = new StarSystemConfig();
|
|
else Logger.LogWarning($"Loaded system config for {config.starSystem}. Why wasn't this loaded earlier?");
|
|
|
|
starSystemConfig.Migrate();
|
|
starSystemConfig.FixCoordinates();
|
|
|
|
var system = new NewHorizonsSystem(config.starSystem, starSystemConfig, $"", mod);
|
|
|
|
SystemDict.Add(config.starSystem, system);
|
|
|
|
BodyDict.Add(config.starSystem, new List<NewHorizonsBody>());
|
|
}
|
|
|
|
// Has to happen after we make sure theres a system config
|
|
config.Validate();
|
|
config.Migrate();
|
|
|
|
body = new NewHorizonsBody(config, mod, relativePath);
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Logger.LogError($"Error encounter when loading {relativePath}:\n{e}");
|
|
MenuHandler.RegisterFailedConfig(Path.GetFileName(relativePath));
|
|
}
|
|
|
|
return body;
|
|
}
|
|
|
|
public void SetDefaultSystem(string defaultSystem)
|
|
{
|
|
_defaultStarSystem = defaultSystem;
|
|
}
|
|
|
|
#endregion Load
|
|
|
|
#region Change star system
|
|
public void ChangeCurrentStarSystem(string newStarSystem, bool warp = false, bool vessel = false)
|
|
{
|
|
// If we're just on the title screen set the system for later
|
|
if (LoadManager.GetCurrentScene() == OWScene.TitleScreen)
|
|
{
|
|
_currentStarSystem = newStarSystem;
|
|
IsWarpingFromShip = warp;
|
|
IsWarpingFromVessel = vessel;
|
|
DidWarpFromVessel = false;
|
|
|
|
var warpingToEye = newStarSystem == "EyeOfTheUniverse";
|
|
|
|
if (warpingToEye) PlayerData.SaveWarpedToTheEye(180);
|
|
else PlayerData.SaveEyeCompletion();
|
|
|
|
var loadableScene = warpingToEye ? SubmitActionLoadScene.LoadableScenes.EYE : SubmitActionLoadScene.LoadableScenes.GAME;
|
|
var newGame = SearchUtilities.Find("TitleMenu/TitleCanvas/TitleLayoutGroup/MainMenuBlock/MainMenuLayoutGroup/Button-NewGame")?.GetComponent<SubmitActionLoadScene>();
|
|
var resumeGame = SearchUtilities.Find("TitleMenu/TitleCanvas/TitleLayoutGroup/MainMenuBlock/MainMenuLayoutGroup/Button-ResumeGame")?.GetComponent<SubmitActionLoadScene>();
|
|
if (newGame != null) newGame._sceneToLoad = loadableScene;
|
|
if (resumeGame != null) resumeGame._sceneToLoad = loadableScene;
|
|
|
|
return;
|
|
}
|
|
|
|
if (IsChangingStarSystem) return;
|
|
|
|
IsWarpingFromShip = warp;
|
|
IsWarpingFromVessel = vessel;
|
|
DidWarpFromVessel = false;
|
|
OnChangeStarSystem?.Invoke(newStarSystem);
|
|
|
|
Logger.Log($"Warping to {newStarSystem}");
|
|
if (warp && _shipWarpController) _shipWarpController.WarpOut();
|
|
IsChangingStarSystem = true;
|
|
WearingSuit = PlayerState.IsWearingSuit();
|
|
|
|
OWScene sceneToLoad;
|
|
|
|
if (newStarSystem == "EyeOfTheUniverse")
|
|
{
|
|
PlayerData.SaveWarpedToTheEye(TimeLoopUtilities.GetVanillaSecondsRemaining());
|
|
sceneToLoad = OWScene.EyeOfTheUniverse;
|
|
}
|
|
else
|
|
{
|
|
PlayerData.SaveEyeCompletion(); // So that the title screen doesn't keep warping you back to eye
|
|
|
|
if (SystemDict[_currentStarSystem].Config.enableTimeLoop) SecondsElapsedInLoop = TimeLoop.GetSecondsElapsed();
|
|
else SecondsElapsedInLoop = -1;
|
|
|
|
sceneToLoad = OWScene.SolarSystem;
|
|
}
|
|
|
|
_currentStarSystem = newStarSystem;
|
|
|
|
// Freeze player inputs
|
|
OWInput.ChangeInputMode(InputMode.None);
|
|
|
|
LoadManager.LoadSceneAsync(sceneToLoad, !vessel, LoadManager.FadeType.ToBlack, vessel ? 1 : 0.1f, true);
|
|
}
|
|
|
|
void OnDeath(DeathType _)
|
|
{
|
|
// We reset the solar system on death
|
|
if (!IsChangingStarSystem)
|
|
{
|
|
if (SystemDict[_currentStarSystem].Config.respawnHere) return;
|
|
|
|
// If the override is a valid system then we go there
|
|
if (SystemDict.ContainsKey(_defaultSystemOverride))
|
|
{
|
|
_currentStarSystem = _defaultSystemOverride;
|
|
}
|
|
else
|
|
{
|
|
_currentStarSystem = _defaultStarSystem;
|
|
}
|
|
}
|
|
}
|
|
#endregion Change star system
|
|
}
|
|
}
|