diff --git a/NewHorizons/Assets/DefaultMapModeStar.png b/NewHorizons/Assets/DefaultMapModeStar.png index 7bc0ac1b..bdcedc5b 100644 Binary files a/NewHorizons/Assets/DefaultMapModeStar.png and b/NewHorizons/Assets/DefaultMapModeStar.png differ diff --git a/NewHorizons/Assets/addon-manifest.json b/NewHorizons/Assets/addon-manifest.json index 363bc1bb..b5a71ba2 100644 --- a/NewHorizons/Assets/addon-manifest.json +++ b/NewHorizons/Assets/addon-manifest.json @@ -10,7 +10,7 @@ "Trifid#Tester\n#Programmer", "Nageld#Programmer", "Ernesto#Fish", - "With help from#Raicuparta\n#dgarroDC\n#jtsalomo\n#and the modding community", + "With help from#Raicuparta\n#dgarroDC\n#jtsalomo\n#coderCleric\n#TRSasasusu\n#and the modding community", " ", "Based off Marshmallow made by#_nebula", "With help from#AmazingAlek\n#Raicuparta\n#and the Outer Wilds discord server", diff --git a/NewHorizons/Builder/Atmosphere/FogBuilder.cs b/NewHorizons/Builder/Atmosphere/FogBuilder.cs index 9f1d7da8..f47e3e29 100644 --- a/NewHorizons/Builder/Atmosphere/FogBuilder.cs +++ b/NewHorizons/Builder/Atmosphere/FogBuilder.cs @@ -1,10 +1,10 @@ using NewHorizons.External.Modules; -using NewHorizons.External.Modules.Props; using NewHorizons.Utility; using NewHorizons.Utility.Files; using OWML.Common; using System; using UnityEngine; + namespace NewHorizons.Builder.Atmosphere { public static class FogBuilder @@ -26,7 +26,9 @@ namespace NewHorizons.Builder.Atmosphere internal static void InitPrefabs() { - if (_ramp == null) _ramp = ImageUtilities.GetTexture(Main.Instance, "Assets/textures/FogColorRamp.png"); + // Checking null here it was getting destroyed and wouldnt reload and never worked outside of the first loop + // GetTexture caches itself anyway so it doesn't matter that this gets called multiple times + _ramp = ImageUtilities.GetTexture(Main.Instance, "Assets/textures/FogColorRamp.png"); if (_isInit) return; @@ -73,6 +75,7 @@ namespace NewHorizons.Builder.Atmosphere atmo.fogRampPath != null ? ImageUtilities.GetTexture(mod, atmo.fogRampPath) : atmo.fogTint != null ? ImageUtilities.TintImage(_ramp, atmo.fogTint.ToColor()) : _ramp; + PFC.fogColorRampTexture = colorRampTexture; PFC.fogColorRampIntensity = 1f; if (atmo.fogTint != null) diff --git a/NewHorizons/Builder/Atmosphere/SunOverrideBuilder.cs b/NewHorizons/Builder/Atmosphere/SunOverrideBuilder.cs index df696f4d..9ee0e365 100644 --- a/NewHorizons/Builder/Atmosphere/SunOverrideBuilder.cs +++ b/NewHorizons/Builder/Atmosphere/SunOverrideBuilder.cs @@ -1,6 +1,7 @@ using NewHorizons.External.Modules; using NewHorizons.External.Modules.VariableSize; using UnityEngine; + namespace NewHorizons.Builder.Atmosphere { public static class SunOverrideBuilder diff --git a/NewHorizons/Builder/General/AstroObjectBuilder.cs b/NewHorizons/Builder/General/AstroObjectBuilder.cs index 45966762..a2fc1410 100644 --- a/NewHorizons/Builder/General/AstroObjectBuilder.cs +++ b/NewHorizons/Builder/General/AstroObjectBuilder.cs @@ -1,6 +1,6 @@ using NewHorizons.Components; using NewHorizons.Components.Orbital; -using NewHorizons.External.Configs; +using NewHorizons.External; using NewHorizons.Utility.OWML; using UnityEngine; @@ -8,9 +8,13 @@ namespace NewHorizons.Builder.General { public static class AstroObjectBuilder { - public static NHAstroObject Make(GameObject body, AstroObject primaryBody, PlanetConfig config, bool isVanilla) + public static NHAstroObject Make(GameObject body, AstroObject primaryBody, NewHorizonsBody nhBody, bool isVanilla) { NHAstroObject astroObject = body.AddComponent(); + astroObject.modUniqueName = nhBody.Mod.ModHelper.Manifest.UniqueName; + + var config = nhBody.Config; + astroObject.isVanilla = isVanilla; astroObject.HideDisplayName = !config.Base.hasMapMarker; astroObject.invulnerableToSun = config.Base.invulnerableToSun; diff --git a/NewHorizons/Builder/General/RFVolumeBuilder.cs b/NewHorizons/Builder/General/RFVolumeBuilder.cs index f359a7e0..f8fa8aa8 100644 --- a/NewHorizons/Builder/General/RFVolumeBuilder.cs +++ b/NewHorizons/Builder/General/RFVolumeBuilder.cs @@ -12,6 +12,8 @@ namespace NewHorizons.Builder.General { // We can't not build a reference frame volume, Cloak requires one to be there module.maxTargetDistance = 0f; + module.targetWhenClose = true; + module.targetColliderRadius = 0f; module.hideInMap = true; owrb.SetIsTargetable(false); } diff --git a/NewHorizons/Builder/Props/Audio/SignalBuilder.cs b/NewHorizons/Builder/Props/Audio/SignalBuilder.cs index 66a86061..b5fbfaf0 100644 --- a/NewHorizons/Builder/Props/Audio/SignalBuilder.cs +++ b/NewHorizons/Builder/Props/Audio/SignalBuilder.cs @@ -1,9 +1,11 @@ using HarmonyLib; +using NewHorizons.External; using NewHorizons.External.Modules.Props.Audio; using NewHorizons.Utility; using NewHorizons.Utility.OWML; using OWML.Common; using OWML.Utils; +using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; @@ -36,27 +38,16 @@ namespace NewHorizons.Builder.Props.Audio }; NumberOfFrequencies = EnumUtils.GetValues().Length; - _qmSignals = new (){ SearchUtilities.Find("QuantumMoon_Body/Signal_Quantum").GetComponent() }; + _qmSignals = new () { SearchUtilities.Find("QuantumMoon_Body/Signal_Quantum").GetComponent() }; _cloakedSignals = new(); Initialized = true; SceneManager.sceneUnloaded -= OnSceneUnloaded; SceneManager.sceneUnloaded += OnSceneUnloaded; - Main.Instance.OnStarSystemLoaded.RemoveListener(OnStarSystemLoaded); - Main.Instance.OnStarSystemLoaded.AddListener(OnStarSystemLoaded); - } - private static HashSet _frequenciesInUse = new(); - - private static void OnSceneUnloaded(Scene _) - { - _frequenciesInUse.Clear(); - } - - private static void OnStarSystemLoaded(string starSystem) - { // If its the base game solar system or eye we get all the main frequencies + var starSystem = Main.Instance.CurrentStarSystem; if (starSystem == "SolarSystem" || starSystem == "EyeOfTheUniverse") { _frequenciesInUse.Add(SignalFrequency.Quantum); @@ -69,19 +60,43 @@ namespace NewHorizons.Builder.Props.Audio // We don't want a scenario where the player knows no frequencies _frequenciesInUse.Add(SignalFrequency.Traveler); + // Make sure the NH save file has all the right frequencies + // Skip "default" + for (int i = 1; i < PlayerData._currentGameSave.knownFrequencies.Length; i++) + { + if (PlayerData._currentGameSave.knownFrequencies[i]) + { + NewHorizonsData.LearnFrequency(AudioSignal.IndexToFrequency(i).ToString()); + } + } + NHLogger.LogVerbose($"Frequencies in use in {starSystem}: {_frequenciesInUse.Join(x => x.ToString())}"); } + private static HashSet _frequenciesInUse = new(); + + private static void OnSceneUnloaded(Scene _) + { + _frequenciesInUse.Clear(); + } + public static bool IsFrequencyInUse(SignalFrequency freq) => _frequenciesInUse.Contains(freq); + public static bool IsFrequencyInUse(string freqString) + { + if (Enum.TryParse(freqString, out var freq)) + { + return IsFrequencyInUse(freq); + } + return false; + } + public static bool IsCloaked(this AudioSignal signal) => _cloakedSignals.Contains(signal); public static bool IsOnQuantumMoon(this AudioSignal signal) => _qmSignals.Contains(signal); public static SignalFrequency AddFrequency(string str) { - if (_customFrequencyNames == null) Init(); - var freq = CollectionUtilities.KeyByValue(_customFrequencyNames, str); if (freq != default) return freq; @@ -99,23 +114,19 @@ 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 - Object.FindObjectOfType()._strongestSignals = new AudioSignal[NumberOfFrequencies + 1]; + GameObject.FindObjectOfType()._strongestSignals = new AudioSignal[NumberOfFrequencies + 1]; return freq; } public static string GetCustomFrequencyName(SignalFrequency frequencyName) { - if (_customFrequencyNames == null) Init(); - _customFrequencyNames.TryGetValue(frequencyName, out string name); return name; } public static SignalName AddSignalName(string str) { - if (_customSignalNames == null) Init(); - var name = CollectionUtilities.KeyByValue(_customSignalNames, str); if (name != default) return name; @@ -129,8 +140,6 @@ namespace NewHorizons.Builder.Props.Audio public static string GetCustomSignalName(SignalName signalName) { - if (_customSignalNames == null) Init(); - _customSignalNames.TryGetValue(signalName, out string name); return name; } diff --git a/NewHorizons/Builder/Props/BrambleNodeBuilder.cs b/NewHorizons/Builder/Props/BrambleNodeBuilder.cs index 2aa1075e..82e85a12 100644 --- a/NewHorizons/Builder/Props/BrambleNodeBuilder.cs +++ b/NewHorizons/Builder/Props/BrambleNodeBuilder.cs @@ -6,6 +6,7 @@ using NewHorizons.Handlers; using NewHorizons.Utility; using NewHorizons.Utility.OuterWilds; using NewHorizons.Utility.OWML; +using Newtonsoft.Json; using OWML.Common; using System.Collections.Generic; using System.Linq; @@ -414,7 +415,13 @@ namespace NewHorizons.Builder.Props { foreach (var signalConfig in connectedSignals) { - var signalGO = SignalBuilder.Make(go, sector, signalConfig, mod); + // Have to ensure that this new signal doesn't use parent path, else it looks for a parent that only exists on the original body + // Have to make a copy of it as well to avoid modifying the old body's info + var signalConfigCopy = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(signalConfig)); + signalConfigCopy.parentPath = null; + signalConfigCopy.isRelativeToParent = false; + + var signalGO = SignalBuilder.Make(go, sector, signalConfigCopy, mod); signalGO.GetComponent()._identificationDistance = 0; signalGO.GetComponent()._sourceRadius = 1; signalGO.transform.position = brambleNode.transform.position; diff --git a/NewHorizons/Builder/Props/DetailBuilder.cs b/NewHorizons/Builder/Props/DetailBuilder.cs index e96b51dc..6a05cb09 100644 --- a/NewHorizons/Builder/Props/DetailBuilder.cs +++ b/NewHorizons/Builder/Props/DetailBuilder.cs @@ -101,6 +101,7 @@ namespace NewHorizons.Builder.Props GameObject prop; bool isItem; bool invalidComponentFound = false; + bool isFromAssetBundle = !string.IsNullOrEmpty(detail.assetBundle); // We save copies with all their components fixed, good if the user is placing the same detail more than once if (detail?.path != null && _fixedPrefabCache.TryGetValue((sector, detail.path), out var storedPrefab)) @@ -139,12 +140,21 @@ namespace NewHorizons.Builder.Props } else { - FixSectoredComponent(component, sector, existingSectors, detail.keepLoaded); + // Fix cull groups only when not from an asset bundle (because then they're there on purpose!) + // keepLoaded should remove existing groups + // renderers/colliders get enabled later so we dont have to do that here + if (detail.keepLoaded && !isFromAssetBundle && component is SectorCullGroup or SectorCollisionGroup or SectorLightsCullGroup) + { + UnityEngine.Object.DestroyImmediate(component); + continue; + } + + FixSectoredComponent(component, sector, existingSectors); } // Asset bundle is a real string -> Object loaded from unity // If they're adding dialogue we have to manually register the xml text - if (!string.IsNullOrEmpty(detail.assetBundle) && component is CharacterDialogueTree dialogue) + if (isFromAssetBundle && component is CharacterDialogueTree dialogue) { DialogueBuilder.AddTranslation(dialogue._xmlCharacterDialogueAsset.text, null); } @@ -278,16 +288,8 @@ namespace NewHorizons.Builder.Props /// /// Fix components that have sectors. Has a specific fix if there is a VisionTorchItem on the object. /// - private static void FixSectoredComponent(Component component, Sector sector, HashSet existingSectors, bool keepLoaded) + private static void FixSectoredComponent(Component component, Sector sector, HashSet existingSectors) { - // keepLoaded should remove existing groups - // renderers/colliders get enabled later so we dont have to do that here - if (keepLoaded && component is SectorCullGroup or SectorCollisionGroup or SectorLightsCullGroup) - { - UnityEngine.Object.DestroyImmediate(component); - return; - } - // fix Sector stuff, eg SectorCullGroup (without this, props that have a SectorCullGroup component will become invisible inappropriately) if (component is ISectorGroup sectorGroup && !existingSectors.Contains(sectorGroup.GetSector())) { @@ -295,15 +297,8 @@ namespace NewHorizons.Builder.Props } // Not doing else if here because idk if any of the classes below implement ISectorGroup - - // Null check else shuttles controls break - // parent sector is always null before Awake so this code actually never runs lol - if (component is Sector s && s.GetParentSector() != null && !existingSectors.Contains(s.GetParentSector())) - { - s.SetParentSector(sector); - } - else if(component is SectoredMonoBehaviour behaviour && !existingSectors.Contains(behaviour._sector)) + if(component is SectoredMonoBehaviour behaviour && !existingSectors.Contains(behaviour._sector)) { // not using SetSector here because it registers the events twice // perhaps this happens with ISectorGroup.SetSector or Sector.SetParentSector too? idk and nothing seems to break because of it yet diff --git a/NewHorizons/Builder/Props/DialogueBuilder.cs b/NewHorizons/Builder/Props/DialogueBuilder.cs index 4daabe4a..429626e5 100644 --- a/NewHorizons/Builder/Props/DialogueBuilder.cs +++ b/NewHorizons/Builder/Props/DialogueBuilder.cs @@ -102,10 +102,12 @@ namespace NewHorizons.Builder.Props // We just have to merge the dialogue options var dialogueOptions = newDialogueNode.GetChildNode("DialogueOptionsList").GetChildNodes("DialogueOption"); var existingDialogueOptionsList = existingNode.GetChildNode("DialogueOptionsList"); + var firstNode = existingDialogueOptionsList.ChildNodes[0]; foreach (XmlNode node in dialogueOptions) { var importedNode = existingDialogueOptionsList.OwnerDocument.ImportNode(node, true); - existingDialogueOptionsList.AppendChild(importedNode); + // We add them to the start because normally the last option is to return to menu or exit + existingDialogueOptionsList.PrependChild(importedNode); } } else diff --git a/NewHorizons/Builder/Props/ItemBuilder.cs b/NewHorizons/Builder/Props/ItemBuilder.cs index 78a866be..2a678d58 100644 --- a/NewHorizons/Builder/Props/ItemBuilder.cs +++ b/NewHorizons/Builder/Props/ItemBuilder.cs @@ -51,6 +51,10 @@ namespace NewHorizons.Builder.Props item.DisplayName = itemName; item.ItemType = itemType; item.Droppable = info.droppable; + item.HoldOffset = info.holdOffset ?? Vector3.zero; + item.HoldRotation = info.holdRotation ?? Vector3.zero; + item.SocketOffset = info.socketOffset ?? Vector3.zero; + item.SocketRotation = info.socketRotation ?? Vector3.zero; if (!string.IsNullOrEmpty(info.pickupAudio)) { item.PickupAudio = AudioTypeHandler.GetAudioType(info.pickupAudio, mod); diff --git a/NewHorizons/Builder/Props/TranslatorText/TranslatorTextBuilder.cs b/NewHorizons/Builder/Props/TranslatorText/TranslatorTextBuilder.cs index 9ad3ba5c..89b4249b 100644 --- a/NewHorizons/Builder/Props/TranslatorText/TranslatorTextBuilder.cs +++ b/NewHorizons/Builder/Props/TranslatorText/TranslatorTextBuilder.cs @@ -476,7 +476,7 @@ namespace NewHorizons.Builder.Props.TranslatorText } ArcCacheData[] cachedData = null; - if (nhBody.Cache?.ContainsKey(cacheKey) ?? false) + if (nhBody?.Cache?.ContainsKey(cacheKey) ?? false) cachedData = nhBody.Cache.Get(cacheKey); var arranger = nomaiWallText.gameObject.AddComponent(); diff --git a/NewHorizons/Builder/ShipLog/MapModeBuilder.cs b/NewHorizons/Builder/ShipLog/MapModeBuilder.cs index a36c6003..60e0e879 100644 --- a/NewHorizons/Builder/ShipLog/MapModeBuilder.cs +++ b/NewHorizons/Builder/ShipLog/MapModeBuilder.cs @@ -30,7 +30,7 @@ namespace NewHorizons.Builder.ShipLog { if (body.Config.ShipLog == null) continue; - if (body.Config.ShipLog?.mapMode?.manualPosition == null) + if (body.Config.ShipLog.mapMode?.manualPosition == null) { flagAutoPositionUsed = true; } @@ -45,6 +45,12 @@ namespace NewHorizons.Builder.ShipLog } } + // If they're both false, just default to auto (this means that no planets even have ship log info) + if (!flagManualPositionUsed && !flagAutoPositionUsed) + { + flagAutoPositionUsed = true; + } + var isBaseSolarSystem = systemName == "SolarSystem"; // Default to MANUAL in Base Solar System (we can't automatically fix them so it might just break, but AUTO breaks even more!) @@ -142,6 +148,7 @@ namespace NewHorizons.Builder.ShipLog astroObject._imageObj = CreateImage(gameObject, image, body.Config.name + " Revealed", layer); astroObject._outlineObj = CreateImage(gameObject, outline, body.Config.name + " Outline", layer); + if (ShipLogHandler.BodyHasEntries(body)) { Image revealedImage = astroObject._imageObj.GetComponent(); @@ -156,6 +163,12 @@ namespace NewHorizons.Builder.ShipLog Rect imageRect = astroObject._imageObj.GetComponent().rect; astroObject._unviewedObj.transform.localPosition = new Vector3(imageRect.width / 2 + unviewedIconOffset, imageRect.height / 2 + unviewedIconOffset, 0); + + // Set all icons inactive, they will be conditionally activated when the map mode is opened for the first time + astroObject._unviewedObj.SetActive(false); + astroObject._imageObj.SetActive(false); + astroObject._outlineObj.SetActive(false); + return astroObject; } #endregion diff --git a/NewHorizons/Components/Fixers/PlayerShipAtmosphereDetectorFix.cs b/NewHorizons/Components/Fixers/PlayerShipAtmosphereDetectorFix.cs new file mode 100644 index 00000000..25d135c1 --- /dev/null +++ b/NewHorizons/Components/Fixers/PlayerShipAtmosphereDetectorFix.cs @@ -0,0 +1,33 @@ +using NewHorizons.Utility.OWML; +using UnityEngine; + +namespace NewHorizons.Components.Fixers; + +/// +/// Fixes a bug where spawning into the ship would not trigger the hatch entryway, so the player could drown if the ship flew into water +/// +internal class PlayerShipAtmosphereDetectorFix : MonoBehaviour +{ + private PlayerCameraFluidDetector _fluidDetector; + private SimpleFluidVolume _shipAtmosphereVolume; + + public void Start() + { + _fluidDetector = Locator.GetPlayerCameraDetector().GetComponent(); + _shipAtmosphereVolume = Locator.GetShipBody().transform.Find("Volumes/ShipAtmosphereVolume").GetComponent(); + } + + public void Update() + { + if (PlayerState.IsInsideShip()) + { + if (!_fluidDetector._activeVolumes.Contains(_shipAtmosphereVolume)) + { + NHLogger.LogVerbose($"{nameof(PlayerShipAtmosphereDetectorFix)} had to add the ship atmosphere volume [{_shipAtmosphereVolume}] to the fluid detector"); + _fluidDetector.AddVolume(_shipAtmosphereVolume); + } + NHLogger.LogVerbose($"{nameof(PlayerShipAtmosphereDetectorFix)} applied its fix"); + Component.Destroy(this); + } + } +} diff --git a/NewHorizons/Components/Orbital/NHAstroObject.cs b/NewHorizons/Components/Orbital/NHAstroObject.cs index ed51060c..cb35f059 100644 --- a/NewHorizons/Components/Orbital/NHAstroObject.cs +++ b/NewHorizons/Components/Orbital/NHAstroObject.cs @@ -14,6 +14,11 @@ namespace NewHorizons.Components.Orbital public bool invulnerableToSun; public bool isVanilla; + /// + /// The unique name of the mod that created this body or, if it is an existing body being edited, the last mod to edit it + /// + public string modUniqueName; + public void SetOrbitalParametersFromConfig(OrbitModule orbit) { SetOrbitalParametersFromTrueAnomaly(orbit.eccentricity, orbit.semiMajorAxis, orbit.inclination, orbit.argumentOfPeriapsis, orbit.longitudeOfAscendingNode, orbit.trueAnomaly); diff --git a/NewHorizons/Components/Props/ConditionalObjectActivation.cs b/NewHorizons/Components/Props/ConditionalObjectActivation.cs index 2fd0cde1..122302cf 100644 --- a/NewHorizons/Components/Props/ConditionalObjectActivation.cs +++ b/NewHorizons/Components/Props/ConditionalObjectActivation.cs @@ -19,6 +19,7 @@ namespace NewHorizons.Components.Props { var conditionalObjectActivationGO = new GameObject($"{go.name}_{condition}"); var component = conditionalObjectActivationGO.AddComponent(); + component.transform.parent = go.transform.parent; component.GameObject = go; component.DialogueCondition = condition; component.CloseEyes = closeEyes; diff --git a/NewHorizons/Components/Props/NHItem.cs b/NewHorizons/Components/Props/NHItem.cs index b21db7ea..bdf3e388 100644 --- a/NewHorizons/Components/Props/NHItem.cs +++ b/NewHorizons/Components/Props/NHItem.cs @@ -19,6 +19,10 @@ namespace NewHorizons.Components.Props public AudioType DropAudio; public AudioType SocketAudio; public AudioType UnsocketAudio; + public Vector3 HoldOffset; + public Vector3 HoldRotation; + public Vector3 SocketOffset; + public Vector3 SocketRotation; public string PickupCondition; public bool ClearPickupConditionOnDrop; public string PickupFact; @@ -42,6 +46,8 @@ namespace NewHorizons.Components.Props public override void PickUpItem(Transform holdTranform) { base.PickUpItem(holdTranform); + transform.localPosition = HoldOffset; + transform.localEulerAngles = HoldRotation; TriggerPickupConditions(); PlayCustomSound(PickupAudio); } @@ -56,6 +62,8 @@ namespace NewHorizons.Components.Props public override void SocketItem(Transform socketTransform, Sector sector) { base.SocketItem(socketTransform, sector); + transform.localPosition = SocketOffset; + transform.localEulerAngles = SocketRotation; TriggerDropConditions(); PlayCustomSound(SocketAudio); } diff --git a/NewHorizons/Components/Sectored/BrambleSectorController.cs b/NewHorizons/Components/Sectored/BrambleSectorController.cs index 3d48e53a..00077c25 100644 --- a/NewHorizons/Components/Sectored/BrambleSectorController.cs +++ b/NewHorizons/Components/Sectored/BrambleSectorController.cs @@ -33,13 +33,16 @@ namespace NewHorizons.Components.Sectored } private void Start() + { + DisableRenderers(); + } + + private void GetRenderers() { _renderers = gameObject.GetComponentsInChildren(); _tessellatedRenderers = gameObject.GetComponentsInChildren(); _colliders = gameObject.GetComponentsInChildren(); _lights = gameObject.GetComponentsInChildren(); - - DisableRenderers(); } private void OnSectorOccupantsUpdated() @@ -54,54 +57,35 @@ namespace NewHorizons.Components.Sectored } } - private void EnableRenderers() + private void EnableRenderers() => ToggleRenderers(true); + + private void DisableRenderers() => ToggleRenderers(false); + + private void ToggleRenderers(bool visible) { + GetRenderers(); + foreach (var renderer in _renderers) { - renderer.forceRenderingOff = false; + renderer.forceRenderingOff = !visible; } foreach (var tessellatedRenderer in _tessellatedRenderers) { - tessellatedRenderer.enabled = true; + tessellatedRenderer.enabled = visible; } foreach (var collider in _colliders) { - collider.enabled = true; + collider.enabled = visible; } foreach (var light in _lights) { - light.enabled = true; + light.enabled = visible; } - _renderersShown = true; - } - - private void DisableRenderers() - { - foreach (var renderer in _renderers) - { - renderer.forceRenderingOff = true; - } - - foreach (var tessellatedRenderer in _tessellatedRenderers) - { - tessellatedRenderer.enabled = false; - } - - foreach (var collider in _colliders) - { - collider.enabled = false; - } - - foreach (var light in _lights) - { - light.enabled = false; - } - - _renderersShown = false; + _renderersShown = visible; } } } diff --git a/NewHorizons/External/Configs/PlanetConfig.cs b/NewHorizons/External/Configs/PlanetConfig.cs index 40a9f7f5..f29c511a 100644 --- a/NewHorizons/External/Configs/PlanetConfig.cs +++ b/NewHorizons/External/Configs/PlanetConfig.cs @@ -213,7 +213,6 @@ namespace NewHorizons.External.Configs // Always have to have a base module if (Base == null) Base = new BaseModule(); if (Orbit == null) Orbit = new OrbitModule(); - if (ShipLog == null) ShipLog = new ShipLogModule(); if (ReferenceFrame == null) ReferenceFrame = new ReferenceFrameModule(); } diff --git a/NewHorizons/External/Modules/Props/Item/ItemInfo.cs b/NewHorizons/External/Modules/Props/Item/ItemInfo.cs index 6307db11..23253119 100644 --- a/NewHorizons/External/Modules/Props/Item/ItemInfo.cs +++ b/NewHorizons/External/Modules/Props/Item/ItemInfo.cs @@ -44,6 +44,22 @@ namespace NewHorizons.External.Modules.Props.Item /// public MVector3 dropNormal; /// + /// A relative offset to apply to the item's position when holding it. The initial position varies for vanilla item types. + /// + public MVector3 holdOffset; + /// + /// A relative offset to apply to the item's rotation when holding it. + /// + public MVector3 holdRotation; + /// + /// A relative offset to apply to the item's position when placing it into a socket. + /// + public MVector3 socketOffset; + /// + /// A relative offset to apply to the item's rotation when placing it into a socket. + /// + public MVector3 socketRotation; + /// /// The audio to play when this item is picked up. Only applies to custom/non-vanilla item types. /// Can be a path to a .wav/.ogg/.mp3 file, or taken from the AudioClip list. /// diff --git a/NewHorizons/External/NewHorizonsData.cs b/NewHorizons/External/NewHorizonsData.cs index b691b622..63a62392 100644 --- a/NewHorizons/External/NewHorizonsData.cs +++ b/NewHorizons/External/NewHorizonsData.cs @@ -1,5 +1,7 @@ using System; using System.Collections.Generic; +using System.Linq; +using NewHorizons.Builder.Props.Audio; using NewHorizons.Utility.OWML; namespace NewHorizons.External @@ -124,7 +126,6 @@ namespace NewHorizons.External if (!KnowsFrequency(frequency)) { _activeProfile.KnownFrequencies.Add(frequency); - Save(); } } @@ -134,13 +135,12 @@ namespace NewHorizons.External if (KnowsFrequency(frequency)) { _activeProfile.KnownFrequencies.Remove(frequency); - Save(); } } public static bool KnowsMultipleFrequencies() { - return _activeProfile != null && _activeProfile.KnownFrequencies.Count > 0; + return _activeProfile?.KnownFrequencies != null && _activeProfile.KnownFrequencies.Count(SignalBuilder.IsFrequencyInUse) > 1; } #endregion @@ -159,7 +159,6 @@ namespace NewHorizons.External if (!KnowsSignal(signal)) { _activeProfile.KnownSignals.Add(signal); - Save(); } } @@ -170,7 +169,6 @@ namespace NewHorizons.External public static void AddNewlyRevealedFactID(string id) { _activeProfile?.NewlyRevealedFactIDs.Add(id); - Save(); } public static List GetNewlyRevealedFactIDs() @@ -181,7 +179,6 @@ namespace NewHorizons.External public static void ClearNewlyRevealedFactIDs() { _activeProfile?.NewlyRevealedFactIDs.Clear(); - Save(); } #endregion @@ -191,7 +188,6 @@ namespace NewHorizons.External public static void ReadOneTimePopup(string id) { _activeProfile?.PopupsRead.Add(id); - Save(); } public static bool HasReadOneTimePopup(string id) @@ -208,7 +204,6 @@ namespace NewHorizons.External { if (name == CharacterDialogueTree.RECORDING_NAME || name == CharacterDialogueTree.SIGN_NAME) return; _activeProfile?.CharactersTalkedTo.SafeAdd(name); - Save(); } public static bool HasTalkedToFiveCharacters() diff --git a/NewHorizons/Handlers/PlanetCreationHandler.cs b/NewHorizons/Handlers/PlanetCreationHandler.cs index a778b8ad..75edb30a 100644 --- a/NewHorizons/Handlers/PlanetCreationHandler.cs +++ b/NewHorizons/Handlers/PlanetCreationHandler.cs @@ -371,7 +371,7 @@ namespace NewHorizons.Handlers const float sphereOfInfluence = 2000f; var owRigidBody = RigidBodyBuilder.Make(go, sphereOfInfluence, body.Config); - var ao = AstroObjectBuilder.Make(go, null, body.Config, false); + var ao = AstroObjectBuilder.Make(go, null, body, false); var sector = SectorBuilder.Make(go, owRigidBody, sphereOfInfluence); ao._rootSector = sector; @@ -447,7 +447,7 @@ namespace NewHorizons.Handlers var sphereOfInfluence = GetSphereOfInfluence(body); var owRigidBody = RigidBodyBuilder.Make(go, sphereOfInfluence, body.Config); - var ao = AstroObjectBuilder.Make(go, primaryBody, body.Config, false); + var ao = AstroObjectBuilder.Make(go, primaryBody, body, false); var sector = SectorBuilder.Make(go, owRigidBody, sphereOfInfluence * 2f); ao._rootSector = sector; @@ -788,7 +788,7 @@ namespace NewHorizons.Handlers } // Just destroy the existing AO after copying everything over - var newAO = AstroObjectBuilder.Make(go, primary, body.Config, true); + var newAO = AstroObjectBuilder.Make(go, primary, body, true); newAO._gravityVolume = ao._gravityVolume; newAO._moon = ao._moon; newAO._name = ao._name; diff --git a/NewHorizons/Handlers/PlayerSpawnHandler.cs b/NewHorizons/Handlers/PlayerSpawnHandler.cs index 22380665..40670ad8 100644 --- a/NewHorizons/Handlers/PlayerSpawnHandler.cs +++ b/NewHorizons/Handlers/PlayerSpawnHandler.cs @@ -115,6 +115,17 @@ namespace NewHorizons.Handlers } // 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 + + // Sometimes the ship isn't added to the volumes it's meant to now be in + foreach (var volume in SpawnPointBuilder.ShipSpawn.GetAttachedOWRigidbody().GetComponentsInChildren()) + { + if (volume.GetOWTriggerVolume().GetPenetrationDistance(ship.transform.position) > 0) + { + // Add ship to volume + // If it's already tracking it it will complain here but thats fine + volume.GetOWTriggerVolume().AddObjectToVolume(Locator.GetShipDetector()); + } + } } } else if (Main.Instance.CurrentStarSystem != "SolarSystem" && !Main.Instance.IsWarpingFromShip) diff --git a/NewHorizons/Handlers/SubtitlesHandler.cs b/NewHorizons/Handlers/SubtitlesHandler.cs index 7207a8a5..d3fe3fb8 100644 --- a/NewHorizons/Handlers/SubtitlesHandler.cs +++ b/NewHorizons/Handlers/SubtitlesHandler.cs @@ -11,8 +11,8 @@ namespace NewHorizons.Handlers { class SubtitlesHandler : MonoBehaviour { - public static int SUBTITLE_HEIGHT = 97; - public static int SUBTITLE_WIDTH = 669; // nice + public static float SUBTITLE_HEIGHT = 97; + public static float SUBTITLE_WIDTH = 669; // nice public float fadeSpeed = 0.005f; public float fade = 1; @@ -45,7 +45,7 @@ namespace NewHorizons.Handlers if (eoteSprite != null) { // Don't make it appear first actually because we have mods to display! - possibleSubtitles.Add(eoteSprite); + possibleSubtitles.Add(eoteSprite); } eoteSubtitleHasBeenInserted = true; } @@ -67,7 +67,7 @@ namespace NewHorizons.Handlers CheckForEOTE(); // We add our subtitles as a child object so that their sizing doesnt shift the layout of the main menu - _subtitleDisplay = new GameObject().AddComponent(); + _subtitleDisplay = new GameObject("SubtitleDisplay").AddComponent(); _subtitleDisplay.transform.parent = transform; _subtitleDisplay.transform.localPosition = new Vector3(0, 0, 0); _subtitleDisplay.transform.localScale = new Vector3(0.75f, 0.75f, 0.75f); @@ -173,9 +173,12 @@ namespace NewHorizons.Handlers { subtitleIndex = (subtitleIndex + 1) % possibleSubtitles.Count; - _subtitleDisplay.sprite = possibleSubtitles[subtitleIndex]; - var ratio = SUBTITLE_WIDTH / _subtitleDisplay.sprite.texture.width; - _subtitleDisplay.rectTransform.sizeDelta = new Vector2(_subtitleDisplay.sprite.texture.width, _subtitleDisplay.sprite.texture.height) * ratio; + var subtitle = possibleSubtitles[subtitleIndex]; + _subtitleDisplay.sprite = subtitle; + var width = subtitle.texture.width; + var height = subtitle.texture.height; + var ratio = SUBTITLE_WIDTH / width; // one of these needs to be a float so that compiler doesn't think "oh 2 integers! let's round to nearest whole" + _subtitleDisplay.rectTransform.sizeDelta = new Vector2(width, height) * ratio; } } } diff --git a/NewHorizons/Handlers/TranslationHandler.cs b/NewHorizons/Handlers/TranslationHandler.cs index d8130aa8..c2f49ebf 100644 --- a/NewHorizons/Handlers/TranslationHandler.cs +++ b/NewHorizons/Handlers/TranslationHandler.cs @@ -2,9 +2,11 @@ using NewHorizons.External.Configs; using NewHorizons.Utility; using NewHorizons.Utility.OWML; using System; +using System.Collections; using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; +using static TextTranslation; namespace NewHorizons.Handlers { @@ -50,30 +52,46 @@ namespace NewHorizons.Handlers } // Get the translated text - if (dictionary.TryGetValue(language, out var table)) + if (TryGetTranslatedText(dictionary, language, text, out var translatedText)) { - if (table.TryGetValue(text, out var translatedText)) + return translatedText; + } + + if (warn) + { + NHLogger.LogVerbose($"Defaulting to english for {text}"); + } + + if (TryGetTranslatedText(dictionary, Language.ENGLISH, text, out translatedText)) + { + return translatedText; + } + + if (warn) + { + NHLogger.LogVerbose($"Defaulting to key for {text}"); + } + + return text; + } + + private static bool TryGetTranslatedText(Dictionary> dict, Language language, string text, out string translatedText) + { + if (dict.TryGetValue(language, out var table)) + { + if (table.TryGetValue(text, out translatedText)) { - return translatedText; + return true; } // Try without whitespace if its missing else if (table.TryGetValue(text.TruncateWhitespaceAndToLower(), out translatedText)) { - return translatedText; + return true; } } - if (warn) NHLogger.LogVerbose($"Defaulting to english for {text}"); - - // Try to default to English - if (dictionary.TryGetValue(TextTranslation.Language.ENGLISH, out var englishTable)) - if (englishTable.TryGetValue(text, out var englishText)) - return englishText; - - if (warn) NHLogger.LogVerbose($"Defaulting to key for {text}"); - - // Default to the key - return text; + translatedText = null; + return false; } public static void RegisterTranslation(TextTranslation.Language language, TranslationConfig config) diff --git a/NewHorizons/INewHorizons.cs b/NewHorizons/INewHorizons.cs index 4dfd2d1f..71337802 100644 --- a/NewHorizons/INewHorizons.cs +++ b/NewHorizons/INewHorizons.cs @@ -1,4 +1,3 @@ -using NewHorizons.Handlers; using OWML.Common; using System; using System.Collections.Generic; diff --git a/NewHorizons/Main.cs b/NewHorizons/Main.cs index db83045f..c8b714c7 100644 --- a/NewHorizons/Main.cs +++ b/NewHorizons/Main.cs @@ -263,7 +263,6 @@ namespace NewHorizons // Call this from the menu since we hadn't hooked onto the event yet Delay.FireOnNextUpdate(() => OnSceneLoaded(SceneManager.GetActiveScene(), LoadSceneMode.Single)); Delay.FireOnNextUpdate(() => _firstLoad = false); - Instance.ModHelper.Menus.PauseMenu.OnInit += DebugReload.InitializePauseMenu; MenuHandler.Init(); AchievementHandler.Init(); @@ -275,6 +274,13 @@ namespace NewHorizons LoadAddonManifest("Assets/addon-manifest.json", this); } + public override void SetupPauseMenu(IPauseMenuManager pauseMenu) + { + base.SetupPauseMenu(pauseMenu); + DebugReload.InitializePauseMenu(pauseMenu); + DebugMenu.InitializePauseMenu(pauseMenu); + } + public void OnDestroy() { NHLogger.Log($"Destroying NewHorizons"); @@ -512,8 +518,10 @@ namespace NewHorizons // We are in a custom system on the first loop -> The time loop isn't active, that's not very good // TimeLoop uses the launch codes condition to know if the loop is active or not + // We also skip them to loop 2, else if they enter a credits volume in this loop they get reset if (CurrentStarSystem != "SolarSystem" && PlayerData.LoadLoopCount() == 1) { + PlayerData.SaveLoopCount(2); PlayerData.SetPersistentCondition("LAUNCH_CODES_GIVEN", true); } } @@ -595,6 +603,7 @@ namespace NewHorizons Locator.GetPlayerBody().gameObject.AddComponent(); Locator.GetPlayerBody().gameObject.AddComponent(); Locator.GetPlayerBody().gameObject.AddComponent(); + Locator.GetPlayerBody().gameObject.AddComponent(); PlayerSpawnHandler.OnSystemReady(shouldWarpInFromShip, shouldWarpInFromVessel); diff --git a/NewHorizons/NewHorizons.csproj b/NewHorizons/NewHorizons.csproj index c1e195b3..e8abb757 100644 --- a/NewHorizons/NewHorizons.csproj +++ b/NewHorizons/NewHorizons.csproj @@ -16,7 +16,7 @@ - + diff --git a/NewHorizons/OtherMods/MenuFramework/IMenuAPI.cs b/NewHorizons/OtherMods/MenuFramework/IMenuAPI.cs deleted file mode 100644 index f44aecdf..00000000 --- a/NewHorizons/OtherMods/MenuFramework/IMenuAPI.cs +++ /dev/null @@ -1,20 +0,0 @@ -using UnityEngine; -using UnityEngine.UI; - -namespace NewHorizons.OtherMods.MenuFramework -{ - public interface IMenuAPI - { - GameObject TitleScreen_MakeMenuOpenButton(string name, int index, Menu menuToOpen); - GameObject TitleScreen_MakeSceneLoadButton(string name, int index, SubmitActionLoadScene.LoadableScenes sceneToLoad, PopupMenu confirmPopup = null); - Button TitleScreen_MakeSimpleButton(string name, int index); - GameObject PauseMenu_MakeMenuOpenButton(string name, Menu menuToOpen, Menu customMenu = null); - GameObject PauseMenu_MakeSceneLoadButton(string name, SubmitActionLoadScene.LoadableScenes sceneToLoad, PopupMenu confirmPopup = null, Menu customMenu = null); - Button PauseMenu_MakeSimpleButton(string name, Menu customMenu = null); - Menu PauseMenu_MakePauseListMenu(string title); - PopupMenu MakeTwoChoicePopup(string message, string confirmText, string cancelText); - PopupInputMenu MakeInputFieldPopup(string message, string placeholderMessage, string confirmText, string cancelText); - PopupMenu MakeInfoPopup(string message, string continueButtonText); - void RegisterStartupPopup(string message); - } -} diff --git a/NewHorizons/OtherMods/MenuFramework/MenuHandler.cs b/NewHorizons/OtherMods/MenuFramework/MenuHandler.cs index 101a0789..1a54fc46 100644 --- a/NewHorizons/OtherMods/MenuFramework/MenuHandler.cs +++ b/NewHorizons/OtherMods/MenuFramework/MenuHandler.cs @@ -11,15 +11,11 @@ namespace NewHorizons.OtherMods.MenuFramework { public static class MenuHandler { - private static IMenuAPI _menuApi; - private static List<(IModBehaviour mod, string message, bool repeat)> _registeredPopups = new(); private static List _failedFiles = new(); public static void Init() { - _menuApi = Main.Instance.ModHelper.Interaction.TryGetModApi("_nebula.MenuFramework"); - TextTranslation.Get().OnLanguageChanged += OnLanguageChanged; } @@ -35,14 +31,14 @@ namespace NewHorizons.OtherMods.MenuFramework Application.version); NHLogger.LogError(warning); - _menuApi.RegisterStartupPopup(warning); + Main.Instance.ModHelper.MenuHelper.PopupMenuManager.RegisterStartupPopup(warning); } foreach(var (mod, message, repeat) in _registeredPopups) { if (repeat || !NewHorizonsData.HasReadOneTimePopup(mod.ModHelper.Manifest.UniqueName)) { - _menuApi.RegisterStartupPopup(TranslationHandler.GetTranslation(message, TranslationHandler.TextType.UI)); + Main.Instance.ModHelper.MenuHelper.PopupMenuManager.RegisterStartupPopup(TranslationHandler.GetTranslation(message, TranslationHandler.TextType.UI)); NewHorizonsData.ReadOneTimePopup(mod.ModHelper.Manifest.UniqueName); } } @@ -52,7 +48,7 @@ namespace NewHorizons.OtherMods.MenuFramework var message = TranslationHandler.GetTranslation("JSON_FAILED_TO_LOAD", TranslationHandler.TextType.UI); var mods = string.Join(",", _failedFiles.Take(10)); if (_failedFiles.Count > 10) mods += "..."; - _menuApi.RegisterStartupPopup(string.Format(message, mods)); + Main.Instance.ModHelper.MenuHelper.PopupMenuManager.RegisterStartupPopup(string.Format(message, mods)); } _registeredPopups.Clear(); diff --git a/NewHorizons/Patches/BrambleProjectionFixPatches.cs b/NewHorizons/Patches/BrambleProjectionFixPatches.cs new file mode 100644 index 00000000..9d41a251 --- /dev/null +++ b/NewHorizons/Patches/BrambleProjectionFixPatches.cs @@ -0,0 +1,26 @@ +using HarmonyLib; + +namespace NewHorizons.Patches; + +/// +/// Bug fix from the Outsider +/// +[HarmonyPatch] +internal class BrambleProjectionFixPatches +{ + [HarmonyPrefix] + [HarmonyPatch(typeof(FogWarpVolume), nameof(FogWarpVolume.WarpDetector))] + public static bool FogWarpVolume_WarpDetector() + { + // Do not warp the player if they have entered the fog via a projection + return !PlayerState.UsingNomaiRemoteCamera(); + } + + [HarmonyPrefix] + [HarmonyPatch(typeof(FogWarpDetector), nameof(FogWarpDetector.FixedUpdate))] + public static bool FogWarpDetector_FixedUpdate() + { + // Do not warp the player if they have entered the fog via a projection + return !PlayerState.UsingNomaiRemoteCamera(); + } +} diff --git a/NewHorizons/Patches/DialoguePatches/RemoteDialogueTriggerPatches.cs b/NewHorizons/Patches/DialoguePatches/RemoteDialogueTriggerPatches.cs index 330e578e..c01240f2 100644 --- a/NewHorizons/Patches/DialoguePatches/RemoteDialogueTriggerPatches.cs +++ b/NewHorizons/Patches/DialoguePatches/RemoteDialogueTriggerPatches.cs @@ -1,4 +1,6 @@ using HarmonyLib; +using System.Collections; +using UnityEngine.InputSystem; namespace NewHorizons.Patches.DialoguePatches { @@ -7,6 +9,29 @@ namespace NewHorizons.Patches.DialoguePatches { private static bool _wasLastDialogueInactive = false; + [HarmonyPostfix] + [HarmonyPatch(nameof(RemoteDialogueTrigger.Awake))] + public static void RemoteDialogueTrigger_Awake(RemoteDialogueTrigger __instance) + { + // Wait for player to be up and moving before allowing them to trigger remote dialogue + // Stops you getting locked into dialogue while waking up + if (OWInput.GetInputMode() != InputMode.Character) + { + __instance._collider.enabled = false; + __instance.StartCoroutine(AwakeCoroutine(__instance)); + } + } + + private static IEnumerator AwakeCoroutine(RemoteDialogueTrigger instance) + { + while (OWInput.GetInputMode() != InputMode.Character) + { + yield return null; + } + + instance._collider.enabled = true; + } + /// /// Should fix a bug where disabled a CharacterDialogueTree makes its related RemoteDialogueTriggers softlock your game /// diff --git a/NewHorizons/Patches/HUDPatches/ProbeHUDMarkerPatches.cs b/NewHorizons/Patches/HUDPatches/ProbeHUDMarkerPatches.cs index 15da0b12..b0c31daa 100644 --- a/NewHorizons/Patches/HUDPatches/ProbeHUDMarkerPatches.cs +++ b/NewHorizons/Patches/HUDPatches/ProbeHUDMarkerPatches.cs @@ -1,6 +1,7 @@ using HarmonyLib; using NewHorizons.Components.Sectored; using NewHorizons.Handlers; +using NewHorizons.Utility.OWML; namespace NewHorizons.Patches.HUDPatches { @@ -27,15 +28,21 @@ namespace NewHorizons.Patches.HUDPatches [HarmonyPatch(nameof(ProbeHUDMarker.RefreshOwnVisibility))] public static bool ProbeHUDMarker_RefreshOwnVisibility(ProbeHUDMarker __instance) { + // Probe marker seems to never appear in the eye or QM in base game (inside eye being past the vortex) ?? at least thats what its code implies bool insideEYE = Locator.GetEyeStateManager() != null && Locator.GetEyeStateManager().IsInsideTheEye(); bool insideQM = __instance._quantumMoon != null && (__instance._quantumMoon.IsPlayerInside() || __instance._quantumMoon.IsProbeInside()); - bool insideRW = Locator.GetRingWorldController() != null && Locator.GetRingWorldController().isPlayerInside == Locator.GetRingWorldController().isProbeInside; - bool insideIP = Locator.GetCloakFieldController() != null && Locator.GetCloakFieldController().isPlayerInsideCloak == Locator.GetCloakFieldController().isProbeInsideCloak; - bool insideCloak = CloakSectorController.isPlayerInside == CloakSectorController.isProbeInside; + + // Either the controllers wtv are null or the player and probe state are the same + bool sameRW = Locator.GetRingWorldController() == null || Locator.GetRingWorldController().isPlayerInside == Locator.GetRingWorldController().isProbeInside; + bool sameIP = Locator.GetCloakFieldController() == null || Locator.GetCloakFieldController().isPlayerInsideCloak == Locator.GetCloakFieldController().isProbeInsideCloak; + bool sameCloak = CloakSectorController.isPlayerInside == CloakSectorController.isProbeInside; bool sameInterference = InterferenceHandler.IsPlayerSameAsProbe(); + bool isActive = __instance.gameObject.activeInHierarchy || __instance._isTLCDuplicate; - __instance._isVisible = isActive && !insideEYE && !insideQM && !__instance._translatorEquipped && !__instance._inConversation && __instance._launched && (__instance._isWearingHelmet || __instance._atFlightConsole) && insideRW && insideIP && insideCloak && sameInterference; + __instance._isVisible = isActive && !insideEYE && !insideQM && !__instance._translatorEquipped + && !__instance._inConversation && __instance._launched && (__instance._isWearingHelmet || __instance._atFlightConsole) + && sameRW && sameIP && sameCloak && sameInterference; if (__instance._canvasMarker != null) __instance._canvasMarker.SetVisibility(__instance._isVisible); diff --git a/NewHorizons/Patches/PlayerPatches/PlayerDataPatches.cs b/NewHorizons/Patches/PlayerPatches/PlayerDataPatches.cs index 16056c7b..6785a8a2 100644 --- a/NewHorizons/Patches/PlayerPatches/PlayerDataPatches.cs +++ b/NewHorizons/Patches/PlayerPatches/PlayerDataPatches.cs @@ -85,12 +85,8 @@ namespace NewHorizons.Patches.PlayerPatches [HarmonyPatch(nameof(PlayerData.KnowsMultipleFrequencies))] public static bool PlayerData_KnowsMultipleFrequencies(ref bool __result) { - if (NewHorizonsData.KnowsMultipleFrequencies()) - { - __result = true; - return false; - } - return true; + __result = NewHorizonsData.KnowsMultipleFrequencies(); + return false; } [HarmonyPrefix] @@ -140,5 +136,12 @@ namespace NewHorizons.Patches.PlayerPatches { NewHorizonsData.Reset(); } + + [HarmonyPostfix] + [HarmonyPatch(nameof(PlayerData.SaveCurrentGame))] + public static void PlayerData_SaveCurrentGame() + { + NewHorizonsData.Save(); + } } } diff --git a/NewHorizons/Patches/ShipLogPatches/ShipLogAstroObjectPatches.cs b/NewHorizons/Patches/ShipLogPatches/ShipLogAstroObjectPatches.cs index ba3c0e33..abfc67a8 100644 --- a/NewHorizons/Patches/ShipLogPatches/ShipLogAstroObjectPatches.cs +++ b/NewHorizons/Patches/ShipLogPatches/ShipLogAstroObjectPatches.cs @@ -25,9 +25,32 @@ namespace NewHorizons.Patches.ShipLogPatches } } + [HarmonyPrefix] + [HarmonyPatch(nameof(ShipLogAstroObject.UpdateState))] + public static bool ShipLogAstroObject_UpdateState_Pre(ShipLogAstroObject __instance) + { + // Custom astro objects might have no entries, in this case they will be permanently hidden + // Just treat it as if it were revealed + if (__instance._entries.Count == 0) + { + __instance._state = ShipLogEntry.State.Explored; + __instance._imageObj.SetActive(true); + __instance._outlineObj?.SetActive(false); + if (__instance._image != null) + { + __instance.SetMaterialGreyscale(false); + __instance._image.color = Color.white; + } + + return false; + } + + return true; + } + [HarmonyPostfix] [HarmonyPatch(nameof(ShipLogAstroObject.UpdateState))] - public static void ShipLogAstroObject_UpdateState(ShipLogAstroObject __instance) + public static void ShipLogAstroObject_UpdateState_Post(ShipLogAstroObject __instance) { Transform detailsParent = __instance.transform.Find("Details"); if (detailsParent != null) diff --git a/NewHorizons/Patches/SignalPatches/SignalscopePatches.cs b/NewHorizons/Patches/SignalPatches/SignalscopePatches.cs index 12c54db5..2b91dc72 100644 --- a/NewHorizons/Patches/SignalPatches/SignalscopePatches.cs +++ b/NewHorizons/Patches/SignalPatches/SignalscopePatches.cs @@ -1,5 +1,6 @@ using HarmonyLib; using NewHorizons.Builder.Props.Audio; +using NewHorizons.Utility.OWML; namespace NewHorizons.Patches.SignalPatches { @@ -19,13 +20,18 @@ namespace NewHorizons.Patches.SignalPatches { var count = SignalBuilder.NumberOfFrequencies; __instance._frequencyFilterIndex += increment; + // Base game does 1 here but we use frequency index 0 as "default" or "???" __instance._frequencyFilterIndex = __instance._frequencyFilterIndex >= count ? 0 : __instance._frequencyFilterIndex; __instance._frequencyFilterIndex = __instance._frequencyFilterIndex < 0 ? count - 1 : __instance._frequencyFilterIndex; var signalFrequency = AudioSignal.IndexToFrequency(__instance._frequencyFilterIndex); + NHLogger.Log($"Changed freq to {signalFrequency} at {__instance._frequencyFilterIndex}"); + // Skip over this frequency - var isUnknown = !PlayerData.KnowsFrequency(signalFrequency) && !(__instance._isUnknownFreqNearby && __instance._unknownFrequency == signalFrequency); - if (isUnknown || !SignalBuilder.IsFrequencyInUse(signalFrequency)) + // Never skip traveler (always known) + var isTraveler = __instance._frequencyFilterIndex == 1; + var isUnknown = !PlayerData.KnowsFrequency(signalFrequency) && (!__instance._isUnknownFreqNearby || __instance._unknownFrequency != signalFrequency); + if (!isTraveler && (isUnknown || !SignalBuilder.IsFrequencyInUse(signalFrequency))) { __instance.SwitchFrequencyFilter(increment); } diff --git a/NewHorizons/Patches/VolumePatches/DestructionVolumePatches.cs b/NewHorizons/Patches/VolumePatches/DestructionVolumePatches.cs index 0dd86a57..3091d1fd 100644 --- a/NewHorizons/Patches/VolumePatches/DestructionVolumePatches.cs +++ b/NewHorizons/Patches/VolumePatches/DestructionVolumePatches.cs @@ -26,5 +26,25 @@ namespace NewHorizons.Patches.VolumePatches return false; } + + /// + /// This method detects Nomai shuttles that are inactive + /// When active, it swaps the position of the NomaiShuttleController and the Rigidbody, so its not found as a child here and explodes continuously forever + /// Just ignore the shuttle if its inactive + /// + [HarmonyPrefix] + [HarmonyPatch(nameof(DestructionVolume.VanishNomaiShuttle))] + public static bool DestructionVolume_VanishNomaiShuttle(DestructionVolume __instance, OWRigidbody shuttleBody, RelativeLocationData entryLocation) + { + if (shuttleBody.GetComponentInChildren() == null) + { + if (__instance._nomaiShuttleBody == shuttleBody) + { + __instance._nomaiShuttleBody = null; + } + return false; + } + return true; + } } } diff --git a/NewHorizons/Schemas/body_schema.json b/NewHorizons/Schemas/body_schema.json index d6356f75..3e9321e8 100644 --- a/NewHorizons/Schemas/body_schema.json +++ b/NewHorizons/Schemas/body_schema.json @@ -1429,6 +1429,22 @@ "description": "The direction the item will be oriented when dropping it on the ground. Defaults to up (0, 1, 0).", "$ref": "#/definitions/MVector3" }, + "holdOffset": { + "description": "A relative offset to apply to the item's position when holding it. The initial position varies for vanilla item types.", + "$ref": "#/definitions/MVector3" + }, + "holdRotation": { + "description": "A relative offset to apply to the item's rotation when holding it.", + "$ref": "#/definitions/MVector3" + }, + "socketOffset": { + "description": "A relative offset to apply to the item's position when placing it into a socket.", + "$ref": "#/definitions/MVector3" + }, + "socketRotation": { + "description": "A relative offset to apply to the item's rotation when placing it into a socket.", + "$ref": "#/definitions/MVector3" + }, "pickupAudio": { "type": "string", "description": "The audio to play when this item is picked up. Only applies to custom/non-vanilla item types.\nCan be a path to a .wav/.ogg/.mp3 file, or taken from the AudioClip list." diff --git a/NewHorizons/Utility/DebugTools/DebugReload.cs b/NewHorizons/Utility/DebugTools/DebugReload.cs index 87dc99cf..cd067d98 100644 --- a/NewHorizons/Utility/DebugTools/DebugReload.cs +++ b/NewHorizons/Utility/DebugTools/DebugReload.cs @@ -3,6 +3,7 @@ using NewHorizons.Utility.Files; using NewHorizons.Utility.OWML; using OWML.Common; using OWML.Common.Menus; +using OWML.Utils; using System; namespace NewHorizons.Utility.DebugTools @@ -10,22 +11,18 @@ namespace NewHorizons.Utility.DebugTools public static class DebugReload { - private static IModButton _reloadButton; + private static SubmitAction _reloadButton; - public static void InitializePauseMenu() + public static void InitializePauseMenu(IPauseMenuManager pauseMenu) { - _reloadButton = Main.Instance.ModHelper.Menus.PauseMenu.OptionsButton.Duplicate(TranslationHandler.GetTranslation("Reload Configs", TranslationHandler.TextType.UI).ToUpper()); - _reloadButton.OnClick += ReloadConfigs; + _reloadButton = pauseMenu.MakeSimpleButton(TranslationHandler.GetTranslation("Reload Configs", TranslationHandler.TextType.UI).ToUpper(), 3, true); + _reloadButton.OnSubmitAction += ReloadConfigs; UpdateReloadButton(); } public static void UpdateReloadButton() { - if (_reloadButton != null) - { - if (Main.Debug) _reloadButton.Show(); - else _reloadButton.Hide(); - } + _reloadButton?.SetButtonVisible(Main.Debug); } private static void ReloadConfigs() diff --git a/NewHorizons/Utility/DebugTools/Menu/DebugMenu.cs b/NewHorizons/Utility/DebugTools/Menu/DebugMenu.cs index 07bd39f6..92e77893 100644 --- a/NewHorizons/Utility/DebugTools/Menu/DebugMenu.cs +++ b/NewHorizons/Utility/DebugTools/Menu/DebugMenu.cs @@ -5,6 +5,7 @@ using NewHorizons.Utility.OWML; using Newtonsoft.Json; using OWML.Common; using OWML.Common.Menus; +using OWML.Utils; using System; using System.Collections.Generic; using System.IO; @@ -15,7 +16,7 @@ namespace NewHorizons.Utility.DebugTools.Menu { class DebugMenu : MonoBehaviour { - private static IModButton pauseMenuButton; + private static SubmitAction pauseMenuButton; public GUIStyle _editorMenuStyle; public GUIStyle _tabBarStyle; @@ -23,7 +24,6 @@ namespace NewHorizons.Utility.DebugTools.Menu internal Vector2 EditorMenuSize = new Vector2(600, 900); bool menuOpen = false; static bool openMenuOnPause; - static bool staticInitialized; // Menu params internal static IModBehaviour loadedMod = null; @@ -34,6 +34,8 @@ namespace NewHorizons.Utility.DebugTools.Menu // Submenus private List submenus; private int activeSubmenu = 0; + + private static DebugMenu _instance; internal static JsonSerializerSettings jsonSettings = new JsonSerializerSettings { @@ -55,28 +57,13 @@ namespace NewHorizons.Utility.DebugTools.Menu private void Start() { - if (!staticInitialized) - { - staticInitialized = true; + _instance = this; - Main.Instance.ModHelper.Menus.PauseMenu.OnInit += PauseMenuInitHook; - Main.Instance.ModHelper.Menus.PauseMenu.OnClosed += CloseMenu; - Main.Instance.ModHelper.Menus.PauseMenu.OnOpened += RestoreMenuOpennessState; + Main.Instance.ModHelper.MenuHelper.PauseMenuManager.PauseMenuOpened += OnOpenMenu; + Main.Instance.ModHelper.MenuHelper.PauseMenuManager.PauseMenuClosed += OnCloseMenu; + Main.Instance.OnChangeStarSystem.AddListener(OnChangeStarSystem); - PauseMenuInitHook(); - - Main.Instance.OnChangeStarSystem.AddListener((string s) => { - if (saveButtonUnlocked) - { - SaveLoadedConfigsForRecentSystem(); - saveButtonUnlocked = false; - } - }); - } - else - { - InitMenu(); - } + InitMenu(); if (loadedMod != null) { @@ -84,26 +71,38 @@ namespace NewHorizons.Utility.DebugTools.Menu } } - private void PauseMenuInitHook() + public void OnDestroy() { - pauseMenuButton = Main.Instance.ModHelper.Menus.PauseMenu.OptionsButton.Duplicate(TranslationHandler.GetTranslation("Toggle Dev Tools Menu", TranslationHandler.TextType.UI).ToUpper()); - InitMenu(); + Main.Instance.ModHelper.MenuHelper.PauseMenuManager.PauseMenuOpened -= OnOpenMenu; + Main.Instance.ModHelper.MenuHelper.PauseMenuManager.PauseMenuClosed -= OnCloseMenu; + Main.Instance.OnChangeStarSystem.RemoveListener(OnChangeStarSystem); + } + + private void OnChangeStarSystem(string _) + { + if (saveButtonUnlocked) + { + SaveLoadedConfigsForRecentSystem(); + saveButtonUnlocked = false; + } + } + + public static void InitializePauseMenu(IPauseMenuManager pauseMenu) + { + pauseMenuButton = pauseMenu.MakeSimpleButton(TranslationHandler.GetTranslation("Toggle Dev Tools Menu", TranslationHandler.TextType.UI).ToUpper(), 3, true); + _instance?.InitMenu(); } public static void UpdatePauseMenuButton() { - if (pauseMenuButton != null) - { - if (Main.Debug) pauseMenuButton.Show(); - else pauseMenuButton.Hide(); - } + pauseMenuButton?.SetButtonVisible(Main.Debug); } - private void RestoreMenuOpennessState() { menuOpen = openMenuOnPause; } + private void OnOpenMenu() { menuOpen = openMenuOnPause; } private void ToggleMenu() { menuOpen = !menuOpen; openMenuOnPause = !openMenuOnPause; } - private void CloseMenu() { menuOpen = false; } + private void OnCloseMenu() { menuOpen = false; } private void OnGUI() { @@ -284,7 +283,7 @@ namespace NewHorizons.Utility.DebugTools.Menu UpdatePauseMenuButton(); // TODO: figure out how to clear this event list so that we don't pile up useless instances of the DebugMenu that can't get garbage collected - pauseMenuButton.OnClick += ToggleMenu; + pauseMenuButton.OnSubmitAction += ToggleMenu; submenus.ForEach(submenu => submenu.OnInit(this)); diff --git a/NewHorizons/Utility/OWML/NHLogger.cs b/NewHorizons/Utility/OWML/NHLogger.cs index 080cdcad..c539f43f 100644 --- a/NewHorizons/Utility/OWML/NHLogger.cs +++ b/NewHorizons/Utility/OWML/NHLogger.cs @@ -19,10 +19,17 @@ namespace NewHorizons.Utility.OWML Main.Instance.ModHelper.Console.WriteLine($"{Enum.GetName(typeof(LogType), type)} : {text}", LogTypeToMessageType(type)); } + public static void LogVerbose(params object[] obj) => LogVerbose(string.Join(", ", obj)); public static void LogVerbose(object text) => Log(text, LogType.Verbose); + public static void Log(object text) => Log(text, LogType.Log); + public static void Log(params object[] obj) => Log(string.Join(", ", obj)); + public static void LogWarning(object text) => Log(text, LogType.Warning); + public static void LogWarning(params object[] obj) => LogWarning(string.Join(", ", obj)); + public static void LogError(object text) => Log(text, LogType.Error); + public static void LogError(params object[] obj) => LogError(string.Join(", ", obj)); public enum LogType { diff --git a/NewHorizons/manifest.json b/NewHorizons/manifest.json index 1feb5fcd..224a5735 100644 --- a/NewHorizons/manifest.json +++ b/NewHorizons/manifest.json @@ -4,9 +4,9 @@ "author": "xen, Bwc9876, JohnCorby, MegaPiggy, Clay, Trifid, and friends", "name": "New Horizons", "uniqueName": "xen.NewHorizons", - "version": "1.19.3", - "owmlVersion": "2.9.8", - "dependencies": [ "JohnCorby.VanillaFix", "_nebula.MenuFramework", "xen.CommonCameraUtility", "dgarro.CustomShipLogModes" ], + "version": "1.19.9", + "owmlVersion": "2.10.3", + "dependencies": [ "JohnCorby.VanillaFix", "xen.CommonCameraUtility", "dgarro.CustomShipLogModes" ], "conflicts": [ "Raicuparta.QuantumSpaceBuddies", "PacificEngine.OW_CommonResources" ], "pathsToPreserve": [ "planets", "systems", "translations" ], "donateLink": "https://www.patreon.com/ownh" diff --git a/docs/src/content/docs/start-here/getting-started.md b/docs/src/content/docs/start-here/getting-started.md index c2c8fbd2..c37163bb 100644 --- a/docs/src/content/docs/start-here/getting-started.md +++ b/docs/src/content/docs/start-here/getting-started.md @@ -30,7 +30,7 @@ Once in VSCode, paste this code into the file: ```json title="wetrock.json" { "name": "Wetrock", - "$schema": "https://raw.githubusercontent.com/Outer-Wilds-New-Horizons/new-horizons/main/NewHorizons/Schemas/body_schema.json", + "$schema": "https://raw.githubusercontent.com/Outer-Wilds-New-Horizons/new-horizons/main/NewHorizons/Schemas/body_schema.json", "starSystem": "SolarSystem", "Base": { "groundSize": 100,