diff --git a/NewHorizons/Assets/xen.newhorizons b/NewHorizons/Assets/xen.newhorizons index 1a754842..de0815e9 100644 Binary files a/NewHorizons/Assets/xen.newhorizons and b/NewHorizons/Assets/xen.newhorizons differ diff --git a/NewHorizons/Assets/xen.newhorizons.manifest b/NewHorizons/Assets/xen.newhorizons.manifest index d45ddec5..8902bd7f 100644 --- a/NewHorizons/Assets/xen.newhorizons.manifest +++ b/NewHorizons/Assets/xen.newhorizons.manifest @@ -1,14 +1,16 @@ ManifestFileVersion: 0 -CRC: 1014555239 +CRC: 2022446871 Hashes: AssetFileHash: serializedVersion: 2 - Hash: 45fa3430ee7bea1e8384e57927fc0f76 + Hash: 083882699617744b8fc49234bb8cb795 TypeTreeHash: serializedVersion: 2 - Hash: 55d48f4ad9c3b13330b9eb5ee5686477 + Hash: 10a6a558690295dadb3dd990eda0821a HashAppended: 0 ClassTypes: +- Class: 21 + Script: {instanceID: 0} - Class: 48 Script: {instanceID: 0} SerializeReferenceClassIdentifiers: [] @@ -18,6 +20,7 @@ Assets: - Assets/Shaders/SphereTextureWrapperNormal.shader - Assets/Shaders/UnlitRing1Pixel.shader - Assets/Shaders/UnlitTransparent.shader +- Assets/Resources/TransparentCloud.mat - Assets/Shaders/StandardCullOFF.shader - Assets/Shaders/Ring1Pixel.shader Dependencies: [] diff --git a/NewHorizons/Builder/Atmosphere/AtmosphereBuilder.cs b/NewHorizons/Builder/Atmosphere/AtmosphereBuilder.cs index 7646a205..9dd1e8a8 100644 --- a/NewHorizons/Builder/Atmosphere/AtmosphereBuilder.cs +++ b/NewHorizons/Builder/Atmosphere/AtmosphereBuilder.cs @@ -59,7 +59,7 @@ namespace NewHorizons.Builder.Atmosphere } } - material.SetFloat(InnerRadius, atmosphereModule.clouds != null ? atmosphereModule.size : surfaceSize); + material.SetFloat(InnerRadius, (atmosphereModule.clouds != null && atmosphereModule.clouds.cloudsPrefab != CloudPrefabType.Transparent) ? atmosphereModule.size : surfaceSize); material.SetFloat(OuterRadius, atmosphereModule.size * 1.2f); if (atmosphereModule.atmosphereTint != null) material.SetColor(SkyColor, atmosphereModule.atmosphereTint.ToColor()); diff --git a/NewHorizons/Builder/Atmosphere/CloudsBuilder.cs b/NewHorizons/Builder/Atmosphere/CloudsBuilder.cs index 6732b18f..d5b15f89 100644 --- a/NewHorizons/Builder/Atmosphere/CloudsBuilder.cs +++ b/NewHorizons/Builder/Atmosphere/CloudsBuilder.cs @@ -11,6 +11,7 @@ namespace NewHorizons.Builder.Atmosphere { private static Material[] _gdCloudMaterials; private static Material[] _qmCloudMaterials; + private static Material _transparentCloud; private static GameObject _lightningPrefab; private static Texture2D _colorRamp; private static readonly int Color = Shader.PropertyToID("_Color"); @@ -18,6 +19,7 @@ namespace NewHorizons.Builder.Atmosphere private static readonly int MainTex = Shader.PropertyToID("_MainTex"); private static readonly int RampTex = Shader.PropertyToID("_RampTex"); private static readonly int CapTex = Shader.PropertyToID("_CapTex"); + private static readonly int Smoothness = Shader.PropertyToID("_Glossiness"); public static void Make(GameObject planetGO, Sector sector, AtmosphereModule atmo, bool cloaked, IModBehaviour mod) { @@ -28,7 +30,15 @@ namespace NewHorizons.Builder.Atmosphere cloudsMainGO.SetActive(false); cloudsMainGO.transform.parent = sector?.transform ?? planetGO.transform; - MakeTopClouds(cloudsMainGO, atmo, mod); + if (atmo.clouds.cloudsPrefab != CloudPrefabType.Transparent) MakeTopClouds(cloudsMainGO, atmo, mod); + else + { + MakeTransparentClouds(cloudsMainGO, atmo, mod); + if (atmo.clouds.hasLightning) MakeLightning(cloudsMainGO, sector, atmo); + cloudsMainGO.transform.position = planetGO.transform.TransformPoint(Vector3.zero); + cloudsMainGO.SetActive(true); + return; + } GameObject cloudsBottomGO = new GameObject("BottomClouds"); cloudsBottomGO.SetActive(false); @@ -114,7 +124,7 @@ namespace NewHorizons.Builder.Atmosphere lightning.transform.localPosition = Vector3.zero; var lightningGenerator = lightning.GetComponent(); - lightningGenerator._altitude = (atmo.clouds.outerCloudRadius + atmo.clouds.innerCloudRadius) / 2f; + lightningGenerator._altitude = atmo.clouds.cloudsPrefab != CloudPrefabType.Transparent ? (atmo.clouds.outerCloudRadius + atmo.clouds.innerCloudRadius) / 2f : atmo.clouds.outerCloudRadius; if (noAudio) { lightningGenerator._audioPrefab = null; @@ -177,7 +187,7 @@ namespace NewHorizons.Builder.Atmosphere var material = new Material(Shader.Find("Standard")); if (atmo.clouds.unlit) material.renderQueue = 3000; material.name = atmo.clouds.unlit ? "BasicCloud" : "BasicShadowCloud"; - material.SetFloat(279, 0f); // smoothness + material.SetFloat(Smoothness, 0f); tempArray[0] = material; } else @@ -218,5 +228,65 @@ namespace NewHorizons.Builder.Atmosphere return cloudsTopGO; } + + public static GameObject MakeTransparentClouds(GameObject rootObject, AtmosphereModule atmo, IModBehaviour mod, bool isProxy = false) + { + Texture2D image; + + try + { + image = ImageUtilities.GetTexture(mod, atmo.clouds.texturePath); + } + catch (Exception e) + { + Logger.LogError($"Couldn't load Cloud texture for [{atmo.clouds.texturePath}]:\n{e}"); + return null; + } + + GameObject cloudsTransparentGO = new GameObject("TransparentClouds"); + cloudsTransparentGO.SetActive(false); + cloudsTransparentGO.transform.parent = rootObject.transform; + cloudsTransparentGO.transform.localScale = Vector3.one * atmo.clouds.outerCloudRadius; + + MeshFilter filter = cloudsTransparentGO.AddComponent(); + filter.mesh = SearchUtilities.Find("CloudsTopLayer_GD").GetComponent().mesh; + + MeshRenderer renderer = cloudsTransparentGO.AddComponent(); + if (_transparentCloud == null) _transparentCloud = Main.NHAssetBundle.LoadAsset("Assets/Resources/TransparentCloud.mat"); + var material = new Material(_transparentCloud); + material.name = "TransparentClouds_" + image.name; + material.SetTexture(MainTex, image); + renderer.sharedMaterial = material; + + if (!isProxy) + { + GameObject tcrqcGO = new GameObject("TransparentCloudRenderQueueController"); + tcrqcGO.transform.SetParent(cloudsTransparentGO.transform, false); + tcrqcGO.layer = LayerMask.NameToLayer("BasicEffectVolume"); + + var shape = tcrqcGO.AddComponent(); + shape.radius = 1; + + var owTriggerVolume = tcrqcGO.AddComponent(); + owTriggerVolume._shape = shape; + + TransparentCloudRenderQueueController tcrqc = tcrqcGO.AddComponent(); + tcrqc.renderer = renderer; + } + + if (atmo.clouds.rotationSpeed != 0f) + { + var rt = cloudsTransparentGO.AddComponent(); + rt._localAxis = Vector3.up; + rt._degreesPerSecond = atmo.clouds.rotationSpeed; + rt._randomizeRotationRate = false; + } + + cloudsTransparentGO.transform.localPosition = Vector3.zero; + + cloudsTransparentGO.SetActive(true); + + return cloudsTransparentGO; + } } } diff --git a/NewHorizons/Builder/Atmosphere/EffectsBuilder.cs b/NewHorizons/Builder/Atmosphere/EffectsBuilder.cs index c177a9ed..6394e02f 100644 --- a/NewHorizons/Builder/Atmosphere/EffectsBuilder.cs +++ b/NewHorizons/Builder/Atmosphere/EffectsBuilder.cs @@ -21,7 +21,6 @@ namespace NewHorizons.Builder.Atmosphere SCG._waitForStreaming = false; var minHeight = surfaceSize; - var maxHeight = config.Atmosphere.size; if (config.HeightMap?.minHeight != null) { if (config.Water?.size >= config.HeightMap.minHeight) minHeight = config.Water.size; // use sea level if its higher @@ -30,6 +29,9 @@ namespace NewHorizons.Builder.Atmosphere else if (config.Water?.size != null) minHeight = config.Water.size; else if (config.Lava?.size != null) minHeight = config.Lava.size; + var maxHeight = config.Atmosphere.size; + if (config.Atmosphere.clouds?.outerCloudRadius != null) maxHeight = config.Atmosphere.clouds.outerCloudRadius; + if (config.Atmosphere.hasRain) { var rainGO = GameObject.Instantiate(SearchUtilities.Find("GiantsDeep_Body/Sector_GD/Sector_GDInterior/Effects_GDInterior/Effects_GD_Rain"), effectsGO.transform); diff --git a/NewHorizons/Builder/Body/ProxyBuilder.cs b/NewHorizons/Builder/Body/ProxyBuilder.cs index 4e028acf..32f7d355 100644 --- a/NewHorizons/Builder/Body/ProxyBuilder.cs +++ b/NewHorizons/Builder/Body/ProxyBuilder.cs @@ -111,7 +111,8 @@ namespace NewHorizons.Builder.Body if (body.Config.Atmosphere.clouds != null) { - topClouds = CloudsBuilder.MakeTopClouds(proxy, body.Config.Atmosphere, body.Mod).GetComponent(); + if (body.Config.Atmosphere.clouds.cloudsPrefab != External.Modules.CloudPrefabType.Transparent) topClouds = CloudsBuilder.MakeTopClouds(proxy, body.Config.Atmosphere, body.Mod).GetComponent(); + else topClouds = CloudsBuilder.MakeTransparentClouds(proxy, body.Config.Atmosphere, body.Mod, true).GetAddComponent(); if (body.Config.Atmosphere.clouds.hasLightning) lightningGenerator = CloudsBuilder.MakeLightning(proxy, null, body.Config.Atmosphere, true); diff --git a/NewHorizons/Builder/ShipLog/RevealBuilder.cs b/NewHorizons/Builder/ShipLog/RevealBuilder.cs index 95f118b6..59662218 100644 --- a/NewHorizons/Builder/ShipLog/RevealBuilder.cs +++ b/NewHorizons/Builder/ShipLog/RevealBuilder.cs @@ -41,7 +41,22 @@ namespace NewHorizons.Builder.ShipLog GameObject revealTriggerVolume = new GameObject("Reveal Volume (" + info.revealOn + ")"); revealTriggerVolume.SetActive(false); revealTriggerVolume.transform.parent = sector?.transform ?? planetGO.transform; + + if (!string.IsNullOrEmpty(info.parentPath)) + { + var newParent = planetGO.transform.Find(info.parentPath); + if (newParent != null) + { + revealTriggerVolume.transform.parent = newParent; + } + else + { + Logger.LogWarning($"Cannot find parent object at path: {planetGO.name}/{info.parentPath}"); + } + } + revealTriggerVolume.transform.position = planetGO.transform.TransformPoint(info.position ?? Vector3.zero); + return revealTriggerVolume; } diff --git a/NewHorizons/Builder/Volumes/AudioVolumeBuilder.cs b/NewHorizons/Builder/Volumes/AudioVolumeBuilder.cs index b487670a..2952f590 100644 --- a/NewHorizons/Builder/Volumes/AudioVolumeBuilder.cs +++ b/NewHorizons/Builder/Volumes/AudioVolumeBuilder.cs @@ -19,6 +19,20 @@ namespace NewHorizons.Builder.Volumes go.SetActive(false); go.transform.parent = sector?.transform ?? planetGO.transform; + + if (!string.IsNullOrEmpty(info.parentPath)) + { + var newParent = planetGO.transform.Find(info.parentPath); + if (newParent != null) + { + go.transform.parent = newParent; + } + else + { + Logger.LogWarning($"Cannot find parent object at path: {planetGO.name}/{info.parentPath}"); + } + } + go.transform.position = planetGO.transform.TransformPoint(info.position != null ? (Vector3)info.position : Vector3.zero); go.layer = LayerMask.NameToLayer("AdvancedEffectVolume"); diff --git a/NewHorizons/Builder/Volumes/HazardVolumeBuilder.cs b/NewHorizons/Builder/Volumes/HazardVolumeBuilder.cs index 67c6f22c..d52b4352 100644 --- a/NewHorizons/Builder/Volumes/HazardVolumeBuilder.cs +++ b/NewHorizons/Builder/Volumes/HazardVolumeBuilder.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.Linq; using UnityEngine; +using Logger = NewHorizons.Utility.Logger; namespace NewHorizons.Builder.Volumes { @@ -16,6 +17,20 @@ namespace NewHorizons.Builder.Volumes go.SetActive(false); go.transform.parent = sector?.transform ?? planetGO.transform; + + if (!string.IsNullOrEmpty(info.parentPath)) + { + var newParent = planetGO.transform.Find(info.parentPath); + if (newParent != null) + { + go.transform.parent = newParent; + } + else + { + Logger.LogWarning($"Cannot find parent object at path: {planetGO.name}/{info.parentPath}"); + } + } + go.transform.position = planetGO.transform.TransformPoint(info.position != null ? (Vector3)info.position : Vector3.zero); go.layer = LayerMask.NameToLayer("BasicEffectVolume"); diff --git a/NewHorizons/Builder/Volumes/NotificationVolumeBuilder.cs b/NewHorizons/Builder/Volumes/NotificationVolumeBuilder.cs index c91e4161..496a9ea7 100644 --- a/NewHorizons/Builder/Volumes/NotificationVolumeBuilder.cs +++ b/NewHorizons/Builder/Volumes/NotificationVolumeBuilder.cs @@ -21,6 +21,20 @@ namespace NewHorizons.Builder.Volumes go.SetActive(false); go.transform.parent = sector?.transform ?? planetGO.transform; + + if (!string.IsNullOrEmpty(info.parentPath)) + { + var newParent = planetGO.transform.Find(info.parentPath); + if (newParent != null) + { + go.transform.parent = newParent; + } + else + { + Logger.LogWarning($"Cannot find parent object at path: {planetGO.name}/{info.parentPath}"); + } + } + go.transform.position = planetGO.transform.TransformPoint(info.position != null ? (Vector3)info.position : Vector3.zero); go.layer = LayerMask.NameToLayer("BasicEffectVolume"); diff --git a/NewHorizons/Builder/Volumes/VolumeBuilder.cs b/NewHorizons/Builder/Volumes/VolumeBuilder.cs new file mode 100644 index 00000000..afeffd73 --- /dev/null +++ b/NewHorizons/Builder/Volumes/VolumeBuilder.cs @@ -0,0 +1,46 @@ +using NewHorizons.Components; +using NewHorizons.External.Modules; +using UnityEngine; +using Logger = NewHorizons.Utility.Logger; + +namespace NewHorizons.Builder.Volumes +{ + public static class VolumeBuilder + { + public static TVolume Make(GameObject planetGO, Sector sector, VolumesModule.VolumeInfo info) where TVolume : MonoBehaviour //Could be BaseVolume but I need to create vanilla volumes too. + { + var go = new GameObject(typeof(TVolume).Name); + go.SetActive(false); + + go.transform.parent = sector?.transform ?? planetGO.transform; + + if (!string.IsNullOrEmpty(info.parentPath)) + { + var newParent = planetGO.transform.Find(info.parentPath); + if (newParent != null) + { + go.transform.parent = newParent; + } + else + { + Logger.LogWarning($"Cannot find parent object at path: {planetGO.name}/{info.parentPath}"); + } + } + + go.transform.position = planetGO.transform.TransformPoint(info.position != null ? (Vector3)info.position : Vector3.zero); + go.layer = LayerMask.NameToLayer("BasicEffectVolume"); + + var shape = go.AddComponent(); + shape.radius = info.radius; + + var owTriggerVolume = go.AddComponent(); + owTriggerVolume._shape = shape; + + var volume = go.AddComponent(); + + go.SetActive(true); + + return volume; + } + } +} diff --git a/NewHorizons/Builder/Volumes/VolumesBuildManager.cs b/NewHorizons/Builder/Volumes/VolumesBuildManager.cs index f7a664b9..9e9a9c36 100644 --- a/NewHorizons/Builder/Volumes/VolumesBuildManager.cs +++ b/NewHorizons/Builder/Volumes/VolumesBuildManager.cs @@ -1,6 +1,7 @@ using NewHorizons.Builder.Body; using NewHorizons.Builder.ShipLog; using NewHorizons.Builder.Volumes; +using NewHorizons.Components; using NewHorizons.External.Configs; using OWML.Common; using System; @@ -49,6 +50,34 @@ namespace NewHorizons.Builder.Volumes HazardVolumeBuilder.Make(go, sector, planetBody, hazardVolume, mod); } } + if (config.Volumes.mapRestrictionVolumes != null) + { + foreach (var mapRestrictionVolume in config.Volumes.mapRestrictionVolumes) + { + VolumeBuilder.Make(go, sector, mapRestrictionVolume); + } + } + if (config.Volumes.interferenceVolumes != null) + { + foreach (var interferenceVolume in config.Volumes.interferenceVolumes) + { + VolumeBuilder.Make(go, sector, interferenceVolume); + } + } + if (config.Volumes.reverbVolumes != null) + { + foreach (var reverbVolume in config.Volumes.reverbVolumes) + { + VolumeBuilder.Make(go, sector, reverbVolume); + } + } + if (config.Volumes.insulatingVolumes != null) + { + foreach (var insulatingVolume in config.Volumes.insulatingVolumes) + { + VolumeBuilder.Make(go, sector, insulatingVolume); + } + } } } } diff --git a/NewHorizons/Components/BaseVolume.cs b/NewHorizons/Components/BaseVolume.cs new file mode 100644 index 00000000..6ddccada --- /dev/null +++ b/NewHorizons/Components/BaseVolume.cs @@ -0,0 +1,28 @@ +using UnityEngine; + +namespace NewHorizons.Components +{ + [RequireComponent(typeof(OWTriggerVolume))] + public abstract class BaseVolume : MonoBehaviour + { + private OWTriggerVolume _triggerVolume; + + public virtual void Awake() + { + _triggerVolume = this.GetRequiredComponent(); + _triggerVolume.OnEntry += OnTriggerVolumeEntry; + _triggerVolume.OnExit += OnTriggerVolumeExit; + } + + public virtual void OnDestroy() + { + if (_triggerVolume == null) return; + _triggerVolume.OnEntry -= OnTriggerVolumeEntry; + _triggerVolume.OnExit -= OnTriggerVolumeExit; + } + + public abstract void OnTriggerVolumeEntry(GameObject hitObj); + + public abstract void OnTriggerVolumeExit(GameObject hitObj); + } +} diff --git a/NewHorizons/Components/InterferenceVolume.cs b/NewHorizons/Components/InterferenceVolume.cs new file mode 100644 index 00000000..43cf34ac --- /dev/null +++ b/NewHorizons/Components/InterferenceVolume.cs @@ -0,0 +1,54 @@ +using NewHorizons.Handlers; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; + +namespace NewHorizons.Components +{ + public class InterferenceVolume : BaseVolume + { + public override void OnTriggerVolumeEntry(GameObject hitObj) + { + if (hitObj.CompareTag("PlayerDetector")) + { + OnPlayerEnter(); + } + else if (hitObj.CompareTag("ProbeDetector")) + { + OnProbeEnter(); + } + else if (hitObj.CompareTag("ShipDetector")) + { + OnShipEnter(); + } + } + + public override void OnTriggerVolumeExit(GameObject hitObj) + { + if (hitObj.CompareTag("PlayerDetector")) + { + OnPlayerExit(); + } + else if (hitObj.CompareTag("ProbeDetector")) + { + OnProbeExit(); + } + else if (hitObj.CompareTag("ShipDetector")) + { + OnShipExit(); + } + } + + public void OnPlayerEnter() => InterferenceHandler.OnPlayerEnterInterferenceVolume(this); + public void OnPlayerExit() => InterferenceHandler.OnPlayerExitInterferenceVolume(this); + + public void OnProbeEnter() => InterferenceHandler.OnProbeEnterInterferenceVolume(this); + public void OnProbeExit() => InterferenceHandler.OnProbeExitInterferenceVolume(this); + + public void OnShipEnter() => InterferenceHandler.OnShipEnterInterferenceVolume(this); + public void OnShipExit() => InterferenceHandler.OnShipExitInterferenceVolume(this); + } +} diff --git a/NewHorizons/Components/MapRestrictionVolume.cs b/NewHorizons/Components/MapRestrictionVolume.cs new file mode 100644 index 00000000..04442840 --- /dev/null +++ b/NewHorizons/Components/MapRestrictionVolume.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; + +namespace NewHorizons.Components +{ + public class MapRestrictionVolume : BaseVolume + { + public override void OnTriggerVolumeEntry(GameObject hitObj) + { + if (hitObj.CompareTag("PlayerDetector")) + { + Locator.GetMapController()?.OnPlayerEnterMapRestriction(); + } + } + + public override void OnTriggerVolumeExit(GameObject hitObj) + { + if (hitObj.CompareTag("PlayerDetector")) + { + Locator.GetMapController()?.OnPlayerExitMapRestriction(); + } + } + } +} diff --git a/NewHorizons/Components/NotificationVolume.cs b/NewHorizons/Components/NotificationVolume.cs index 2dc81ed1..6fe7b746 100644 --- a/NewHorizons/Components/NotificationVolume.cs +++ b/NewHorizons/Components/NotificationVolume.cs @@ -7,29 +7,13 @@ using UnityEngine; namespace NewHorizons.Components { - [RequireComponent(typeof(OWTriggerVolume))] - public class NotificationVolume : MonoBehaviour + public class NotificationVolume : BaseVolume { private NotificationTarget _target = NotificationTarget.All; private bool _pin = false; - private OWTriggerVolume _triggerVolume; private NotificationData _entryNotification; private NotificationData _exitNotification; - public void Awake() - { - _triggerVolume = this.GetRequiredComponent(); - _triggerVolume.OnEntry += OnTriggerVolumeEntry; - _triggerVolume.OnExit += OnTriggerVolumeExit; - } - - public void OnDestroy() - { - if (_triggerVolume == null) return; - _triggerVolume.OnEntry -= OnTriggerVolumeEntry; - _triggerVolume.OnExit -= OnTriggerVolumeExit; - } - public void SetPinned(bool pin) => _pin = pin; public void SetTarget(External.Modules.VolumesModule.NotificationVolumeInfo.NotificationTarget target) => SetTarget(EnumUtils.Parse(target.ToString(), NotificationTarget.All)); @@ -46,7 +30,7 @@ namespace NewHorizons.Components _exitNotification = new NotificationData(_target, TranslationHandler.GetTranslation(displayMessage, TranslationHandler.TextType.UI), duration); } - public void OnTriggerVolumeEntry(GameObject hitObj) + public override void OnTriggerVolumeEntry(GameObject hitObj) { if (_target == NotificationTarget.All) { @@ -71,7 +55,7 @@ namespace NewHorizons.Components } } - public void OnTriggerVolumeExit(GameObject hitObj) + public override void OnTriggerVolumeExit(GameObject hitObj) { if (_target == NotificationTarget.All) { diff --git a/NewHorizons/Components/TransparentCloudRenderQueueController.cs b/NewHorizons/Components/TransparentCloudRenderQueueController.cs new file mode 100644 index 00000000..d78259b1 --- /dev/null +++ b/NewHorizons/Components/TransparentCloudRenderQueueController.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; + +namespace NewHorizons.Components +{ + [RequireComponent(typeof(OWTriggerVolume))] + public class TransparentCloudRenderQueueController : MonoBehaviour + { + public int insideQueue = 3001; + public int outsideQueue = 2999; + + private OWTriggerVolume _triggerVolume; + public Renderer renderer; + + public void Awake() + { + _triggerVolume = this.GetRequiredComponent(); + if (_triggerVolume == null) return; + _triggerVolume.OnEntry += OnTriggerVolumeEntry; + _triggerVolume.OnExit += OnTriggerVolumeExit; + } + + public void OnDestroy() + { + if (_triggerVolume == null) return; + _triggerVolume.OnEntry -= OnTriggerVolumeEntry; + _triggerVolume.OnExit -= OnTriggerVolumeExit; + } + + public void OnTriggerVolumeEntry(GameObject hitObj) + { + if (hitObj.CompareTag("PlayerDetector")) SetQueueToInside(); + } + + public void OnTriggerVolumeExit(GameObject hitObj) + { + if (hitObj.CompareTag("PlayerDetector")) SetQueueToOutside(); + } + + public void SetQueueToInside() + { + if (renderer == null) return; + renderer.sharedMaterial.renderQueue = insideQueue; + } + + public void SetQueueToOutside() + { + if (renderer == null) return; + renderer.sharedMaterial.renderQueue = outsideQueue; + } + } +} diff --git a/NewHorizons/External/Modules/AtmosphereModule.cs b/NewHorizons/External/Modules/AtmosphereModule.cs index d2b835ee..33c0ccef 100644 --- a/NewHorizons/External/Modules/AtmosphereModule.cs +++ b/NewHorizons/External/Modules/AtmosphereModule.cs @@ -30,6 +30,8 @@ namespace NewHorizons.External.Modules [EnumMember(Value = @"quantumMoon")] QuantumMoon = 1, [EnumMember(Value = @"basic")] Basic = 2, + + [EnumMember(Value = @"transparent")] Transparent = 3, } [JsonObject] diff --git a/NewHorizons/External/Modules/VolumesModule.cs b/NewHorizons/External/Modules/VolumesModule.cs index 43059fbf..a3c810a0 100644 --- a/NewHorizons/External/Modules/VolumesModule.cs +++ b/NewHorizons/External/Modules/VolumesModule.cs @@ -15,27 +15,66 @@ namespace NewHorizons.External.Modules public class VolumesModule { /// - /// Add audio volumes to this planet + /// Add audio volumes to this planet. /// public AudioVolumeInfo[] audioVolumes; /// - /// Add hazard volumes to this planet + /// Add hazard volumes to this planet. /// public HazardVolumeInfo[] hazardVolumes; /// - /// Add notification volumes to this planet + /// Add interference volumes to this planet. + /// + public VolumeInfo[] interferenceVolumes; + + /// + /// Add insulating volumes to this planet. These will stop electricty hazard volumes from affecting you (just like the jellyfish). + /// + public VolumeInfo[] insulatingVolumes; + + /// + /// Add map restriction volumes to this planet. + /// + public VolumeInfo[] mapRestrictionVolumes; + + /// + /// Add notification volumes to this planet. /// public NotificationVolumeInfo[] notificationVolumes; /// - /// Add triggers that reveal parts of the ship log on this planet + /// Add triggers that reveal parts of the ship log on this planet. /// public RevealVolumeInfo[] revealVolumes; + /// + /// Add reverb volumes to this planet. Great for echoes in caves. + /// + public VolumeInfo[] reverbVolumes; + [JsonObject] - public class RevealVolumeInfo + public class VolumeInfo + { + /// + /// The location of this volume. Optional (will default to 0,0,0). + /// + public MVector3 position; + + /// + /// The radius of this volume. + /// + public float radius = 1f; + + /// + /// The relative path from the planet to the parent of this object. Optional (will default to the root sector). + /// + public string parentPath; + } + + [JsonObject] + public class RevealVolumeInfo : VolumeInfo { [JsonConverter(typeof(StringEnumConverter))] public enum RevealVolumeType @@ -57,16 +96,6 @@ namespace NewHorizons.External.Modules /// public float maxDistance = -1f; // Snapshot & Observe Only - /// - /// The position to place this volume at - /// - public MVector3 position; - - /// - /// The radius of this reveal volume - /// - public float radius = 1f; - /// /// What needs to be done to the volume to unlock the facts /// @@ -84,18 +113,8 @@ namespace NewHorizons.External.Modules } [JsonObject] - public class AudioVolumeInfo + public class AudioVolumeInfo : VolumeInfo { - /// - /// The location of this audio volume. Optional (will default to 0,0,0). - /// - public MVector3 position; - - /// - /// The radius of this audio volume - /// - public float radius; - /// /// The audio to use. Can be a path to a .wav/.ogg/.mp3 file, or taken from the AudioClip list. /// @@ -113,23 +132,13 @@ namespace NewHorizons.External.Modules } [JsonObject] - public class NotificationVolumeInfo + public class NotificationVolumeInfo : VolumeInfo { /// /// What the notification will show for. /// [DefaultValue("all")] public NotificationTarget target = NotificationTarget.All; - /// - /// The location of this notification volume. Optional (will default to 0,0,0). - /// - public MVector3 position; - - /// - /// The radius of this notification volume. - /// - public float radius; - /// /// The notification that will play when you enter this volume. /// @@ -165,18 +174,8 @@ namespace NewHorizons.External.Modules } [JsonObject] - public class HazardVolumeInfo + public class HazardVolumeInfo : VolumeInfo { - /// - /// The location of this hazard volume. Optional (will default to 0,0,0). - /// - public MVector3 position; - - /// - /// The radius of this hazard volume. - /// - public float radius; - /// /// The type of hazard for this volume. /// @@ -202,7 +201,7 @@ namespace NewHorizons.External.Modules { [EnumMember(Value = @"none")] NONE = 0, [EnumMember(Value = @"general")] GENERAL = 1, - [EnumMember(Value = @"darkMatter")] DARKMATTER = 2, + [EnumMember(Value = @"ghostMatter")] DARKMATTER = 2, [EnumMember(Value = @"heat")] HEAT = 4, [EnumMember(Value = @"fire")] FIRE = 8, [EnumMember(Value = @"sandfall")] SANDFALL = 16, diff --git a/NewHorizons/Handlers/InterferenceHandler.cs b/NewHorizons/Handlers/InterferenceHandler.cs new file mode 100644 index 00000000..97ff0046 --- /dev/null +++ b/NewHorizons/Handlers/InterferenceHandler.cs @@ -0,0 +1,75 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NewHorizons.Handlers +{ + using InterferenceVolume = NewHorizons.Components.InterferenceVolume; + + public static class InterferenceHandler + { + private static List _playerInterference; + private static List _probeInterference; + private static List _shipInterference; + + public static void Init() + { + _playerInterference = new List(); + _probeInterference = new List(); + _shipInterference = new List(); + } + + public static bool PlayerHasInterference() => _playerInterference.Any(volume => volume != null); + public static bool ProbeHasInterference() => _probeInterference.Any(volume => volume != null); + public static bool ShipHasInterference() => _shipInterference.Any(volume => volume != null); + + public static bool IsPlayerSameAsProbe() + { + _playerInterference.RemoveAll(volume => volume == null); + return _playerInterference.All(_probeInterference.Contains) && _playerInterference.Count == _probeInterference.Count; + } + + public static bool IsPlayerSameAsShip() + { + _playerInterference.RemoveAll(volume => volume == null); + return _playerInterference.All(_shipInterference.Contains) && _playerInterference.Count == _shipInterference.Count; + } + + public static void OnPlayerEnterInterferenceVolume(InterferenceVolume interferenceVolume) + { + _playerInterference.SafeAdd(interferenceVolume); + GlobalMessenger.FireEvent("RefreshHUDVisibility"); + } + + public static void OnPlayerExitInterferenceVolume(InterferenceVolume interferenceVolume) + { + _playerInterference.Remove(interferenceVolume); + GlobalMessenger.FireEvent("RefreshHUDVisibility"); + } + + public static void OnProbeEnterInterferenceVolume(InterferenceVolume interferenceVolume) + { + _probeInterference.SafeAdd(interferenceVolume); + GlobalMessenger.FireEvent("RefreshHUDVisibility"); + } + + public static void OnProbeExitInterferenceVolume(InterferenceVolume interferenceVolume) + { + _probeInterference.Remove(interferenceVolume); + GlobalMessenger.FireEvent("RefreshHUDVisibility"); + } + + public static void OnShipEnterInterferenceVolume(InterferenceVolume interferenceVolume) + { + _shipInterference.SafeAdd(interferenceVolume); + GlobalMessenger.FireEvent("RefreshHUDVisibility"); + } + public static void OnShipExitInterferenceVolume(InterferenceVolume interferenceVolume) + { + _shipInterference.Remove(interferenceVolume); + GlobalMessenger.FireEvent("RefreshHUDVisibility"); + } + } +} diff --git a/NewHorizons/Handlers/PlanetCreationHandler.cs b/NewHorizons/Handlers/PlanetCreationHandler.cs index 67700c36..ec75a23c 100644 --- a/NewHorizons/Handlers/PlanetCreationHandler.cs +++ b/NewHorizons/Handlers/PlanetCreationHandler.cs @@ -590,7 +590,7 @@ namespace NewHorizons.Handlers if (!string.IsNullOrEmpty(body.Config.Atmosphere?.clouds?.texturePath)) { CloudsBuilder.Make(go, sector, body.Config.Atmosphere, willHaveCloak, body.Mod); - SunOverrideBuilder.Make(go, sector, body.Config.Atmosphere, body.Config.Water, surfaceSize); + if (body.Config.Atmosphere.clouds.cloudsPrefab != External.Modules.CloudPrefabType.Transparent) SunOverrideBuilder.Make(go, sector, body.Config.Atmosphere, body.Config.Water, surfaceSize); } if (body.Config.Atmosphere.hasRain || body.Config.Atmosphere.hasSnow) diff --git a/NewHorizons/Handlers/TitleSceneHandler.cs b/NewHorizons/Handlers/TitleSceneHandler.cs index b4fb22dc..ea435305 100644 --- a/NewHorizons/Handlers/TitleSceneHandler.cs +++ b/NewHorizons/Handlers/TitleSceneHandler.cs @@ -89,7 +89,7 @@ namespace NewHorizons.Handlers heightMap.minHeight = body.Config.HeightMap.minHeight * size / body.Config.HeightMap.maxHeight; heightMap.stretch = body.Config.HeightMap.stretch; } - if (body.Config.Atmosphere?.clouds?.texturePath != null) + if (body.Config.Atmosphere?.clouds?.texturePath != null && body.Config.Atmosphere?.clouds?.cloudsPrefab != CloudPrefabType.Transparent) { // Hacky but whatever I just want a sphere size = Mathf.Clamp(body.Config.Atmosphere.size / 10, minSize, maxSize); diff --git a/NewHorizons/Main.cs b/NewHorizons/Main.cs index 5eaaeb8f..f06bc48a 100644 --- a/NewHorizons/Main.cs +++ b/NewHorizons/Main.cs @@ -315,6 +315,7 @@ namespace NewHorizons AstroObjectLocator.Init(); StreamingHandler.Init(); AudioTypeHandler.Init(); + InterferenceHandler.Init(); RemoteHandler.Init(); AtmosphereBuilder.Init(); BrambleNodeBuilder.Init(BodyDict[CurrentStarSystem].Select(x => x.Config).Where(x => x.Bramble?.dimension != null).ToArray()); diff --git a/NewHorizons/Patches/HUDPatches.cs b/NewHorizons/Patches/HUDPatches.cs index bbb0061a..fc37e4e0 100644 --- a/NewHorizons/Patches/HUDPatches.cs +++ b/NewHorizons/Patches/HUDPatches.cs @@ -1,4 +1,5 @@ using HarmonyLib; +using NewHorizons.Handlers; namespace NewHorizons.Patches { @@ -9,6 +10,8 @@ namespace NewHorizons.Patches [HarmonyPatch(typeof(HUDMarker), nameof(HUDMarker.Awake))] public static void HUDMarker_Awake(HUDMarker __instance) { + GlobalMessenger.AddListener("RefreshHUDVisibility", __instance.RefreshOwnVisibility); + GlobalMessenger.AddListener("RefreshHUDVisibility", __instance.RefreshOwnVisibility); GlobalMessenger.AddListener("PlayerEnterCloakField", __instance.OnPlayerEnterCloakField); GlobalMessenger.AddListener("PlayerExitCloakField", __instance.OnPlayerExitCloakField); } @@ -17,6 +20,8 @@ namespace NewHorizons.Patches [HarmonyPatch(typeof(HUDMarker), nameof(HUDMarker.OnDestroy))] public static void HUDMarker_OnDestroy(HUDMarker __instance) { + GlobalMessenger.RemoveListener("RefreshHUDVisibility", __instance.RefreshOwnVisibility); + GlobalMessenger.RemoveListener("RefreshHUDVisibility", __instance.RefreshOwnVisibility); GlobalMessenger.RemoveListener("PlayerEnterCloakField", __instance.OnPlayerEnterCloakField); GlobalMessenger.RemoveListener("PlayerExitCloakField", __instance.OnPlayerExitCloakField); } @@ -53,11 +58,67 @@ namespace NewHorizons.Patches GlobalMessenger.RemoveListener("ShipExitCloakField", __instance.RefreshOwnVisibility); } + [HarmonyPrefix] + [HarmonyPatch(typeof(ProbeHUDMarker), nameof(ProbeHUDMarker.RefreshOwnVisibility))] + public static bool ProbeHUDMarker_RefreshOwnVisibility(ProbeHUDMarker __instance) + { + 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 = Components.CloakSectorController.isPlayerInside == Components.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; + + if (__instance._canvasMarker != null) __instance._canvasMarker.SetVisibility(__instance._isVisible); + + return false; + } + + [HarmonyPrefix] + [HarmonyPatch(typeof(ShipHUDMarker), nameof(ShipHUDMarker.RefreshOwnVisibility))] + public static bool ShipHUDMarker_RefreshOwnVisibility(ShipHUDMarker __instance) + { + bool insideEYE = Locator.GetEyeStateManager() != null && Locator.GetEyeStateManager().IsInsideTheEye(); + bool insideQM = __instance._quantumMoon != null && (__instance._quantumMoon.IsPlayerInside() || __instance._quantumMoon.IsShipInside()); + bool insideRW = Locator.GetRingWorldController() != null && Locator.GetRingWorldController().isPlayerInside; + bool insideIP = Locator.GetCloakFieldController() != null ? true : Locator.GetCloakFieldController().isPlayerInsideCloak == Locator.GetCloakFieldController().isShipInsideCloak; + bool insideCloak = Components.CloakSectorController.isPlayerInside == Components.CloakSectorController.isShipInside; + bool sameInterference = InterferenceHandler.IsPlayerSameAsShip(); + + __instance._isVisible = !insideEYE && !insideQM && !insideRW && !__instance._translatorEquipped && !__instance._inConversation && !__instance._shipDestroyed && !__instance._playerInShip && PlayerState.HasPlayerEnteredShip() && __instance._isWearingHelmet && insideIP && insideCloak && sameInterference; + + if (__instance._canvasMarker != null) __instance._canvasMarker.SetVisibility(__instance._isVisible); + + return false; + } + + [HarmonyPrefix] + [HarmonyPatch(typeof(ShipLogEntryHUDMarker), nameof(ShipLogEntryHUDMarker.RefreshOwnVisibility))] + public static bool ShipLogEntryHUDMarker_RefreshOwnVisibility(ShipLogEntryHUDMarker __instance) + { + bool hasEntryLocation = ShipLogEntryHUDMarker.s_entryLocation != null; + bool insideEYE = Locator.GetEyeStateManager() != null && Locator.GetEyeStateManager().IsInsideTheEye(); + bool insideQM = __instance._quantumMoon != null && __instance._quantumMoon.IsPlayerInside(); + bool insideRW = Locator.GetRingWorldController() != null && Locator.GetRingWorldController().isPlayerInside && ShipLogEntryHUDMarker.s_entryLocationID == "IP_RING_WORLD"; + bool insideIP = (hasEntryLocation && ShipLogEntryHUDMarker.s_entryLocation.IsWithinCloakField()) || !(Locator.GetCloakFieldController() != null && Locator.GetCloakFieldController().isPlayerInsideCloak); + bool insideCloak = (hasEntryLocation && ShipLogEntryHUDMarker.s_entryLocation.IsWithinCloakField()) || !Components.CloakSectorController.isPlayerInside; + + __instance._isVisible = (!insideEYE && !insideQM && !insideRW && !__instance._translatorEquipped && !__instance._inConversation && hasEntryLocation && (__instance._isWearingHelmet || __instance._atFlightConsole) && insideIP && insideCloak); + + if (__instance._canvasMarker != null) __instance._canvasMarker.SetVisibility(__instance._isVisible); + + return false; + } + + [HarmonyPostfix] [HarmonyPatch(typeof(ProbeCamera), nameof(ProbeCamera.HasInterference))] public static void ProbeCamera_HasInterference(ProbeCamera __instance, ref bool __result) { - __result = __result || Components.CloakSectorController.isPlayerInside != Components.CloakSectorController.isProbeInside; + __result = __result || (__instance._id != ProbeCamera.ID.PreLaunch && (Components.CloakSectorController.isPlayerInside != Components.CloakSectorController.isProbeInside || !InterferenceHandler.IsPlayerSameAsProbe())); } } } diff --git a/NewHorizons/Schemas/body_schema.json b/NewHorizons/Schemas/body_schema.json index 7ea40e04..b1a756cd 100644 --- a/NewHorizons/Schemas/body_schema.json +++ b/NewHorizons/Schemas/body_schema.json @@ -400,12 +400,14 @@ "x-enumNames": [ "GiantsDeep", "QuantumMoon", - "Basic" + "Basic", + "Transparent" ], "enum": [ "giantsDeep", "quantumMoon", - "basic" + "basic", + "transparent" ] }, "FluidType": { @@ -2393,31 +2395,59 @@ "properties": { "audioVolumes": { "type": "array", - "description": "Add audio volumes to this planet", + "description": "Add audio volumes to this planet.", "items": { "$ref": "#/definitions/AudioVolumeInfo" } }, "hazardVolumes": { "type": "array", - "description": "Add hazard volumes to this planet", + "description": "Add hazard volumes to this planet.", "items": { "$ref": "#/definitions/HazardVolumeInfo" } }, + "interferenceVolumes": { + "type": "array", + "description": "Add interference volumes to this planet.", + "items": { + "$ref": "#/definitions/VolumeInfo" + } + }, + "insulatingVolumes": { + "type": "array", + "description": "Add insulating volumes to this planet. These will stop electricty hazard volumes from affecting you (just like the jellyfish).", + "items": { + "$ref": "#/definitions/VolumeInfo" + } + }, + "mapRestrictionVolumes": { + "type": "array", + "description": "Add map restriction volumes to this planet.", + "items": { + "$ref": "#/definitions/VolumeInfo" + } + }, "notificationVolumes": { "type": "array", - "description": "Add notification volumes to this planet", + "description": "Add notification volumes to this planet.", "items": { "$ref": "#/definitions/NotificationVolumeInfo" } }, "revealVolumes": { "type": "array", - "description": "Add triggers that reveal parts of the ship log on this planet", + "description": "Add triggers that reveal parts of the ship log on this planet.", "items": { "$ref": "#/definitions/RevealVolumeInfo" } + }, + "reverbVolumes": { + "type": "array", + "description": "Add reverb volumes to this planet. Great for echoes in caves.", + "items": { + "$ref": "#/definitions/VolumeInfo" + } } } }, @@ -2426,14 +2456,18 @@ "additionalProperties": false, "properties": { "position": { - "description": "The location of this audio volume. Optional (will default to 0,0,0).", + "description": "The location of this volume. Optional (will default to 0,0,0).", "$ref": "#/definitions/MVector3" }, "radius": { "type": "number", - "description": "The radius of this audio volume", + "description": "The radius of this volume.", "format": "float" }, + "parentPath": { + "type": "string", + "description": "The relative path from the planet to the parent of this object. Optional (will default to the root sector)." + }, "audio": { "type": "string", "description": "The audio to use. Can be a path to a .wav/.ogg/.mp3 file, or taken from the AudioClip list." @@ -2495,14 +2529,18 @@ "additionalProperties": false, "properties": { "position": { - "description": "The location of this hazard volume. Optional (will default to 0,0,0).", + "description": "The location of this volume. Optional (will default to 0,0,0).", "$ref": "#/definitions/MVector3" }, "radius": { "type": "number", - "description": "The radius of this hazard volume.", + "description": "The radius of this volume.", "format": "float" }, + "parentPath": { + "type": "string", + "description": "The relative path from the planet to the parent of this object. Optional (will default to the root sector)." + }, "type": { "description": "The type of hazard for this volume.", "default": "general", @@ -2542,7 +2580,7 @@ "enum": [ "none", "general", - "darkMatter", + "ghostMatter", "heat", "fire", "sandfall", @@ -2564,24 +2602,47 @@ "electrical" ] }, - "NotificationVolumeInfo": { + "VolumeInfo": { "type": "object", "additionalProperties": false, "properties": { - "target": { - "description": "What the notification will show for.", - "default": "all", - "$ref": "#/definitions/NotificationTarget" - }, "position": { - "description": "The location of this notification volume. Optional (will default to 0,0,0).", + "description": "The location of this volume. Optional (will default to 0,0,0).", "$ref": "#/definitions/MVector3" }, "radius": { "type": "number", - "description": "The radius of this notification volume.", + "description": "The radius of this volume.", "format": "float" }, + "parentPath": { + "type": "string", + "description": "The relative path from the planet to the parent of this object. Optional (will default to the root sector)." + } + } + }, + "NotificationVolumeInfo": { + "type": "object", + "additionalProperties": false, + "properties": { + "position": { + "description": "The location of this volume. Optional (will default to 0,0,0).", + "$ref": "#/definitions/MVector3" + }, + "radius": { + "type": "number", + "description": "The radius of this volume.", + "format": "float" + }, + "parentPath": { + "type": "string", + "description": "The relative path from the planet to the parent of this object. Optional (will default to the root sector)." + }, + "target": { + "description": "What the notification will show for.", + "default": "all", + "$ref": "#/definitions/NotificationTarget" + }, "entryNotification": { "description": "The notification that will play when you enter this volume.", "$ref": "#/definitions/NotificationInfo" @@ -2626,6 +2687,19 @@ "type": "object", "additionalProperties": false, "properties": { + "position": { + "description": "The location of this volume. Optional (will default to 0,0,0).", + "$ref": "#/definitions/MVector3" + }, + "radius": { + "type": "number", + "description": "The radius of this volume.", + "format": "float" + }, + "parentPath": { + "type": "string", + "description": "The relative path from the planet to the parent of this object. Optional (will default to the root sector)." + }, "maxAngle": { "type": "number", "description": "The max view angle (in degrees) the player can see the volume with to unlock the fact (`observe` only)", @@ -2636,15 +2710,6 @@ "description": "The max distance the user can be away from the volume to reveal the fact (`snapshot` and `observe` only)", "format": "float" }, - "position": { - "description": "The position to place this volume at", - "$ref": "#/definitions/MVector3" - }, - "radius": { - "type": "number", - "description": "The radius of this reveal volume", - "format": "float" - }, "revealOn": { "description": "What needs to be done to the volume to unlock the facts", "default": "enter",