mirror of
https://github.com/Outer-Wilds-New-Horizons/new-horizons.git
synced 2025-12-11 20:15:44 +01:00
Merge branch 'dev' into scene-load-fixes
This commit is contained in:
commit
ff999c271c
Binary file not shown.
|
Before Width: | Height: | Size: 127 KiB After Width: | Height: | Size: 128 KiB |
@ -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)
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
using NewHorizons.External.Modules;
|
||||
using NewHorizons.External.Modules.VariableSize;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NewHorizons.Builder.Atmosphere
|
||||
{
|
||||
public static class SunOverrideBuilder
|
||||
|
||||
@ -408,10 +408,15 @@ namespace NewHorizons.Builder.Body
|
||||
if (starModule.endTint != null)
|
||||
{
|
||||
var endColour = starModule.endTint.ToColor();
|
||||
darkenedColor = new Color(endColour.r * modifier, endColour.g * modifier, endColour.b * modifier);
|
||||
var adjustedEndColour = new Color(endColour.r * modifier, endColour.g * modifier, endColour.b * modifier);
|
||||
Color.RGBToHSV(adjustedEndColour, out var hEnd, out var sEnd, out var vEnd);
|
||||
var darkenedEndColor = Color.HSVToRGB(hEnd, sEnd * 1.2f, vEnd * 0.1f);
|
||||
surface.sharedMaterial.SetTexture(ColorRamp, ImageUtilities.LerpGreyscaleImageAlongX(_colorOverTime, adjustedColour, darkenedColor, adjustedEndColour, darkenedEndColor));
|
||||
}
|
||||
else
|
||||
{
|
||||
surface.sharedMaterial.SetTexture(ColorRamp, ImageUtilities.LerpGreyscaleImage(_colorOverTime, adjustedColour, darkenedColor));
|
||||
}
|
||||
|
||||
surface.sharedMaterial.SetTexture(ColorRamp, ImageUtilities.LerpGreyscaleImage(_colorOverTime, adjustedColour, darkenedColor));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(starModule.starRampTexture))
|
||||
|
||||
@ -135,7 +135,8 @@ namespace NewHorizons.Builder.Body
|
||||
var fogGO = Object.Instantiate(_oceanFog, waterGO.transform);
|
||||
fogGO.name = "OceanFog";
|
||||
fogGO.transform.localPosition = Vector3.zero;
|
||||
fogGO.transform.localScale = Vector3.one;
|
||||
// In base game GD ocean fog is 550 while the water volume is 500
|
||||
fogGO.transform.localScale = Vector3.one * 550f / 500f;
|
||||
fogGO.SetActive(true);
|
||||
|
||||
if (module.tint != null)
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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<SignalFrequency>().Length;
|
||||
|
||||
_qmSignals = new (){ SearchUtilities.Find("QuantumMoon_Body/Signal_Quantum").GetComponent<AudioSignal>() };
|
||||
_qmSignals = new () { SearchUtilities.Find("QuantumMoon_Body/Signal_Quantum").GetComponent<AudioSignal>() };
|
||||
_cloakedSignals = new();
|
||||
|
||||
Initialized = true;
|
||||
|
||||
SceneManager.sceneUnloaded -= OnSceneUnloaded;
|
||||
SceneManager.sceneUnloaded += OnSceneUnloaded;
|
||||
Main.Instance.OnStarSystemLoaded.RemoveListener(OnStarSystemLoaded);
|
||||
Main.Instance.OnStarSystemLoaded.AddListener(OnStarSystemLoaded);
|
||||
}
|
||||
|
||||
private static HashSet<SignalFrequency> _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<SignalFrequency> _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<SignalFrequency>(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<SignalFrequency>().Length;
|
||||
|
||||
// This stuff happens after the signalscope is Awake so we have to change the number of frequencies now
|
||||
Object.FindObjectOfType<Signalscope>()._strongestSignals = new AudioSignal[NumberOfFrequencies + 1];
|
||||
GameObject.FindObjectOfType<Signalscope>()._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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
@ -33,12 +34,17 @@ namespace NewHorizons.Builder.Props
|
||||
private static GameObject _brambleSeedPrefab;
|
||||
private static GameObject _brambleNodePrefab;
|
||||
|
||||
private static HashSet<FogWarpVolume> _nhFogWarpVolumes = new();
|
||||
|
||||
public static bool IsNHFogWarpVolume(FogWarpVolume volume) => _nhFogWarpVolumes.Contains(volume);
|
||||
|
||||
public static void Init(PlanetConfig[] dimensionConfigs)
|
||||
{
|
||||
_unpairedNodes.Clear();
|
||||
_propagatedSignals.Clear();
|
||||
namedNodes.Clear();
|
||||
builtBrambleNodes.Clear();
|
||||
_nhFogWarpVolumes.Clear();
|
||||
|
||||
PropagateSignals(dimensionConfigs);
|
||||
}
|
||||
@ -190,6 +196,12 @@ namespace NewHorizons.Builder.Props
|
||||
collider.enabled = true;
|
||||
}
|
||||
|
||||
// We track all the fog warp volumes that NH created so we can only effect those in patches, this way we leave base game stuff alone.
|
||||
foreach (var fogWarpVolume in brambleNode.GetComponentsInChildren<FogWarpVolume>(true).Append(brambleNode.GetComponent<FogWarpVolume>()))
|
||||
{
|
||||
_nhFogWarpVolumes.Add(fogWarpVolume);
|
||||
}
|
||||
|
||||
var innerFogWarpVolume = brambleNode.GetComponent<InnerFogWarpVolume>();
|
||||
var outerFogWarpVolume = GetOuterFogWarpVolumeFromAstroObject(go);
|
||||
var fogLight = brambleNode.GetComponent<FogLight>();
|
||||
@ -239,6 +251,12 @@ namespace NewHorizons.Builder.Props
|
||||
foreach(Transform child in brambleNode.transform)
|
||||
{
|
||||
child.localScale = Vector3.one * config.scale;
|
||||
|
||||
// The fog on bramble seeds has a specific scale we need to copy over
|
||||
if (child.name == "VolumetricFogSphere (2)")
|
||||
{
|
||||
child.localScale *= 6.3809f;
|
||||
}
|
||||
}
|
||||
innerFogWarpVolume._warpRadius *= config.scale;
|
||||
innerFogWarpVolume._exitRadius *= config.scale;
|
||||
@ -397,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<SignalInfo>(JsonConvert.SerializeObject(signalConfig));
|
||||
signalConfigCopy.parentPath = null;
|
||||
signalConfigCopy.isRelativeToParent = false;
|
||||
|
||||
var signalGO = SignalBuilder.Make(go, sector, signalConfigCopy, mod);
|
||||
signalGO.GetComponent<AudioSignal>()._identificationDistance = 0;
|
||||
signalGO.GetComponent<AudioSignal>()._sourceRadius = 1;
|
||||
signalGO.transform.position = brambleNode.transform.position;
|
||||
|
||||
@ -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,7 +140,23 @@ 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 (isFromAssetBundle && component is CharacterDialogueTree dialogue)
|
||||
{
|
||||
DialogueBuilder.AddTranslation(dialogue._xmlCharacterDialogueAsset.text, null);
|
||||
}
|
||||
|
||||
FixComponent(component, go, detail.ignoreSun);
|
||||
@ -171,6 +188,11 @@ namespace NewHorizons.Builder.Props
|
||||
if (detail.item != null)
|
||||
{
|
||||
ItemBuilder.MakeItem(prop, go, sector, detail.item, mod);
|
||||
isItem = true;
|
||||
if (detail.hasPhysics)
|
||||
{
|
||||
NHLogger.LogWarning($"An item with the path {detail.path} has both '{nameof(DetailInfo.hasPhysics)}' and '{nameof(DetailInfo.item)}' set. This will usually result in undesirable behavior.");
|
||||
}
|
||||
}
|
||||
|
||||
if (detail.itemSocket != null)
|
||||
@ -266,16 +288,8 @@ namespace NewHorizons.Builder.Props
|
||||
/// <summary>
|
||||
/// Fix components that have sectors. Has a specific fix if there is a VisionTorchItem on the object.
|
||||
/// </summary>
|
||||
private static void FixSectoredComponent(Component component, Sector sector, HashSet<Sector> existingSectors, bool keepLoaded)
|
||||
private static void FixSectoredComponent(Component component, Sector sector, HashSet<Sector> 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()))
|
||||
{
|
||||
@ -283,26 +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 SectorCullGroup sectorCullGroup)
|
||||
{
|
||||
sectorCullGroup._controllingProxy = null;
|
||||
|
||||
// fixes sector cull group deactivating renderers on map view enter and fast foward
|
||||
// TODO: does this actually work? what? how?
|
||||
sectorCullGroup._inMapView = false;
|
||||
sectorCullGroup._isFastForwarding = false;
|
||||
sectorCullGroup.SetVisible(sectorCullGroup.ShouldBeVisible(), true, false);
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
@ -376,7 +376,7 @@ namespace NewHorizons.Builder.Props
|
||||
}
|
||||
}
|
||||
|
||||
private static void AddTranslation(string xml, string characterName = null)
|
||||
public static void AddTranslation(string xml, string characterName = null)
|
||||
{
|
||||
var xmlDocument = new XmlDocument();
|
||||
xmlDocument.LoadXml(xml);
|
||||
|
||||
@ -79,6 +79,12 @@ namespace NewHorizons.Builder.Props
|
||||
item.ClearPickupConditionOnDrop = info.clearPickupConditionOnDrop;
|
||||
item.PickupFact = info.pickupFact;
|
||||
|
||||
if (info.colliderRadius > 0f)
|
||||
{
|
||||
go.AddComponent<SphereCollider>().radius = info.colliderRadius;
|
||||
go.GetAddComponent<OWCollider>();
|
||||
}
|
||||
|
||||
Delay.FireOnNextUpdate(() =>
|
||||
{
|
||||
if (item != null && !string.IsNullOrEmpty(info.pathToInitialSocket))
|
||||
|
||||
@ -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<Image>();
|
||||
@ -156,6 +163,12 @@ namespace NewHorizons.Builder.ShipLog
|
||||
|
||||
Rect imageRect = astroObject._imageObj.GetComponent<RectTransform>().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
|
||||
|
||||
@ -0,0 +1,33 @@
|
||||
using NewHorizons.Utility.OWML;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NewHorizons.Components.Fixers;
|
||||
|
||||
/// <summary>
|
||||
/// 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
|
||||
/// </summary>
|
||||
internal class PlayerShipAtmosphereDetectorFix : MonoBehaviour
|
||||
{
|
||||
private PlayerCameraFluidDetector _fluidDetector;
|
||||
private SimpleFluidVolume _shipAtmosphereVolume;
|
||||
|
||||
public void Start()
|
||||
{
|
||||
_fluidDetector = Locator.GetPlayerCameraDetector().GetComponent<PlayerCameraFluidDetector>();
|
||||
_shipAtmosphereVolume = Locator.GetShipBody().transform.Find("Volumes/ShipAtmosphereVolume").GetComponent<SimpleFluidVolume>();
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -19,6 +19,7 @@ namespace NewHorizons.Components.Props
|
||||
{
|
||||
var conditionalObjectActivationGO = new GameObject($"{go.name}_{condition}");
|
||||
var component = conditionalObjectActivationGO.AddComponent<ConditionalObjectActivation>();
|
||||
component.transform.parent = go.transform.parent;
|
||||
component.GameObject = go;
|
||||
component.DialogueCondition = condition;
|
||||
component.CloseEyes = closeEyes;
|
||||
|
||||
@ -33,13 +33,16 @@ namespace NewHorizons.Components.Sectored
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
DisableRenderers();
|
||||
}
|
||||
|
||||
private void GetRenderers()
|
||||
{
|
||||
_renderers = gameObject.GetComponentsInChildren<Renderer>();
|
||||
_tessellatedRenderers = gameObject.GetComponentsInChildren<TessellatedRenderer>();
|
||||
_colliders = gameObject.GetComponentsInChildren<Collider>();
|
||||
_lights = gameObject.GetComponentsInChildren<Light>();
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -13,6 +13,9 @@ namespace NewHorizons.Components
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// So that mods can turn the time loop on/off using the TimLoop.SetTimeLoopEnabled method
|
||||
if (!TimeLoop._timeLoopEnabled) return;
|
||||
|
||||
// Stock gives like 33 seconds after the sun collapses
|
||||
if (_supernovaHappened && Time.time > _supernovaTime + 50f)
|
||||
{
|
||||
|
||||
@ -1,8 +0,0 @@
|
||||
namespace NewHorizons.Components.Volumes
|
||||
{
|
||||
public class NHInnerFogWarpVolume : InnerFogWarpVolume
|
||||
{
|
||||
public override bool IsProbeOnly() => _exitRadius <= 6;
|
||||
public override float GetFogThickness() => _exitRadius;
|
||||
}
|
||||
}
|
||||
@ -1,3 +1,4 @@
|
||||
using NewHorizons.Utility.OWML;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NewHorizons.Components.Volumes
|
||||
@ -23,6 +24,23 @@ namespace NewHorizons.Components.Volumes
|
||||
|
||||
public void FixedUpdate()
|
||||
{
|
||||
// Bug report on Astral Codec mod page - Huge lag inside streaming warp volume, possible NRE?
|
||||
if (_probe == null)
|
||||
{
|
||||
_probe = Locator.GetProbe();
|
||||
if (_probe == null)
|
||||
{
|
||||
NHLogger.LogError($"How is your scout probe null? Destroying {nameof(StreamingWarpVolume)}");
|
||||
GameObject.DestroyImmediate(gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
if (streamingGroup == null)
|
||||
{
|
||||
NHLogger.LogError($"{nameof(StreamingWarpVolume)} has no streaming group. Destroying {nameof(StreamingWarpVolume)}");
|
||||
GameObject.DestroyImmediate(gameObject);
|
||||
}
|
||||
|
||||
bool probeActive = _probe.IsLaunched() && !_probe.IsAnchored();
|
||||
|
||||
bool shouldBeLoadingRequiredAssets = _playerInVolume || (_probeInVolume && probeActive);
|
||||
|
||||
1
NewHorizons/External/Configs/PlanetConfig.cs
vendored
1
NewHorizons/External/Configs/PlanetConfig.cs
vendored
@ -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();
|
||||
}
|
||||
|
||||
|
||||
@ -54,7 +54,9 @@ namespace NewHorizons.External.Modules.Props
|
||||
public string quantumGroupID;
|
||||
|
||||
/// <summary>
|
||||
/// Should this detail stay loaded even if you're outside the sector (good for very large props)
|
||||
/// Should this detail stay loaded (visible and collideable) even if you're outside the sector (good for very large props)?
|
||||
/// Also makes this detail visible on the map.
|
||||
/// Most logic/behavior scripts will still only work inside the sector, as most of those scripts break if a sector is not provided.
|
||||
/// </summary>
|
||||
public bool keepLoaded;
|
||||
|
||||
|
||||
@ -19,7 +19,7 @@ namespace NewHorizons.External.Modules.Props.Item
|
||||
/// </summary>
|
||||
public string name;
|
||||
/// <summary>
|
||||
/// The type of the item, which determines its orientation when held and what sockets it fits into. This can be a custom string, or a vanilla ItemType (Scroll, WarpCode, SharedStone, ConversationStone, Lantern, SlideReel, DreamLantern, or VisionTorch). Defaults to the item name.
|
||||
/// The type of the item, which determines its orientation when held and what sockets it fits into. This can be a custom string, or a vanilla ItemType (Scroll, WarpCore, SharedStone, ConversationStone, Lantern, SlideReel, DreamLantern, or VisionTorch). Defaults to the item name.
|
||||
/// </summary>
|
||||
public string itemType;
|
||||
/// <summary>
|
||||
@ -27,6 +27,11 @@ namespace NewHorizons.External.Modules.Props.Item
|
||||
/// </summary>
|
||||
[DefaultValue(2f)] public float interactRange = 2f;
|
||||
/// <summary>
|
||||
/// The radius that the added sphere collider will use for collision and hover detection.
|
||||
/// If there's already a collider on the detail, you can make this 0.
|
||||
/// </summary>
|
||||
[DefaultValue(0.5f)] public float colliderRadius = 0.5f;
|
||||
/// <summary>
|
||||
/// Whether the item can be dropped. Defaults to true.
|
||||
/// </summary>
|
||||
[DefaultValue(true)] public bool droppable = true;
|
||||
|
||||
11
NewHorizons/External/NewHorizonsData.cs
vendored
11
NewHorizons/External/NewHorizonsData.cs
vendored
@ -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<string> 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()
|
||||
|
||||
@ -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<EffectVolume>())
|
||||
{
|
||||
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)
|
||||
|
||||
@ -11,11 +11,8 @@ namespace NewHorizons.Handlers
|
||||
{
|
||||
class SubtitlesHandler : MonoBehaviour
|
||||
{
|
||||
public static int SUBTITLE_HEIGHT = 97;
|
||||
public static int SUBTITLE_WIDTH = 669; // nice
|
||||
|
||||
public Graphic graphic;
|
||||
public Image image;
|
||||
public static float SUBTITLE_HEIGHT = 97;
|
||||
public static float SUBTITLE_WIDTH = 669; // nice
|
||||
|
||||
public float fadeSpeed = 0.005f;
|
||||
public float fade = 1;
|
||||
@ -29,13 +26,27 @@ namespace NewHorizons.Handlers
|
||||
public static readonly int PAUSE_TIMER_MAX = 50;
|
||||
public int pauseTimer = PAUSE_TIMER_MAX;
|
||||
|
||||
private Image _subtitleDisplay;
|
||||
private Graphic _graphic;
|
||||
|
||||
private static List<(IModBehaviour mod, string filePath)> _additionalSubtitles = new();
|
||||
|
||||
public static void RegisterAdditionalSubtitle(IModBehaviour mod, string filePath)
|
||||
{
|
||||
_additionalSubtitles.Add((mod, filePath));
|
||||
}
|
||||
|
||||
public void CheckForEOTE()
|
||||
{
|
||||
if (!eoteSubtitleHasBeenInserted)
|
||||
{
|
||||
if (Main.HasDLC)
|
||||
{
|
||||
if (eoteSprite != null) possibleSubtitles.Insert(0, eoteSprite); // ensure that the Echoes of the Eye subtitle always appears first
|
||||
if (eoteSprite != null)
|
||||
{
|
||||
// Don't make it appear first actually because we have mods to display!
|
||||
possibleSubtitles.Add(eoteSprite);
|
||||
}
|
||||
eoteSubtitleHasBeenInserted = true;
|
||||
}
|
||||
}
|
||||
@ -43,18 +54,25 @@ namespace NewHorizons.Handlers
|
||||
|
||||
public void Start()
|
||||
{
|
||||
// We preserve the current image to add it to our custom subtitle
|
||||
// We also need this element to preserve its size
|
||||
GetComponent<CanvasGroup>().alpha = 1;
|
||||
graphic = GetComponent<Graphic>();
|
||||
image = GetComponent<UnityEngine.UI.Image>();
|
||||
|
||||
graphic.enabled = true;
|
||||
image.enabled = true;
|
||||
|
||||
var image = GetComponent<Image>();
|
||||
eoteSprite = image.sprite;
|
||||
image.sprite = null;
|
||||
image.enabled = false;
|
||||
var layout = GetComponent<LayoutElement>();
|
||||
layout.minHeight = SUBTITLE_HEIGHT;
|
||||
|
||||
CheckForEOTE();
|
||||
|
||||
image.sprite = null; // Just in case. I don't know how not having the dlc changes the subtitle game object
|
||||
// We add our subtitles as a child object so that their sizing doesnt shift the layout of the main menu
|
||||
_subtitleDisplay = new GameObject("SubtitleDisplay").AddComponent<Image>();
|
||||
_subtitleDisplay.transform.parent = transform;
|
||||
_subtitleDisplay.transform.localPosition = new Vector3(0, 0, 0);
|
||||
_subtitleDisplay.transform.localScale = new Vector3(0.75f, 0.75f, 0.75f);
|
||||
_graphic = _subtitleDisplay.gameObject.GetAddComponent<Graphic>();
|
||||
_subtitleDisplay.gameObject.GetAddComponent<LayoutElement>().minWidth = SUBTITLE_WIDTH;
|
||||
|
||||
AddSubtitles();
|
||||
}
|
||||
@ -73,6 +91,10 @@ namespace NewHorizons.Handlers
|
||||
AddSubtitle(mod, "subtitle.png");
|
||||
}
|
||||
}
|
||||
foreach (var pair in _additionalSubtitles)
|
||||
{
|
||||
AddSubtitle(pair.mod, pair.filePath);
|
||||
}
|
||||
}
|
||||
|
||||
public void AddSubtitle(IModBehaviour mod, string filepath)
|
||||
@ -82,7 +104,7 @@ namespace NewHorizons.Handlers
|
||||
var tex = ImageUtilities.GetTexture(mod, filepath, false);
|
||||
if (tex == null) return;
|
||||
|
||||
var sprite = Sprite.Create(tex, new Rect(0.0f, 0.0f, tex.width, SUBTITLE_HEIGHT), new Vector2(0.5f, 0.5f), 100.0f);
|
||||
var sprite = Sprite.Create(tex, new Rect(0.0f, 0.0f, tex.width, Mathf.Max(SUBTITLE_HEIGHT, tex.height)), new Vector2(0.5f, 0.5f), 100.0f);
|
||||
AddSubtitle(sprite);
|
||||
}
|
||||
|
||||
@ -95,12 +117,25 @@ namespace NewHorizons.Handlers
|
||||
{
|
||||
CheckForEOTE();
|
||||
|
||||
if (possibleSubtitles.Count == 0) return;
|
||||
if (possibleSubtitles.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (image.sprite == null) image.sprite = possibleSubtitles[0];
|
||||
_subtitleDisplay.transform.localPosition = new Vector3(0, -36, 0);
|
||||
|
||||
if (_subtitleDisplay.sprite == null)
|
||||
{
|
||||
_subtitleDisplay.sprite = possibleSubtitles[0];
|
||||
// Always call this in case we stop changing subtitles after
|
||||
ChangeSubtitle();
|
||||
}
|
||||
|
||||
// don't fade transition subtitles if there's only one subtitle
|
||||
if (possibleSubtitles.Count <= 1) return;
|
||||
if (possibleSubtitles.Count <= 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (pauseTimer > 0)
|
||||
{
|
||||
@ -111,7 +146,7 @@ namespace NewHorizons.Handlers
|
||||
if (fadingAway)
|
||||
{
|
||||
fade -= fadeSpeed;
|
||||
|
||||
|
||||
if (fade <= 0)
|
||||
{
|
||||
fade = 0;
|
||||
@ -122,7 +157,7 @@ namespace NewHorizons.Handlers
|
||||
else
|
||||
{
|
||||
fade += fadeSpeed;
|
||||
|
||||
|
||||
if (fade >= 1)
|
||||
{
|
||||
fade = 1;
|
||||
@ -131,14 +166,19 @@ namespace NewHorizons.Handlers
|
||||
}
|
||||
}
|
||||
|
||||
graphic.color = new Color(1, 1, 1, fade);
|
||||
_graphic.color = new Color(1, 1, 1, fade);
|
||||
}
|
||||
|
||||
public void ChangeSubtitle()
|
||||
{
|
||||
subtitleIndex = (subtitleIndex + 1) % possibleSubtitles.Count;
|
||||
|
||||
image.sprite = possibleSubtitles[subtitleIndex];
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -34,7 +34,8 @@ namespace NewHorizons.Handlers
|
||||
if (Main.Instance.CurrentStarSystem == "EyeOfTheUniverse") return;
|
||||
|
||||
// Small mod compat change for StopTime - do nothing if it's enabled
|
||||
if (system.Config.enableTimeLoop && !OtherModUtil.IsEnabled("_nebula.StopTime"))
|
||||
// Do not add our custom time loop controller in the base game system: It will handle itself
|
||||
if (Main.Instance.CurrentStarSystem != "SolarSystem" && system.Config.enableTimeLoop && !OtherModUtil.IsEnabled("_nebula.StopTime"))
|
||||
{
|
||||
var timeLoopController = new GameObject("TimeLoopController");
|
||||
timeLoopController.AddComponent<TimeLoopController>();
|
||||
|
||||
@ -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<Language, Dictionary<string, string>> 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.TruncateWhitespace(), out translatedText))
|
||||
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)
|
||||
@ -99,7 +117,7 @@ namespace NewHorizons.Handlers
|
||||
// Fix new lines in dialogue translations, remove whitespace from keys else if the dialogue has weird whitespace and line breaks it gets really annoying
|
||||
// to write translation keys for (can't just copy paste out of xml, have to start adding \\n and \\r and stuff
|
||||
// If any of these issues become relevant to other dictionaries we can bring this code over, but for now why fix what isnt broke
|
||||
var key = originalKey.Replace("\\n", "\n").TruncateWhitespace().Replace("<", "<").Replace(">", ">").Replace("<![CDATA[", "").Replace("]]>", "");
|
||||
var key = originalKey.Replace("\\n", "\n").Replace("<", "<").Replace(">", ">").Replace("<![CDATA[", "").Replace("]]>", "").TruncateWhitespaceAndToLower();
|
||||
var value = config.DialogueDictionary[originalKey].Replace("\\n", "\n").Replace("<", "<").Replace(">", ">").Replace("<![CDATA[", "").Replace("]]>", "");
|
||||
|
||||
if (!_dialogueTranslationDictionary[language].ContainsKey(key)) _dialogueTranslationDictionary[language].Add(key, value);
|
||||
|
||||
@ -207,5 +207,13 @@ namespace NewHorizons
|
||||
/// <returns></returns>
|
||||
string GetTranslationForOtherText(string text);
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Registers a subtitle for the main menu.
|
||||
/// Call this once before the main menu finishes loading
|
||||
/// </summary>
|
||||
/// <param name="mod"></param>
|
||||
/// <param name="filePath"></param>
|
||||
void AddSubtitle(IModBehaviour mod, string filePath);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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<DebugRaycaster>();
|
||||
Locator.GetPlayerBody().gameObject.AddComponent<DebugPropPlacer>();
|
||||
Locator.GetPlayerBody().gameObject.AddComponent<DebugMenu>();
|
||||
Locator.GetPlayerBody().gameObject.AddComponent<PlayerShipAtmosphereDetectorFix>();
|
||||
|
||||
PlayerSpawnHandler.OnSystemReady(shouldWarpInFromShip, shouldWarpInFromVessel);
|
||||
|
||||
|
||||
@ -16,7 +16,7 @@
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="OuterWildsGameLibs" Version="1.1.14.768" />
|
||||
<PackageReference Include="OWML" Version="2.9.8" />
|
||||
<PackageReference Include="OWML" Version="2.11.1" />
|
||||
<Reference Include="../Lib/System.ComponentModel.Annotations.dll" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
||||
@ -336,5 +336,7 @@ namespace NewHorizons
|
||||
public string GetTranslationForUI(string text) => TranslationHandler.GetTranslation(text, TranslationHandler.TextType.UI);
|
||||
|
||||
public string GetTranslationForOtherText(string text) => TranslationHandler.GetTranslation(text, TranslationHandler.TextType.OTHER);
|
||||
|
||||
public void AddSubtitle(IModBehaviour mod, string filePath) => SubtitlesHandler.RegisterAdditionalSubtitle(mod, filePath);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
@ -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<string> _failedFiles = new();
|
||||
|
||||
public static void Init()
|
||||
{
|
||||
_menuApi = Main.Instance.ModHelper.Interaction.TryGetModApi<IMenuAPI>("_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();
|
||||
|
||||
26
NewHorizons/Patches/BrambleProjectionFixPatches.cs
Normal file
26
NewHorizons/Patches/BrambleProjectionFixPatches.cs
Normal file
@ -0,0 +1,26 @@
|
||||
using HarmonyLib;
|
||||
|
||||
namespace NewHorizons.Patches;
|
||||
|
||||
/// <summary>
|
||||
/// Bug fix from the Outsider
|
||||
/// </summary>
|
||||
[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();
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Should fix a bug where disabled a CharacterDialogueTree makes its related RemoteDialogueTriggers softlock your game
|
||||
/// </summary>
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -26,5 +26,25 @@ namespace NewHorizons.Patches.VolumePatches
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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
|
||||
/// </summary>
|
||||
[HarmonyPrefix]
|
||||
[HarmonyPatch(nameof(DestructionVolume.VanishNomaiShuttle))]
|
||||
public static bool DestructionVolume_VanishNomaiShuttle(DestructionVolume __instance, OWRigidbody shuttleBody, RelativeLocationData entryLocation)
|
||||
{
|
||||
if (shuttleBody.GetComponentInChildren<NomaiShuttleController>() == null)
|
||||
{
|
||||
if (__instance._nomaiShuttleBody == shuttleBody)
|
||||
{
|
||||
__instance._nomaiShuttleBody = null;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
using HarmonyLib;
|
||||
using NewHorizons.Builder.Props;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NewHorizons.Patches.VolumePatches
|
||||
@ -8,20 +9,38 @@ namespace NewHorizons.Patches.VolumePatches
|
||||
{
|
||||
[HarmonyPrefix]
|
||||
[HarmonyPatch(typeof(SphericalFogWarpVolume), nameof(SphericalFogWarpVolume.IsProbeOnly))]
|
||||
public static bool SphericalFogWarpVolume_IsProbeOnly(SphericalFogWarpVolume __instance, out bool __result)
|
||||
public static bool SphericalFogWarpVolume_IsProbeOnly(SphericalFogWarpVolume __instance, ref bool __result)
|
||||
{
|
||||
__result = Mathf.Approximately(__instance._exitRadius / __instance._warpRadius, 2f); // Check the ratio between these to determine if seed, instead of just < 10
|
||||
// Do not affect base game volumes
|
||||
if (!BrambleNodeBuilder.IsNHFogWarpVolume(__instance))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check the ratio between these to determine if seed, instead of just < 10
|
||||
__result = Mathf.Approximately(__instance._exitRadius / __instance._warpRadius, 2f);
|
||||
return false;
|
||||
}
|
||||
|
||||
[HarmonyPrefix]
|
||||
[HarmonyPatch(typeof(FogWarpVolume), nameof(FogWarpVolume.GetFogThickness))]
|
||||
public static bool FogWarpVolume_GetFogThickness(FogWarpVolume __instance, out float __result)
|
||||
public static bool FogWarpVolume_GetFogThickness(FogWarpVolume __instance, ref float __result)
|
||||
{
|
||||
if (__instance is InnerFogWarpVolume sph) __result = sph._exitRadius;
|
||||
else __result = 50; // 50f is hardcoded as the return value in the base game
|
||||
// Do not affect base game volumes
|
||||
if (!BrambleNodeBuilder.IsNHFogWarpVolume(__instance))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
if (__instance is InnerFogWarpVolume sph)
|
||||
{
|
||||
__result = sph._exitRadius;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1342,7 +1342,7 @@
|
||||
},
|
||||
"keepLoaded": {
|
||||
"type": "boolean",
|
||||
"description": "Should this detail stay loaded even if you're outside the sector (good for very large props)"
|
||||
"description": "Should this detail stay loaded (visible and collideable) even if you're outside the sector (good for very large props)?\nAlso makes this detail visible on the map.\nMost logic/behavior scripts will still only work inside the sector, as most of those scripts break if a sector is not provided."
|
||||
},
|
||||
"hasPhysics": {
|
||||
"type": "boolean",
|
||||
@ -1402,7 +1402,7 @@
|
||||
},
|
||||
"itemType": {
|
||||
"type": "string",
|
||||
"description": "The type of the item, which determines its orientation when held and what sockets it fits into. This can be a custom string, or a vanilla ItemType (Scroll, WarpCode, SharedStone, ConversationStone, Lantern, SlideReel, DreamLantern, or VisionTorch). Defaults to the item name."
|
||||
"description": "The type of the item, which determines its orientation when held and what sockets it fits into. This can be a custom string, or a vanilla ItemType (Scroll, WarpCore, SharedStone, ConversationStone, Lantern, SlideReel, DreamLantern, or VisionTorch). Defaults to the item name."
|
||||
},
|
||||
"interactRange": {
|
||||
"type": "number",
|
||||
@ -1410,6 +1410,12 @@
|
||||
"format": "float",
|
||||
"default": 2.0
|
||||
},
|
||||
"colliderRadius": {
|
||||
"type": "number",
|
||||
"description": "The radius that the added sphere collider will use for collision and hover detection.\nIf there's already a collider on the detail, you can make this 0.",
|
||||
"format": "float",
|
||||
"default": 0.5
|
||||
},
|
||||
"droppable": {
|
||||
"type": "boolean",
|
||||
"description": "Whether the item can be dropped. Defaults to true.",
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -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<DebugSubmenu> 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));
|
||||
|
||||
|
||||
@ -95,6 +95,10 @@ namespace NewHorizons.Utility.Files
|
||||
_textureCache.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// used specifically for projected slides.
|
||||
/// also adds a border (to prevent weird visual bug) and makes the texture linear (otherwise the projected image is too bright).
|
||||
/// </summary>
|
||||
public static Texture2D Invert(Texture2D texture)
|
||||
{
|
||||
var key = $"{texture.name} > invert";
|
||||
@ -122,7 +126,7 @@ namespace NewHorizons.Utility.Files
|
||||
}
|
||||
}
|
||||
|
||||
var newTexture = new Texture2D(texture.width, texture.height, texture.format, texture.mipmapCount != 1);
|
||||
var newTexture = new Texture2D(texture.width, texture.height, texture.format, texture.mipmapCount != 1, true);
|
||||
newTexture.name = key;
|
||||
newTexture.SetPixels(pixels);
|
||||
newTexture.Apply();
|
||||
@ -297,6 +301,40 @@ namespace NewHorizons.Utility.Files
|
||||
return newImage;
|
||||
}
|
||||
|
||||
public static Color LerpColor(Color start, Color end, float amount)
|
||||
{
|
||||
return new Color(Mathf.Lerp(start.r, end.r, amount), Mathf.Lerp(start.g, end.g, amount), Mathf.Lerp(start.b, end.b, amount));
|
||||
}
|
||||
|
||||
public static Texture2D LerpGreyscaleImageAlongX(Texture2D image, Color lightTintStart, Color darkTintStart, Color lightTintEnd, Color darkTintEnd)
|
||||
{
|
||||
var key = $"{image.name} > lerp greyscale {lightTintStart} {darkTintStart} {lightTintEnd} {darkTintEnd}";
|
||||
if (_textureCache.TryGetValue(key, out var existingTexture)) return (Texture2D)existingTexture;
|
||||
|
||||
var pixels = image.GetPixels();
|
||||
for (int i = 0; i < pixels.Length; i++)
|
||||
{
|
||||
var amount = (i % image.width) / (float) image.width;
|
||||
var lightTint = LerpColor(lightTintStart, lightTintEnd, amount);
|
||||
var darkTint = LerpColor(darkTintStart, darkTintEnd, amount);
|
||||
|
||||
pixels[i].r = Mathf.Lerp(darkTint.r, lightTint.r, pixels[i].r);
|
||||
pixels[i].g = Mathf.Lerp(darkTint.g, lightTint.g, pixels[i].g);
|
||||
pixels[i].b = Mathf.Lerp(darkTint.b, lightTint.b, pixels[i].b);
|
||||
}
|
||||
|
||||
var newImage = new Texture2D(image.width, image.height, image.format, image.mipmapCount != 1);
|
||||
newImage.name = key;
|
||||
newImage.SetPixels(pixels);
|
||||
newImage.Apply();
|
||||
|
||||
newImage.wrapMode = image.wrapMode;
|
||||
|
||||
_textureCache.Add(key, newImage);
|
||||
|
||||
return newImage;
|
||||
}
|
||||
|
||||
public static Texture2D ClearTexture(int width, int height, bool wrap = false)
|
||||
{
|
||||
var key = $"Clear {width} {height} {wrap}";
|
||||
|
||||
@ -351,7 +351,7 @@ namespace NewHorizons.Utility
|
||||
return parentNode.ChildNodes.Cast<XmlNode>().First(node => node.LocalName == tagName);
|
||||
}
|
||||
|
||||
public static string TruncateWhitespace(this string text)
|
||||
public static string TruncateWhitespaceAndToLower(this string text)
|
||||
{
|
||||
// return Regex.Replace(text.Trim(), @"[^\S\r\n]+", "GUH");
|
||||
return Regex.Replace(text.Trim(), @"\s+", " ").ToLowerInvariant();
|
||||
|
||||
@ -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
|
||||
{
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user