diff --git a/NewHorizons/Assets/addon-manifest.json b/NewHorizons/Assets/addon-manifest.json new file mode 100644 index 00000000..9d8fd2a8 --- /dev/null +++ b/NewHorizons/Assets/addon-manifest.json @@ -0,0 +1,19 @@ +{ + "credits": [ + "xen#Mod Director\n#Programmer", + "Bwc9876#Mod Manager\n#Programmer\n#Dev Ops", + "FreezeDriedMangos#Programmer\n#Dev Tool Creator", + "MegaPiggy#Programmer", + "JohnCorby#Programmer", + "Hawkbat#Programmer", + "Trifid#Tester\n#Programmer", + "Nageld#Programmer", + "Ernesto#Fish", + "With help from#Raicuparta\n#dgarroDC\n#jtsalomo\n#and the modding community", + " ", + "Based off Marshmallow made by#Mister_Nebula", + "With help from#AmazingAlek\n#Raicuparta\n#and the Outer Wilds discord server", + " ", + "This work is unofficial Fan Content and is not affiliated with Mobius Digital" + ] +} diff --git a/NewHorizons/Builder/Atmosphere/AtmosphereBuilder.cs b/NewHorizons/Builder/Atmosphere/AtmosphereBuilder.cs index 7ece9706..3bb7d748 100644 --- a/NewHorizons/Builder/Atmosphere/AtmosphereBuilder.cs +++ b/NewHorizons/Builder/Atmosphere/AtmosphereBuilder.cs @@ -18,7 +18,7 @@ namespace NewHorizons.Builder.Atmosphere Skys.Clear(); } - public static void Make(GameObject planetGO, Sector sector, AtmosphereModule atmosphereModule, float surfaceSize) + public static GameObject Make(GameObject planetGO, Sector sector, AtmosphereModule atmosphereModule, float surfaceSize, bool proxy = false) { GameObject atmoGO = new GameObject("Atmosphere"); atmoGO.SetActive(false); @@ -26,40 +26,76 @@ namespace NewHorizons.Builder.Atmosphere if (atmosphereModule.useAtmosphereShader) { - var atmoSphere = SearchUtilities.Find("TimberHearth_Body/Atmosphere_TH/AtmoSphere"); - if (atmoSphere != null) + if (proxy) { - GameObject atmo = GameObject.Instantiate(atmoSphere, atmoGO.transform, true); - atmo.transform.position = planetGO.transform.TransformPoint(Vector3.zero); - atmo.transform.localScale = Vector3.one * atmosphereModule.size * 1.2f; - - var renderers = atmo.GetComponentsInChildren(); - var material = renderers[0].material; // makes a new material - foreach (var renderer in renderers) + var distantProxy = (SearchUtilities.Find("TimberHearth_DistantProxy", false) ?? SearchUtilities.Find("TimberHearth_DistantProxy(Clone)", false))?.FindChild("Atmosphere_TH/Atmosphere_LOD3"); + if (distantProxy != null) { + GameObject atmo = GameObject.Instantiate(distantProxy, atmoGO.transform, true); + atmo.name = "Atmosphere_LOD3"; + atmo.transform.position = planetGO.transform.TransformPoint(Vector3.zero); + atmo.transform.localScale = Vector3.one * atmosphereModule.size * 1.2f * 2f; + + var renderer = atmo.GetComponent(); + var material = renderer.material; // makes a new material renderer.sharedMaterial = material; - } - material.SetFloat(InnerRadius, atmosphereModule.clouds != null ? atmosphereModule.size : surfaceSize); - material.SetFloat(OuterRadius, atmosphereModule.size * 1.2f); - if (atmosphereModule.atmosphereTint != null) material.SetColor(SkyColor, atmosphereModule.atmosphereTint.ToColor()); + material.SetFloat(InnerRadius, atmosphereModule.clouds != null ? atmosphereModule.size : surfaceSize); + material.SetFloat(OuterRadius, atmosphereModule.size * 1.2f); + if (atmosphereModule.atmosphereTint != null) material.SetColor(SkyColor, atmosphereModule.atmosphereTint.ToColor()); - atmo.SetActive(true); + atmo.SetActive(true); - if (atmosphereModule.atmosphereSunIntensity == 0) - { - // do it based on distance - Skys.Add((planetGO, material)); + if (atmosphereModule.atmosphereSunIntensity == 0) + { + // do it based on distance + Skys.Add((planetGO, material)); + } + else + { + // use the override instead + material.SetFloat(SunIntensity, atmosphereModule.atmosphereSunIntensity); + } } - else + } + else + { + var atmoSphere = SearchUtilities.Find("TimberHearth_Body/Atmosphere_TH/AtmoSphere"); + if (atmoSphere != null) { - // use the override instead - material.SetFloat(SunIntensity, atmosphereModule.atmosphereSunIntensity); + GameObject atmo = GameObject.Instantiate(atmoSphere, atmoGO.transform, true); + atmo.name = "AtmoSphere"; + atmo.transform.position = planetGO.transform.TransformPoint(Vector3.zero); + atmo.transform.localScale = Vector3.one * atmosphereModule.size * 1.2f; + + var renderers = atmo.GetComponentsInChildren(); + var material = renderers[0].material; // makes a new material + foreach (var renderer in renderers) + { + renderer.sharedMaterial = material; + } + material.SetFloat(InnerRadius, atmosphereModule.clouds != null ? atmosphereModule.size : surfaceSize); + material.SetFloat(OuterRadius, atmosphereModule.size * 1.2f); + if (atmosphereModule.atmosphereTint != null) material.SetColor(SkyColor, atmosphereModule.atmosphereTint.ToColor()); + atmo.SetActive(true); + + if (atmosphereModule.atmosphereSunIntensity == 0) + { + // do it based on distance + Skys.Add((planetGO, material)); + } + else + { + // use the override instead + material.SetFloat(SunIntensity, atmosphereModule.atmosphereSunIntensity); + } } } } atmoGO.transform.position = planetGO.transform.TransformPoint(Vector3.zero); atmoGO.SetActive(true); + + return atmoGO; } } } diff --git a/NewHorizons/Builder/Atmosphere/CloudsBuilder.cs b/NewHorizons/Builder/Atmosphere/CloudsBuilder.cs index 53531d86..c18487ba 100644 --- a/NewHorizons/Builder/Atmosphere/CloudsBuilder.cs +++ b/NewHorizons/Builder/Atmosphere/CloudsBuilder.cs @@ -109,26 +109,7 @@ namespace NewHorizons.Builder.Atmosphere // Lightning if (atmo.clouds.hasLightning) { - var lightning = _lightningPrefab.InstantiateInactive(); - lightning.transform.parent = cloudsMainGO.transform; - lightning.transform.localPosition = Vector3.zero; - - var lightningGenerator = lightning.GetComponent(); - lightningGenerator._altitude = (atmo.clouds.outerCloudRadius + atmo.clouds.innerCloudRadius) / 2f; - lightningGenerator._audioSector = sector; - if (atmo.clouds.lightningGradient != null) - { - var gradient = new GradientColorKey[atmo.clouds.lightningGradient.Length]; - - for(int i = 0; i < atmo.clouds.lightningGradient.Length; i++) - { - var pair = atmo.clouds.lightningGradient[i]; - gradient[i] = new GradientColorKey(pair.tint.ToColor(), pair.time); - } - - lightningGenerator._lightColor.colorKeys = gradient; - } - lightning.SetActive(true); + MakeLightning(cloudsMainGO, sector, atmo); } cloudsMainGO.transform.position = planetGO.transform.TransformPoint(Vector3.zero); @@ -140,6 +121,37 @@ namespace NewHorizons.Builder.Atmosphere cloudsMainGO.SetActive(true); } + public static CloudLightningGenerator MakeLightning(GameObject rootObject, Sector sector, AtmosphereModule atmo, bool noAudio = false) + { + var lightning = _lightningPrefab.InstantiateInactive(); + lightning.name = "LightningGenerator"; + lightning.transform.parent = rootObject.transform; + lightning.transform.localPosition = Vector3.zero; + + var lightningGenerator = lightning.GetComponent(); + lightningGenerator._altitude = (atmo.clouds.outerCloudRadius + atmo.clouds.innerCloudRadius) / 2f; + if (noAudio) + { + lightningGenerator._audioPrefab = null; + lightningGenerator._audioSourcePool = null; + } + lightningGenerator._audioSector = sector; + if (atmo.clouds.lightningGradient != null) + { + var gradient = new GradientColorKey[atmo.clouds.lightningGradient.Length]; + + for (int i = 0; i < atmo.clouds.lightningGradient.Length; i++) + { + var pair = atmo.clouds.lightningGradient[i]; + gradient[i] = new GradientColorKey(pair.tint.ToColor(), pair.time); + } + + lightningGenerator._lightColor.colorKeys = gradient; + } + lightning.SetActive(true); + return lightningGenerator; + } + public static GameObject MakeTopClouds(GameObject rootObject, AtmosphereModule atmo, IModBehaviour mod) { Color cloudTint = atmo.clouds.tint?.ToColor() ?? UnityEngine.Color.white; @@ -210,11 +222,14 @@ namespace NewHorizons.Builder.Atmosphere cloudsTopGO.layer = LayerMask.NameToLayer("IgnoreSun"); } - RotateTransform topRT = cloudsTopGO.AddComponent(); - // Idk why but the axis is weird - topRT._localAxis = atmo.clouds.cloudsPrefab == CloudPrefabType.Basic ? Vector3.forward : Vector3.up; - topRT._degreesPerSecond = atmo.clouds.rotationSpeed; - topRT._randomizeRotationRate = false; + if (atmo.clouds.rotationSpeed != 0f) + { + RotateTransform topRT = cloudsTopGO.AddComponent(); + // Idk why but the axis is weird + topRT._localAxis = atmo.clouds.cloudsPrefab == CloudPrefabType.Basic ? Vector3.forward : Vector3.up; + topRT._degreesPerSecond = atmo.clouds.rotationSpeed; + topRT._randomizeRotationRate = false; + } cloudsTopGO.transform.localPosition = Vector3.zero; diff --git a/NewHorizons/Builder/Atmosphere/EffectsBuilder.cs b/NewHorizons/Builder/Atmosphere/EffectsBuilder.cs index 0271e8ed..fb405705 100644 --- a/NewHorizons/Builder/Atmosphere/EffectsBuilder.cs +++ b/NewHorizons/Builder/Atmosphere/EffectsBuilder.cs @@ -23,6 +23,7 @@ namespace NewHorizons.Builder.Atmosphere if (config.Atmosphere.hasRain) { var rainGO = GameObject.Instantiate(SearchUtilities.Find("GiantsDeep_Body/Sector_GD/Sector_GDInterior/Effects_GDInterior/Effects_GD_Rain"), effectsGO.transform); + rainGO.name = "RainEmitter"; rainGO.transform.position = planetGO.transform.position; var pvc = rainGO.GetComponent(); diff --git a/NewHorizons/Builder/Atmosphere/FogBuilder.cs b/NewHorizons/Builder/Atmosphere/FogBuilder.cs index 3854fe29..052825d0 100644 --- a/NewHorizons/Builder/Atmosphere/FogBuilder.cs +++ b/NewHorizons/Builder/Atmosphere/FogBuilder.cs @@ -14,7 +14,7 @@ namespace NewHorizons.Builder.Atmosphere private static readonly int DensityExponent = Shader.PropertyToID("_DensityExp"); private static readonly int ColorRampTexture = Shader.PropertyToID("_ColorRampTex"); - public static void Make(GameObject planetGO, Sector sector, AtmosphereModule atmo) + public static PlanetaryFogController Make(GameObject planetGO, Sector sector, AtmosphereModule atmo) { if (_ramp == null) _ramp = ImageUtilities.GetTexture(Main.Instance, "Assets/textures/FogColorRamp.png"); @@ -25,9 +25,9 @@ namespace NewHorizons.Builder.Atmosphere // Going to copy from dark bramble var dbFog = SearchUtilities.Find("DarkBramble_Body/Atmosphere_DB/FogLOD"); - if (dbFog == null) return; + if (dbFog == null) return null; var dbPlanetaryFogController = SearchUtilities.Find("DarkBramble_Body/Atmosphere_DB/FogSphere_DB")?.GetComponent(); - if (dbPlanetaryFogController == null) return; + if (dbPlanetaryFogController == null) return null; MeshFilter MF = fogGO.AddComponent(); MF.mesh = dbFog.GetComponent().mesh; @@ -60,6 +60,41 @@ namespace NewHorizons.Builder.Atmosphere fogGO.transform.position = planetGO.transform.position; fogGO.SetActive(true); + return PFC; + } + + public static Renderer MakeProxy(GameObject proxyGO, AtmosphereModule atmo) + { + if (_ramp == null) _ramp = ImageUtilities.GetTexture(Main.Instance, "Assets/textures/FogColorRamp.png"); + + GameObject fogGO = new GameObject("FogSphere"); + fogGO.SetActive(false); + fogGO.transform.parent = proxyGO.transform; + fogGO.transform.localScale = Vector3.one * atmo.fogSize; + + var fog = (SearchUtilities.Find("TimberHearth_DistantProxy", false) ?? SearchUtilities.Find("TimberHearth_DistantProxy(Clone)", false))?.FindChild("Atmosphere_TH/FogSphere"); + + MeshFilter MF = fogGO.AddComponent(); + MF.mesh = fog.GetComponent().mesh; + + MeshRenderer MR = fogGO.AddComponent(); + MR.materials = fog.GetComponent().materials; + MR.allowOcclusionWhenDynamic = true; + + var colorRampTexture = atmo.fogTint == null ? _ramp : ImageUtilities.TintImage(_ramp, atmo.fogTint.ToColor()); + if (atmo.fogTint != null) + { + MR.material.SetColor(Tint, atmo.fogTint.ToColor()); + } + MR.material.SetFloat(Radius, atmo.fogSize); + MR.material.SetFloat(Density, atmo.fogDensity); + MR.material.SetFloat(DensityExponent, 1); + MR.material.SetTexture(ColorRampTexture, colorRampTexture); + + fogGO.transform.position = proxyGO.transform.position; + + fogGO.SetActive(true); + return MR; } } } diff --git a/NewHorizons/Builder/Body/AsteroidBeltBuilder.cs b/NewHorizons/Builder/Body/AsteroidBeltBuilder.cs index b106ebb4..21b6e4eb 100644 --- a/NewHorizons/Builder/Body/AsteroidBeltBuilder.cs +++ b/NewHorizons/Builder/Body/AsteroidBeltBuilder.cs @@ -62,7 +62,7 @@ namespace NewHorizons.Builder.Body config.ProcGen = new ProcGenModule() { scale = size, - color = new MColor(126, 94, 73, 255) + color = new MColor(126, 94, 73) }; } else diff --git a/NewHorizons/Builder/Body/GeometryBuilder.cs b/NewHorizons/Builder/Body/GeometryBuilder.cs index cc4b0318..bf2bc647 100644 --- a/NewHorizons/Builder/Body/GeometryBuilder.cs +++ b/NewHorizons/Builder/Body/GeometryBuilder.cs @@ -4,7 +4,7 @@ namespace NewHorizons.Builder.Body { public static class GeometryBuilder { - public static void Make(GameObject planetGO, Sector sector, float groundScale) + public static GameObject Make(GameObject planetGO, Sector sector, float groundScale) { GameObject groundGO = GameObject.CreatePrimitive(PrimitiveType.Sphere); groundGO.transform.name = "GroundSphere"; @@ -23,6 +23,8 @@ namespace NewHorizons.Builder.Body groundGO.transform.localScale *= 2; } groundGO.SetActive(true); + + return groundGO; } } } diff --git a/NewHorizons/Builder/Body/HeightMapBuilder.cs b/NewHorizons/Builder/Body/HeightMapBuilder.cs index cf704eb7..3e8a06f5 100644 --- a/NewHorizons/Builder/Body/HeightMapBuilder.cs +++ b/NewHorizons/Builder/Body/HeightMapBuilder.cs @@ -14,7 +14,7 @@ namespace NewHorizons.Builder.Body { public static Shader PlanetShader; - public static void Make(GameObject planetGO, Sector sector, HeightMapModule module, IModBehaviour mod, int resolution, bool useLOD = false) + public static GameObject Make(GameObject planetGO, Sector sector, HeightMapModule module, IModBehaviour mod, int resolution, bool useLOD = false) { var deleteHeightmapFlag = false; @@ -60,7 +60,7 @@ namespace NewHorizons.Builder.Body catch (Exception e) { Logger.LogError($"Couldn't load HeightMap textures:\n{e}"); - return; + return null; } GameObject cubeSphere = new GameObject("CubeSphere"); @@ -111,6 +111,8 @@ namespace NewHorizons.Builder.Body // Now that we've made the mesh we can delete the heightmap texture if (deleteHeightmapFlag) ImageUtilities.DeleteTexture(mod, module.heightMap, heightMap); + + return cubeSphere; } public static MeshRenderer MakeLODTerrain(GameObject root, Texture2D heightMap, Texture2D textureMap, float minHeight, float maxHeight, int resolution, Vector3 stretch) diff --git a/NewHorizons/Builder/Body/LavaBuilder.cs b/NewHorizons/Builder/Body/LavaBuilder.cs index dc1d4d47..95878f9e 100644 --- a/NewHorizons/Builder/Body/LavaBuilder.cs +++ b/NewHorizons/Builder/Body/LavaBuilder.cs @@ -52,6 +52,7 @@ namespace NewHorizons.Builder.Body sectorProxy.SetSector(sector); var destructionVolume = GameObject.Instantiate(SearchUtilities.Find("VolcanicMoon_Body/MoltenCore_VM/DestructionVolume"), moltenCore.transform); + destructionVolume.name = "DestructionVolume"; destructionVolume.GetComponent().radius = 1; destructionVolume.SetActive(true); diff --git a/NewHorizons/Builder/Body/ProcGenBuilder.cs b/NewHorizons/Builder/Body/ProcGenBuilder.cs index 5d696b1e..e168c678 100644 --- a/NewHorizons/Builder/Body/ProcGenBuilder.cs +++ b/NewHorizons/Builder/Body/ProcGenBuilder.cs @@ -9,7 +9,7 @@ namespace NewHorizons.Builder.Body private static Material quantumMaterial; private static Material iceMaterial; - public static void Make(GameObject planetGO, Sector sector, ProcGenModule module) + public static GameObject Make(GameObject planetGO, Sector sector, ProcGenModule module) { if (quantumMaterial == null) quantumMaterial = SearchUtilities.FindResourceOfTypeAndName("Rock_QM_EyeRock_mat"); if (iceMaterial == null) iceMaterial = SearchUtilities.FindResourceOfTypeAndName("Rock_BH_IceSpike_mat"); @@ -40,6 +40,7 @@ namespace NewHorizons.Builder.Body if (superGroup != null) icosphere.AddComponent()._superGroup = superGroup; icosphere.SetActive(true); + return icosphere; } } } diff --git a/NewHorizons/Builder/Body/ProxyBuilder.cs b/NewHorizons/Builder/Body/ProxyBuilder.cs index efc2c70b..f73e8716 100644 --- a/NewHorizons/Builder/Body/ProxyBuilder.cs +++ b/NewHorizons/Builder/Body/ProxyBuilder.cs @@ -34,9 +34,13 @@ namespace NewHorizons.Builder.Body var proxyName = $"{body.Config.name}_Proxy"; var newProxy = new GameObject(proxyName); + newProxy.SetActive(false); try { + var proxyController = newProxy.AddComponent(); + proxyController.astroName = body.Config.name; + // We want to take the largest size I think var realSize = body.Config.Base.surfaceSize; @@ -45,32 +49,57 @@ namespace NewHorizons.Builder.Body HeightMapBuilder.Make(newProxy, null, body.Config.HeightMap, body.Mod, 20); if (realSize < body.Config.HeightMap.maxHeight) realSize = body.Config.HeightMap.maxHeight; } + if (body.Config.Base.groundSize != 0) { GeometryBuilder.Make(newProxy, null, body.Config.Base.groundSize); if (realSize < body.Config.Base.groundSize) realSize = body.Config.Base.groundSize; } - if (body.Config.Atmosphere?.clouds != null) + + if (body.Config.Atmosphere != null) { - CloudsBuilder.MakeTopClouds(newProxy, body.Config.Atmosphere, body.Mod); - if (realSize < body.Config.Atmosphere.size) realSize = body.Config.Atmosphere.size; + proxyController._atmosphere = AtmosphereBuilder.Make(newProxy, null, body.Config.Atmosphere, body.Config.Base.surfaceSize, true).GetComponentInChildren(); + proxyController._mieCurveMaxVal = 0.1f; + proxyController._mieCurve = AnimationCurve.EaseInOut(0.0011f, 1, 1, 0); + + if (body.Config.Atmosphere.fogSize != 0) + { + proxyController._fog = FogBuilder.MakeProxy(newProxy, body.Config.Atmosphere); + proxyController._fogCurveMaxVal = body.Config.Atmosphere.fogDensity; + proxyController._fogCurve = AnimationCurve.Linear(0, 1, 1, 0); + } + + if (body.Config.Atmosphere.clouds != null) + { + proxyController._mainBody = CloudsBuilder.MakeTopClouds(newProxy, body.Config.Atmosphere, body.Mod).GetComponent(); + if (body.Config.Atmosphere.clouds.hasLightning) + { + proxyController._lightningGenerator = CloudsBuilder.MakeLightning(newProxy, null, body.Config.Atmosphere, true); + } + if (realSize < body.Config.Atmosphere.size) realSize = body.Config.Atmosphere.size; + } } + if (body.Config.Ring != null) { RingBuilder.MakeRingGraphics(newProxy, null, body.Config.Ring, body.Mod); if (realSize < body.Config.Ring.outerRadius) realSize = body.Config.Ring.outerRadius; } + if (body.Config.Star != null) { var starGO = StarBuilder.MakeStarProxy(planetGO, newProxy, body.Config.Star, body.Mod); if (realSize < body.Config.Star.size) realSize = body.Config.Star.size; } + + GameObject procGen = null; if (body.Config.ProcGen != null) { - ProcGenBuilder.Make(newProxy, null, body.Config.ProcGen); + procGen = ProcGenBuilder.Make(newProxy, null, body.Config.ProcGen); if (realSize < body.Config.ProcGen.scale) realSize = body.Config.ProcGen.scale; } + if (body.Config.Lava != null) { var sphere = AddColouredSphere(newProxy, body.Config.Lava.size, body.Config.Lava.curve, Color.black); @@ -80,18 +109,21 @@ namespace NewHorizons.Builder.Body if (body.Config.Lava.tint != null) material.SetColor(EmissionColor, body.Config.Lava.tint.ToColor()); sphere.GetComponent().material = material; } + if (body.Config.Water != null) { var colour = body.Config.Water.tint?.ToColor() ?? Color.blue; AddColouredSphere(newProxy, body.Config.Water.size, body.Config.Water.curve, colour); if (realSize < body.Config.Water.size) realSize = body.Config.Water.size; } + if (body.Config.Sand != null) { var colour = body.Config.Sand.tint?.ToColor() ?? Color.yellow; AddColouredSphere(newProxy, body.Config.Sand.size, body.Config.Sand.curve, colour); if (realSize < body.Config.Sand.size) realSize = body.Config.Sand.size; } + // Could improve this to actually use the proper renders and materials if (body.Config.Props?.singularities != null) { @@ -109,10 +141,12 @@ namespace NewHorizons.Builder.Body if (realSize < singularity.size) realSize = singularity.size; } } + if (body.Config.Base.hasCometTail) { CometTailBuilder.Make(newProxy, null, body.Config); } + if (body.Config.Props?.proxyDetails != null) { foreach (var detailInfo in body.Config.Props.proxyDetails) @@ -121,6 +155,11 @@ namespace NewHorizons.Builder.Body } } + if (body.Config.Base.hasSupernovaShockEffect && body.Config.Star == null && body.Config.name != "Sun" && body.Config.FocalPoint == null) + { + proxyController._supernovaPlanetEffectController = SupernovaEffectBuilder.Make(newProxy, null, body.Config, procGen, null, null, null, proxyController._atmosphere, proxyController._fog); + } + // Remove all collisions if there are any foreach (var col in newProxy.GetComponentsInChildren()) { @@ -138,8 +177,6 @@ namespace NewHorizons.Builder.Body tessellatedRenderer.enabled = true; } - var proxyController = newProxy.AddComponent(); - proxyController.astroName = body.Config.name; proxyController._realObjectDiameter = realSize; } catch (Exception ex) @@ -147,6 +184,8 @@ namespace NewHorizons.Builder.Body Logger.LogError($"Exception thrown when generating proxy for [{body.Config.name}]:\n{ex}"); GameObject.Destroy(newProxy); } + + newProxy.SetActive(true); } private static GameObject AddColouredSphere(GameObject rootObj, float size, VariableSizeModule.TimeValuePair[] curve, Color color) diff --git a/NewHorizons/Builder/Body/SingularityBuilder.cs b/NewHorizons/Builder/Body/SingularityBuilder.cs index a58a3595..1676879a 100644 --- a/NewHorizons/Builder/Body/SingularityBuilder.cs +++ b/NewHorizons/Builder/Body/SingularityBuilder.cs @@ -140,6 +140,7 @@ namespace NewHorizons.Builder.Body if (sizeController != null) sizeController.audioSource = blackHoleAudioSource; var blackHoleOneShot = GameObject.Instantiate(SearchUtilities.Find("BrittleHollow_Body/BlackHole_BH/BlackHoleEmissionOneShot"), blackHole.transform); + blackHoleOneShot.name = "BlackHoleEmissionOneShot"; var oneShotAudioSource = blackHoleOneShot.GetComponent(); oneShotAudioSource.maxDistance = size * 3f; oneShotAudioSource.minDistance = size * 0.4f; diff --git a/NewHorizons/Builder/Body/StarBuilder.cs b/NewHorizons/Builder/Body/StarBuilder.cs index 65d84c1f..10b27ba1 100644 --- a/NewHorizons/Builder/Body/StarBuilder.cs +++ b/NewHorizons/Builder/Body/StarBuilder.cs @@ -142,11 +142,14 @@ namespace NewHorizons.Builder.Body controller.supernova = supernova; controller.StartColour = starModule.tint; controller.EndColour = starModule.endTint; + controller.SupernovaColour = starModule.supernovaTint; controller.WillExplode = starModule.goSupernova; controller.lifespan = starModule.lifespan; controller.normalRamp = !string.IsNullOrEmpty(starModule.starRampTexture) ? ImageUtilities.GetTexture(mod, starModule.starRampTexture) : ramp; controller._destructionVolume = deathVolume.GetComponent(); controller._planetDestructionVolume = planetDestructionVolume.GetComponent(); + controller._destructionFluidVolume = planetDestructionVolume.GetComponent(); + controller._planetDestructionFluidVolume = planetDestructionVolume.GetComponent(); if (!string.IsNullOrEmpty(starModule.starCollapseRampTexture)) { controller.collapseRamp = ImageUtilities.GetTexture(mod, starModule.starCollapseRampTexture); @@ -192,6 +195,7 @@ namespace NewHorizons.Builder.Body controller.supernova = supernova; controller.StartColour = starModule.tint; controller.EndColour = starModule.endTint; + controller.SupernovaColour = starModule.supernovaTint; controller.WillExplode = starModule.goSupernova; controller.lifespan = starModule.lifespan; controller.normalRamp = !string.IsNullOrEmpty(starModule.starRampTexture) ? ImageUtilities.GetTexture(mod, starModule.starRampTexture) : ramp; @@ -283,12 +287,13 @@ namespace NewHorizons.Builder.Body private static SupernovaEffectController MakeSupernova(GameObject starGO, StarModule starModule) { var supernovaGO = SearchUtilities.Find("Sun_Body/Sector_SUN/Effects_SUN/Supernova").InstantiateInactive(); + supernovaGO.name = "Supernova"; supernovaGO.transform.SetParent(starGO.transform); supernovaGO.transform.localPosition = Vector3.zero; var supernova = supernovaGO.GetComponent(); supernova._surface = starGO.GetComponentInChildren(); - supernova._supernovaScale = AnimationCurve.Linear(5, 0, 15, starModule.supernovaSize); + supernova._supernovaScale = new AnimationCurve(new Keyframe(0, 200, 0, 0, 1f / 3f, 1f / 3f), new Keyframe(45, starModule.supernovaSize, 1758.508f, 1758.508f, 1f / 3f, 1f / 3f)); supernova._supernovaVolume = null; if (starModule.supernovaTint != null) diff --git a/NewHorizons/Builder/Body/SupernovaEffectBuilder.cs b/NewHorizons/Builder/Body/SupernovaEffectBuilder.cs new file mode 100644 index 00000000..80d6ea31 --- /dev/null +++ b/NewHorizons/Builder/Body/SupernovaEffectBuilder.cs @@ -0,0 +1,163 @@ +using UnityEngine; +using NewHorizons.Utility; +using NewHorizons.External.Configs; +using NewHorizons.Components; +using System.Linq; +using NewHorizons.Handlers; + +namespace NewHorizons.Builder.Body +{ + public static class SupernovaEffectBuilder + { + public static NHSupernovaPlanetEffectController Make(GameObject planetGO, Sector sector, PlanetConfig config, GameObject procGen, Light ambientLight, PlanetaryFogController fog, LODGroup atmosphere, Renderer atmosphereRenderer, Renderer fogImpostor) + { + var vanillaController = planetGO.GetComponentInChildren(); + if (vanillaController != null) + { + ReplaceVanillaWithNH(vanillaController); + } + + var currentController = planetGO.GetComponentInChildren(); + if (currentController != null) + { + if (currentController._ambientLight == null && ambientLight != null) + { + currentController._ambientLight = ambientLight; + currentController._ambientLightOrigIntensity = config.Base.ambientLight; + } + + if (currentController._atmosphere == null && atmosphere != null) currentController._atmosphere = atmosphere; + + if (currentController._fog == null && fog != null) currentController._fog = fog; + + return currentController; + } + else + { + var supernovaController = new GameObject("SupernovaController"); + supernovaController.transform.SetParent(sector?.transform ?? planetGO.transform, false); + var supernovaEffectController = supernovaController.AddComponent(); + supernovaEffectController._ambientLight = ambientLight; + supernovaEffectController._ambientLightOrigIntensity = config.Base.ambientLight; + supernovaEffectController._atmosphere = atmosphere; + supernovaEffectController._atmosphereRenderer = atmosphereRenderer; + supernovaEffectController._fog = fog; + supernovaEffectController._fogImpostor = fogImpostor; + + var shockLayerGD = SearchUtilities.Find("GiantsDeep_Body/Shocklayer_GD"); + var shockLayer = new GameObject("ShockLayer"); + shockLayer.transform.SetParent(sector?.transform ?? planetGO.transform, false); + shockLayer.AddComponent().sharedMesh = shockLayerGD.GetComponent().sharedMesh; + + var shockLayerMaterial = new Material(shockLayerGD.GetComponent().sharedMaterial); + shockLayerMaterial.name = "ShockLayer_mat"; + + var shockLayerRenderer = shockLayer.AddComponent(); + shockLayerRenderer.sharedMaterial = shockLayerMaterial; + supernovaEffectController._shockLayer = shockLayerRenderer; + + var biggestSize = config.Base.surfaceSize; + var noMeshChange = false; + + if (config.Atmosphere != null) + { + if (config.Atmosphere.size > biggestSize) biggestSize = config.Atmosphere.size; + if (config.Atmosphere.fogSize > biggestSize) biggestSize = config.Atmosphere.fogSize; + if (config.Atmosphere.clouds != null) + { + noMeshChange = true; + if (config.Atmosphere.clouds.innerCloudRadius > biggestSize) biggestSize = config.Atmosphere.clouds.innerCloudRadius; + if (config.Atmosphere.clouds.outerCloudRadius > biggestSize) biggestSize = config.Atmosphere.clouds.outerCloudRadius; + } + } + + if (config.Base.groundSize > biggestSize) + { + noMeshChange = true; + biggestSize = config.Base.groundSize; + } + + if (config.HeightMap != null) + { + if (config.HeightMap.minHeight > biggestSize) biggestSize = config.HeightMap.minHeight; + if (config.HeightMap.maxHeight > biggestSize) biggestSize = config.HeightMap.maxHeight; + } + + if (config.ProcGen != null) + { + if (config.ProcGen.scale > biggestSize) biggestSize = config.ProcGen.scale; + } + + if (config.Lava != null) + { + noMeshChange = true; + var lavaSize = config.Lava.size; + if (config.Lava.curve != null) lavaSize *= config.Lava.curve.Max(tvp => tvp.value); + if (lavaSize > biggestSize) biggestSize = lavaSize; + } + + if (config.Water != null) + { + noMeshChange = true; + var waterSize = config.Water.size; + if (config.Water.curve != null) waterSize *= config.Water.curve.Max(tvp => tvp.value); + if (waterSize > biggestSize) biggestSize = waterSize; + } + + if (config.Sand != null) + { + noMeshChange = true; + var sandSize = config.Sand.size; + if (config.Sand.curve != null) sandSize *= config.Sand.curve.Max(tvp => tvp.value); + if (sandSize > biggestSize) biggestSize = sandSize; + } + + if (config.Props?.singularities != null) + { + noMeshChange = true; + foreach (var singularity in config.Props.singularities) + { + if (singularity.size > biggestSize) biggestSize = singularity.size; + } + } + + supernovaEffectController._shockLayerStartRadius = biggestSize; + supernovaEffectController._shockLayerFullRadius = biggestSize * 10f; + supernovaEffectController._shockLayerTrailFlare = 100; + supernovaEffectController._shockLayerTrailLength = biggestSize < 600 ? 300 : 600; + + shockLayer.transform.position = planetGO.transform.position; + shockLayer.transform.localScale = Vector3.one * biggestSize * 1.1f; + + if (!noMeshChange && procGen != null) + { + shockLayer.GetComponent().sharedMesh = procGen.GetComponent().sharedMesh; + shockLayer.transform.localScale = Vector3.one * 1.1f; + shockLayer.transform.rotation = Quaternion.Euler(90, 0, 0); + } + + return supernovaEffectController; + } + } + + public static void ReplaceVanillaWithNH(SupernovaPlanetEffectController vanillaController) + { + if (vanillaController._shockLayer != null) vanillaController._shockLayer.gameObject.SetActive(true); + var supernovaEffectController = vanillaController.gameObject.GetAddComponent(); + supernovaEffectController._atmosphere = vanillaController._atmosphere; + supernovaEffectController._ambientLight = vanillaController._ambientLight; + supernovaEffectController._ambientLightOrigIntensity = vanillaController._ambientLightOrigIntensity; + supernovaEffectController._atmosphere = vanillaController._atmosphere; + supernovaEffectController._fog = vanillaController._fog; + supernovaEffectController._fogOrigTint = vanillaController._fogOrigTint; + supernovaEffectController._shockLayer = vanillaController._shockLayer; + supernovaEffectController._shockLayerColor = vanillaController._shockLayerColor; + supernovaEffectController._shockLayerFullRadius = vanillaController._shockLayerFullRadius; + supernovaEffectController._shockLayerStartRadius = vanillaController._shockLayerStartRadius; + supernovaEffectController._shockLayerTrailFlare = vanillaController._shockLayerTrailFlare; + supernovaEffectController._shockLayerTrailLength = vanillaController._shockLayerTrailLength; + supernovaEffectController._sunController = SearchUtilities.Find("Sun_Body").GetComponent(); + Object.Destroy(vanillaController); + } + } +} diff --git a/NewHorizons/Builder/General/AmbientLightBuilder.cs b/NewHorizons/Builder/General/AmbientLightBuilder.cs index 157a91f7..a3157165 100644 --- a/NewHorizons/Builder/General/AmbientLightBuilder.cs +++ b/NewHorizons/Builder/General/AmbientLightBuilder.cs @@ -4,10 +4,10 @@ namespace NewHorizons.Builder.General { public static class AmbientLightBuilder { - public static void Make(GameObject planetGO, Sector sector, float scale, float intensity) + public static Light Make(GameObject planetGO, Sector sector, float scale, float intensity) { - var ambientLight = Main.Instance.CurrentStarSystem == "EyeOfTheUniverse" ? SearchUtilities.Find("EyeOfTheUniverse_Body/Sector_EyeOfTheUniverse/SixthPlanet_Root/QuantumMoonProxy_Pivot/QuantumMoonProxy_Root/MoonState_Root/AmbientLight_QM") : SearchUtilities.Find("BrittleHollow_Body/AmbientLight_BH_Surface"); - if (ambientLight == null) return; + var ambientLight = Main.Instance.CurrentStarSystem == "EyeOfTheUniverse" ? SearchUtilities.Find("EyeOfTheUniverse_Body/Sector_EyeOfTheUniverse/SixthPlanet_Root/QuantumMoonProxy_Pivot/QuantumMoonProxy_Root/MoonState_Root/AmbientLight_QM") : SearchUtilities.Find("QuantumMoon_Body/AmbientLight_QM"); + if (ambientLight == null) return null; GameObject lightGO = GameObject.Instantiate(ambientLight, sector?.transform ?? planetGO.transform); lightGO.transform.position = planetGO.transform.position; @@ -20,9 +20,17 @@ namespace NewHorizons.Builder.General * A is the intensity and its like square rooted and squared and idgi */ - light.color = new Color(0.0f, 0.0f, 0.8f, 0.0225f); + light.color = new Color(0.5f, 0.0f, 0.8f, 0.0225f); light.range = scale; light.intensity = intensity; + + /*if (tint != null) + { + var cubemap = ImageUtilities.TintImage(ImageUtilities.GetTexture(Main.Instance, "Assets/textures/AmbientLight_QM.png"), tint.ToColor()); + light.cookie = cubemap; + }*/ + + return light; } } } diff --git a/NewHorizons/Builder/General/DetectorBuilder.cs b/NewHorizons/Builder/General/DetectorBuilder.cs index 82671951..579d564a 100644 --- a/NewHorizons/Builder/General/DetectorBuilder.cs +++ b/NewHorizons/Builder/General/DetectorBuilder.cs @@ -1,5 +1,7 @@ using NewHorizons.Components.Orbital; using NewHorizons.External.Configs; +using NewHorizons.Utility; +using System.Collections.Generic; using UnityEngine; using Logger = NewHorizons.Utility.Logger; namespace NewHorizons.Builder.General @@ -33,10 +35,61 @@ namespace NewHorizons.Builder.General OWRB.RegisterAttachedFluidDetector(fluidDetector); - // Could copy the splash from the interloper as well some day + var splashEffects = new List(); + + var cometDetector = SearchUtilities.Find("Comet_Body/Detector_CO")?.GetComponent(); + if (cometDetector != null) + { + foreach (var splashEffect in cometDetector._splashEffects) + { + splashEffects.Add(new SplashEffect + { + fluidType = splashEffect.fluidType, + ignoreSphereAligment = splashEffect.ignoreSphereAligment, + triggerEvent = splashEffect.triggerEvent, + minImpactSpeed = 15, + splashPrefab = splashEffect.splashPrefab + }); + } + } + + var islandDetector = SearchUtilities.Find("GabbroIsland_Body/Detector_GabbroIsland")?.GetComponent(); + if (islandDetector != null) + { + foreach (var splashEffect in islandDetector._splashEffects) + { + splashEffects.Add(new SplashEffect + { + fluidType = splashEffect.fluidType, + ignoreSphereAligment = splashEffect.ignoreSphereAligment, + triggerEvent = splashEffect.triggerEvent, + minImpactSpeed = 15, + splashPrefab = splashEffect.splashPrefab + }); + } + } + + var shipDetector = SearchUtilities.Find("Ship_Body/ShipDetector")?.GetComponent(); + if (shipDetector != null) + { + foreach (var splashEffect in shipDetector._splashEffects) + { + if (splashEffect.fluidType == FluidVolume.Type.SAND) + splashEffects.Add(new SplashEffect + { + fluidType = splashEffect.fluidType, + ignoreSphereAligment = splashEffect.ignoreSphereAligment, + triggerEvent = splashEffect.triggerEvent, + minImpactSpeed = 15, + splashPrefab = splashEffect.splashPrefab + }); + } + } + + fluidDetector._splashEffects = splashEffects.ToArray(); } - SetDetector(primaryBody, astroObject, forceDetector); + if (!config.Orbit.isStatic) SetDetector(primaryBody, astroObject, forceDetector); detectorGO.SetActive(true); return detectorGO; @@ -113,4 +166,4 @@ namespace NewHorizons.Builder.General secondaryCFD._inheritElement0 = false; } } -} +} \ No newline at end of file diff --git a/NewHorizons/Builder/Props/TornadoBuilder.cs b/NewHorizons/Builder/Props/TornadoBuilder.cs index 49b2f43a..e166bea0 100644 --- a/NewHorizons/Builder/Props/TornadoBuilder.cs +++ b/NewHorizons/Builder/Props/TornadoBuilder.cs @@ -36,7 +36,8 @@ namespace NewHorizons.Builder.Props } if (_hurricanePrefab == null) { - _hurricanePrefab = SearchUtilities.Find("GiantsDeep_Body/Sector_GD/Sector_GDInterior/Tornadoes_GDInterior/Hurricane/").InstantiateInactive(); + _hurricanePrefab = SearchUtilities.Find("GiantsDeep_Body/Sector_GD/Sector_GDInterior/Tornadoes_GDInterior/Hurricane").InstantiateInactive(); + _hurricanePrefab.name = "Hurricane_Prefab"; // For some reason they put the hurricane at the origin and offset all its children (450) // Increasing by 40 will keep the bottom above the ground foreach (Transform child in _hurricanePrefab.transform) @@ -84,6 +85,7 @@ namespace NewHorizons.Builder.Props private static void MakeTornado(GameObject planetGO, Sector sector, PropModule.TornadoInfo info, Vector3 position, bool downwards) { var tornadoGO = downwards ? _downPrefab.InstantiateInactive() : _upPrefab.InstantiateInactive(); + tornadoGO.name = downwards ? "Tornado_Down" : "Tornado_Up"; tornadoGO.transform.parent = sector.transform; tornadoGO.transform.position = planetGO.transform.TransformPoint(position); tornadoGO.transform.rotation = Quaternion.FromToRotation(Vector3.up, sector.transform.TransformDirection(position.normalized)); @@ -168,6 +170,7 @@ namespace NewHorizons.Builder.Props private static void MakeHurricane(GameObject planetGO, Sector sector, PropModule.TornadoInfo info, Vector3 position, bool hasClouds) { var hurricaneGO = _hurricanePrefab.InstantiateInactive(); + hurricaneGO.name = "Hurricane"; hurricaneGO.transform.parent = sector.transform; hurricaneGO.transform.position = planetGO.transform.TransformPoint(position); hurricaneGO.transform.rotation = Quaternion.FromToRotation(Vector3.up, sector.transform.TransformDirection(position.normalized)); diff --git a/NewHorizons/Components/NHProxy.cs b/NewHorizons/Components/NHProxy.cs index f9a7e37d..f19f9ae9 100644 --- a/NewHorizons/Components/NHProxy.cs +++ b/NewHorizons/Components/NHProxy.cs @@ -1,4 +1,4 @@ -using NewHorizons.Components.SizeControllers; +using NewHorizons.Components.SizeControllers; using NewHorizons.Utility; using System.Collections.Generic; using UnityEngine; @@ -13,6 +13,9 @@ namespace NewHorizons.Components private TessellatedRenderer[] _starTessellatedRenderers; private ParticleSystemRenderer[] _starParticleRenderers; private SolarFlareEmitter _solarFlareEmitter; + public CloudLightningGenerator _lightningGenerator; + public MeshRenderer _mainBody; + public NHSupernovaPlanetEffectController _supernovaPlanetEffectController; public override void Awake() { @@ -30,6 +33,10 @@ namespace NewHorizons.Components _solarFlareEmitter = _star.GetComponentInChildren(); } + if (_lightningGenerator == null) _lightningGenerator = GetComponentInChildren(); + + if (_supernovaPlanetEffectController == null) _supernovaPlanetEffectController = GetComponentInChildren(); + // Start off _outOfRange = false; ToggleRendering(false); @@ -39,9 +46,9 @@ namespace NewHorizons.Components { AstroObject astroObject = AstroObjectLocator.GetAstroObject(astroName); _realObjectTransform = astroObject.transform; - _hasAtmosphere = _atmosphere != null; - if (_hasAtmosphere) + if (_atmosphere != null) { + _hasAtmosphere = true; _atmosphereMaterial = new Material(_atmosphere.sharedMaterial); _baseAtmoMatShellInnerRadius = _atmosphereMaterial.GetFloat(propID_AtmoInnerRadius); _baseAtmoMatShellOuterRadius = _atmosphereMaterial.GetFloat(propID_AtmoOuterRadius); @@ -73,6 +80,22 @@ namespace NewHorizons.Components _solarFlareEmitter.gameObject.SetActive(on); } + if (_mainBody != null) + { + _mainBody.enabled = on; + } + + if (_lightningGenerator != null) + { + _lightningGenerator.enabled = on; + } + + if (_supernovaPlanetEffectController != null) + { + if (on) _supernovaPlanetEffectController.Enable(); + else _supernovaPlanetEffectController.Disable(); + } + foreach (var renderer in _starRenderers) { renderer.enabled = on; diff --git a/NewHorizons/Components/NHSupernovaPlanetEffectController.cs b/NewHorizons/Components/NHSupernovaPlanetEffectController.cs new file mode 100644 index 00000000..c2c8b48d --- /dev/null +++ b/NewHorizons/Components/NHSupernovaPlanetEffectController.cs @@ -0,0 +1,196 @@ +using NewHorizons.Components.SizeControllers; +using NewHorizons.Handlers; +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; +using static SupernovaPlanetEffectController; + +namespace NewHorizons.Components +{ + public class NHSupernovaPlanetEffectController : MonoBehaviour + { + public Light _ambientLight; + public float _ambientLightOrigIntensity; + public LODGroup _atmosphere; + public Renderer _atmosphereRenderer; + public PlanetaryFogController _fog; + public Renderer _fogImpostor; + public Color _fogOrigTint; + [Space] + public MeshRenderer _shockLayer; + public static readonly Color _shockLayerDefaultColor = new Color(0.3569f, 0.7843f, 1f, 1f); + [ColorUsage(true, true)] + public Color _shockLayerColor = _shockLayerDefaultColor; + public float _shockLayerStartRadius = 1000f; + public float _shockLayerFullRadius = 10000f; + public float _shockLayerTrailLength = 300f; + public float _shockLayerTrailFlare = 100f; + + private LOD[] _atmosphereLODs; + + public StarEvolutionController _starEvolutionController; + + public SunController _sunController; + + public void Awake() + { + if (s_matPropBlock_Atmosphere == null) + { + s_matPropBlock_Atmosphere = new MaterialPropertyBlock(); + s_propID_SunIntensity = Shader.PropertyToID("_SunIntensity"); + s_propID_Tint = Shader.PropertyToID("_Tint"); + s_matPropBlock_ShockLayer = new MaterialPropertyBlock(); + s_propID_Color = Shader.PropertyToID("_Color"); + s_propID_WorldToLocalShockMatrix = Shader.PropertyToID("_WorldToShockLocalMatrix"); + s_propID_Dir = Shader.PropertyToID("_Dir"); + s_propID_Length = Shader.PropertyToID("_Length"); + s_propID_Flare = Shader.PropertyToID("_Flare"); + s_propID_TrailFade = Shader.PropertyToID("_TrailFade"); + s_propID_GradientLerp = Shader.PropertyToID("_GradientLerp"); + s_propID_MainTex_ST = Shader.PropertyToID("_MainTex_ST"); + } + } + + public void Start() + { + SupernovaEffectHandler.RegisterPlanetEffect(this); + if (_atmosphere != null) _atmosphereLODs = _atmosphere.GetLODs(); + if (_fog != null) + { + _fogOrigTint = _fog.fogTint; + _fogImpostor = _fog.fogImpostor; + } + else if (_fogImpostor != null) + { + _fogOrigTint = _fogImpostor.material.GetColor(s_propID_Tint); + } + if (_shockLayer != null) _shockLayer.enabled = false; + } + + public void OnDestroy() + { + SupernovaEffectHandler.UnregisterPlanetEffect(this); + } + + public void Enable() + { + enabled = true; + } + + public void Disable() + { + enabled = false; + if (_shockLayer != null) _shockLayer.enabled = false; + } + + public void Update() + { + SupernovaEffectHandler.GetNearestStarSupernova(this); + if (_starEvolutionController != null) + { + if (_starEvolutionController.HasSupernovaStarted()) + { + if (_shockLayer != null) + { + if (!_shockLayer.enabled) _shockLayer.enabled = true; + Vector3 dir = Vector3.Normalize(transform.position - _starEvolutionController.transform.position); + s_matPropBlock_ShockLayer.SetColor(s_propID_Color, _starEvolutionController.SupernovaColour != null ? _starEvolutionController.SupernovaColour.ToColor() : _shockLayerColor); + s_matPropBlock_ShockLayer.SetMatrix(s_propID_WorldToLocalShockMatrix, Matrix4x4.TRS(transform.position, Quaternion.LookRotation(dir, Vector3.up), Vector3.one).inverse); + s_matPropBlock_ShockLayer.SetVector(s_propID_Dir, dir); + s_matPropBlock_ShockLayer.SetFloat(s_propID_Length, _shockLayerTrailLength); + s_matPropBlock_ShockLayer.SetFloat(s_propID_Flare, _shockLayerTrailFlare); + s_matPropBlock_ShockLayer.SetFloat(s_propID_TrailFade, 1f - Mathf.InverseLerp(_shockLayerStartRadius, _shockLayerFullRadius, _starEvolutionController.GetSupernovaRadius())); + s_matPropBlock_ShockLayer.SetFloat(s_propID_GradientLerp, 0); + s_matPropBlock_ShockLayer.SetVector(s_propID_MainTex_ST, _shockLayer.sharedMaterial.GetVector(s_propID_MainTex_ST) with { w = -Time.timeSinceLevelLoad }); + _shockLayer.SetPropertyBlock(s_matPropBlock_ShockLayer); + } + } + if (_starEvolutionController.IsCollapsing()) + { + float collapseProgress = _starEvolutionController.GetCollapseProgress(); + + if (_ambientLight != null) _ambientLight.intensity = _ambientLightOrigIntensity * (1f - collapseProgress); + + if (_atmosphere != null) + { + s_matPropBlock_Atmosphere.SetFloat(s_propID_SunIntensity, 1f - collapseProgress); + + foreach (var lod in _atmosphereLODs) + foreach (var renderer in lod.renderers) + renderer.SetPropertyBlock(s_matPropBlock_Atmosphere); + } + + if (_atmosphereRenderer != null) + { + s_matPropBlock_Atmosphere.SetFloat(s_propID_SunIntensity, 1f - collapseProgress); + + _atmosphereRenderer.SetPropertyBlock(s_matPropBlock_Atmosphere); + } + + if (_fog != null) _fog.fogTint = Color.Lerp(_fogOrigTint, Color.black, collapseProgress); + + if (_fogImpostor != null) _fogImpostor.material.SetColor(s_propID_Tint, Color.Lerp(_fogOrigTint, Color.black, collapseProgress)); + } + else + { + if (_shockLayer != null) _shockLayer.enabled = false; + } + } + else if (_sunController != null) + { + if (_sunController.HasSupernovaStarted()) + { + if (_shockLayer != null) + { + if (!_shockLayer.enabled) _shockLayer.enabled = true; + Vector3 dir = Vector3.Normalize(transform.position - _sunController.transform.position); + s_matPropBlock_ShockLayer.SetColor(s_propID_Color, _shockLayerColor); + s_matPropBlock_ShockLayer.SetMatrix(s_propID_WorldToLocalShockMatrix, Matrix4x4.TRS(transform.position, Quaternion.LookRotation(dir, Vector3.up), Vector3.one).inverse); + s_matPropBlock_ShockLayer.SetVector(s_propID_Dir, dir); + s_matPropBlock_ShockLayer.SetFloat(s_propID_Length, _shockLayerTrailLength); + s_matPropBlock_ShockLayer.SetFloat(s_propID_Flare, _shockLayerTrailFlare); + s_matPropBlock_ShockLayer.SetFloat(s_propID_TrailFade, 1f - Mathf.InverseLerp(_shockLayerStartRadius, _shockLayerFullRadius, _sunController.GetSupernovaRadius())); + s_matPropBlock_ShockLayer.SetFloat(s_propID_GradientLerp, 0); + s_matPropBlock_ShockLayer.SetVector(s_propID_MainTex_ST, _shockLayer.sharedMaterial.GetVector(s_propID_MainTex_ST) with { w = -Time.timeSinceLevelLoad }); + _shockLayer.SetPropertyBlock(s_matPropBlock_ShockLayer); + } + } + else if (_sunController._collapseStarted) + { + float collapseProgress = _sunController.GetCollapseProgress(); + + if (_ambientLight != null) _ambientLight.intensity = _ambientLightOrigIntensity * (1f - collapseProgress); + + if (_atmosphere != null) + { + s_matPropBlock_Atmosphere.SetFloat(s_propID_SunIntensity, 1f - collapseProgress); + + foreach (var lod in _atmosphereLODs) + foreach (var renderer in lod.renderers) + renderer.SetPropertyBlock(s_matPropBlock_Atmosphere); + } + + if (_atmosphereRenderer != null) + { + s_matPropBlock_Atmosphere.SetFloat(s_propID_SunIntensity, 1f - collapseProgress); + + _atmosphereRenderer.SetPropertyBlock(s_matPropBlock_Atmosphere); + } + + if (_fog != null) _fog.fogTint = Color.Lerp(_fogOrigTint, Color.black, collapseProgress); + + if (_fogImpostor != null) _fogImpostor.material.SetColor(s_propID_Tint, Color.Lerp(_fogOrigTint, Color.black, collapseProgress)); + } + else + { + if (_shockLayer != null) _shockLayer.enabled = false; + } + } + else + { + if (_shockLayer != null) _shockLayer.enabled = false; + } + } + } +} diff --git a/NewHorizons/Components/SizeControllers/StarEvolutionController.cs b/NewHorizons/Components/SizeControllers/StarEvolutionController.cs index f3491024..afb81949 100644 --- a/NewHorizons/Components/SizeControllers/StarEvolutionController.cs +++ b/NewHorizons/Components/SizeControllers/StarEvolutionController.cs @@ -1,4 +1,5 @@ using NewHorizons.Builder.Body; +using NewHorizons.Handlers; using NewHorizons.Utility; using System; using System.Collections.Generic; @@ -19,6 +20,7 @@ namespace NewHorizons.Components.SizeControllers public bool WillExplode { get; set; } public MColor StartColour { get; set; } public MColor EndColour { get; set; } + public MColor SupernovaColour { get; set; } public Texture normalRamp; public Texture collapseRamp; @@ -30,6 +32,8 @@ namespace NewHorizons.Components.SizeControllers private HeatHazardVolume _heatVolume; public DestructionVolume _destructionVolume; public DestructionVolume _planetDestructionVolume; + public SimpleFluidVolume _destructionFluidVolume; + public SimpleFluidVolume _planetDestructionFluidVolume; private SolarFlareEmitter _flareEmitter; private MapMarker _mapMarker; private OWRigidbody _rigidbody; @@ -39,7 +43,9 @@ namespace NewHorizons.Components.SizeControllers private float _collapseTimer; public float collapseTime = 10f; // seconds - public float supernovaTime = 45f; // seconds + public float supernovaScaleStart = 45f; // seconds + public float supernovaScaleEnd = 50f; // seconds + public float supernovaTime = 50f; // seconds public float lifespan = 22f; // minutes public float supernovaSize = 50000f; @@ -56,7 +62,10 @@ namespace NewHorizons.Components.SizeControllers private StarEvolutionController _proxy; + public UnityEvent CollapseStart = new UnityEvent(); + public UnityEvent CollapseStop = new UnityEvent(); public UnityEvent SupernovaStart = new UnityEvent(); + public UnityEvent SupernovaStop = new UnityEvent(); private float maxScale; private float minScale; @@ -122,7 +131,7 @@ namespace NewHorizons.Components.SizeControllers } _heatVolume = GetComponentInChildren(); - if (_destructionVolume != null) _destructionVolume = GetComponentInChildren(); + if (_destructionVolume == null) _destructionVolume = GetComponentInChildren(); if (atmosphere != null) { @@ -146,6 +155,8 @@ namespace NewHorizons.Components.SizeControllers _flareEmitter = GetComponentInChildren(); _surfaceMaterial = supernova._surface._materials[0]; + SupernovaEffectHandler.RegisterStar(this); + var secondsElapsed = TimeLoop.GetSecondsElapsed(); var lifespanInSeconds = lifespan * 60; if (secondsElapsed >= lifespanInSeconds) @@ -162,6 +173,7 @@ namespace NewHorizons.Components.SizeControllers public void OnDestroy() { + SupernovaEffectHandler.UnregisterStar(this); } public void SetProxy(StarEvolutionController proxy) @@ -228,6 +240,12 @@ namespace NewHorizons.Components.SizeControllers if (_planetDestructionVolume != null) _planetDestructionVolume.transform.localScale = Vector3.one * supernova.GetSupernovaRadius() * 0.9f; if (_heatVolume != null) _heatVolume.transform.localScale = Vector3.one * supernova.GetSupernovaRadius(); + var t = Mathf.Clamp01((Time.time - (_supernovaStartTime + supernovaScaleStart)) / (supernovaScaleEnd - supernovaScaleStart)); + if (t > 0) + { + _planetDestructionVolume.GetComponent().radius = Mathf.Lerp(0.8f, 1, t); + } + if (Time.time > _supernovaStartTime + supernovaTime) { DisableStar(); @@ -281,6 +299,7 @@ namespace NewHorizons.Components.SizeControllers Logger.LogVerbose($"{gameObject.transform.root.name} started collapse"); + CollapseStart.Invoke(); _isCollapsing = true; _collapseStartSize = CurrentScale; _collapseTimer = 0f; @@ -295,6 +314,7 @@ namespace NewHorizons.Components.SizeControllers Logger.LogVerbose($"{gameObject.transform.root.name} stopped collapse"); + CollapseStop.Invoke(); _isCollapsing = false; supernova._surface._materials[0].CopyPropertiesFromMaterial(_endSurfaceMaterial); @@ -314,6 +334,8 @@ namespace NewHorizons.Components.SizeControllers if (atmosphere != null) atmosphere.SetActive(false); if (_destructionVolume != null) _destructionVolume._deathType = DeathType.Supernova; if (_planetDestructionVolume != null) _planetDestructionVolume._deathType = DeathType.Supernova; + if (_destructionFluidVolume != null) _destructionFluidVolume.enabled = false; + if (_planetDestructionFluidVolume != null) _planetDestructionFluidVolume.enabled = false; if (_proxy != null) _proxy.StartSupernova(); } @@ -324,6 +346,7 @@ namespace NewHorizons.Components.SizeControllers Logger.LogVerbose($"{gameObject.transform.root.name} stopped supernova"); + SupernovaStop.Invoke(); supernova.enabled = false; _isSupernova = false; if (atmosphere != null) atmosphere.SetActive(true); @@ -337,6 +360,8 @@ namespace NewHorizons.Components.SizeControllers _planetDestructionVolume._deathType = DeathType.Energy; _planetDestructionVolume.transform.localScale = Vector3.one; } + if (_destructionFluidVolume != null) _destructionFluidVolume.enabled = true; + if (_planetDestructionFluidVolume != null) _planetDestructionFluidVolume.enabled = true; if (_heatVolume != null) _heatVolume.transform.localScale = Vector3.one; gameObject.SetActive(true); transform.localScale = Vector3.one; @@ -346,6 +371,24 @@ namespace NewHorizons.Components.SizeControllers if (_proxy != null) _proxy.StopSupernova(); } + public bool IsCollapsing() => _isCollapsing; + + public float GetCollapseProgress() => _collapseTimer / collapseTime; + + public bool HasSupernovaStarted() => _isSupernova; + + public bool IsPointInsideSupernova(Vector3 worldPosition) => _isSupernova && (worldPosition - transform.position).sqrMagnitude < (supernova.GetSupernovaRadius() * supernova.GetSupernovaRadius()); + + public bool IsPointInsideMaxSupernova(Vector3 worldPosition) => (worldPosition - transform.position).sqrMagnitude < (supernovaSize * supernovaSize); + + public float GetDistanceToSupernova(Vector3 worldPosition) => Vector3.Distance(worldPosition, transform.position) - supernova.GetSupernovaRadius(); + + public float GetDistanceToMaxSupernova(Vector3 worldPosition) => Vector3.Distance(worldPosition, transform.position) - supernovaSize; + + public float GetSupernovaRadius() => supernova.GetSupernovaRadius(); + + public float GetMaxSupernovaRadius() => supernovaSize; + protected new void FixedUpdate() { // If we've gone supernova and its been 45 seconds that means it has faded out and is gone diff --git a/NewHorizons/Components/TimeLoopController.cs b/NewHorizons/Components/TimeLoopController.cs index 2e739b2a..7110e6db 100644 --- a/NewHorizons/Components/TimeLoopController.cs +++ b/NewHorizons/Components/TimeLoopController.cs @@ -1,4 +1,4 @@ -using UnityEngine; +using UnityEngine; namespace NewHorizons.Components { public class TimeLoopController : MonoBehaviour @@ -14,8 +14,7 @@ namespace NewHorizons.Components public void Update() { // Stock gives like 33 seconds after the sun collapses - // Gonna assume it takes like 7 seconds to collapse after the supernova trigger - if (_supernovaHappened && Time.time > _supernovaTime + 40f) + if (_supernovaHappened && Time.time > _supernovaTime + 50f) { Locator.GetDeathManager().KillPlayer(DeathType.TimeLoop); } diff --git a/NewHorizons/External/Configs/AddonConfig.cs b/NewHorizons/External/Configs/AddonConfig.cs index bf89193f..2fe85d7b 100644 --- a/NewHorizons/External/Configs/AddonConfig.cs +++ b/NewHorizons/External/Configs/AddonConfig.cs @@ -24,5 +24,9 @@ namespace NewHorizons.External.Configs /// public AchievementInfo[] achievements; + /// + /// Credits info for this mod. A list of contributors and their roles separated by #. For example: xen#New Horizons dev. + /// + public string[] credits; } } diff --git a/NewHorizons/External/Modules/AtmosphereModule.cs b/NewHorizons/External/Modules/AtmosphereModule.cs index 2e96d20f..f75e4bed 100644 --- a/NewHorizons/External/Modules/AtmosphereModule.cs +++ b/NewHorizons/External/Modules/AtmosphereModule.cs @@ -165,9 +165,9 @@ namespace NewHorizons.External.Modules public bool unlit; /// - /// How fast the clouds will rotate in degrees per second. + /// How fast the clouds will rotate relative to the planet in degrees per second. /// - [DefaultValue(10f)] public float rotationSpeed = 10f; + [DefaultValue(0f)] public float rotationSpeed = 0f; #region Obsolete diff --git a/NewHorizons/External/Modules/BaseModule.cs b/NewHorizons/External/Modules/BaseModule.cs index 2d434f66..aad6549c 100644 --- a/NewHorizons/External/Modules/BaseModule.cs +++ b/NewHorizons/External/Modules/BaseModule.cs @@ -56,6 +56,11 @@ namespace NewHorizons.External.Modules /// public bool hasMapMarker; + /// + /// Does this planet have a shock effect when the nearest star goes supernova? + /// + [DefaultValue(true)] public bool hasSupernovaShockEffect = true; + /// /// Can this planet survive entering a star? /// diff --git a/NewHorizons/Handlers/CreditsHandler.cs b/NewHorizons/Handlers/CreditsHandler.cs new file mode 100644 index 00000000..9d7e7405 --- /dev/null +++ b/NewHorizons/Handlers/CreditsHandler.cs @@ -0,0 +1,218 @@ +using System.Collections.Generic; +using System.Xml; +using UnityEngine; +using Logger = NewHorizons.Utility.Logger; + +namespace NewHorizons.Handlers +{ + public static class CreditsHandler + { + private static Dictionary _creditsInfo; + + public static void RegisterCredits(string sectionName, string[] entries) + { + if (_creditsInfo == null) _creditsInfo = new(); + + Logger.LogVerbose($"Registering credits for {sectionName}"); + + _creditsInfo[sectionName] = entries; + } + + public static void AddCredits(Credits credits) + { + Logger.LogVerbose($"Adding to credits"); + + var creditsAsset = credits._creditsAsset; + + var xml = new XmlDocument(); + xml.LoadXml(creditsAsset.xml.text); + + foreach (var pair in _creditsInfo) + { + AddCreditsSection(pair.Key, pair.Value, ref xml); + } + + var outerXml = xml.OuterXml.Replace("/n", " "); + + creditsAsset.xml = new TextAsset(outerXml); + } + + private static void AddCreditsSection(string sectionName, string[] entries, ref XmlDocument xml) + { + var finalCredits = xml.SelectSingleNode("Credits/section"); + + /* + * Looks bad, would need more customization, complicated, messes up music timing, wont do for now + var nodeFade = CreateFadeCreditsFromList(xml, sectionName, entries); + finalCredits.InsertAfter(nodeFade, finalCredits.ChildNodes[0]); + */ + + var fastCredits = NodeWhere(finalCredits.ChildNodes, "MainScrollSection"); + var nodeScroll = CreateScrollCreditsFromList(xml, sectionName, entries); + fastCredits.InsertBefore(nodeScroll, fastCredits.ChildNodes[0]); + } + + private static XmlNode NodeWhere(XmlNodeList list, string name) + { + foreach(XmlNode node in list) + { + try + { + if (node.Attributes[0].Value == name) return node; + } + catch { } + } + return null; + } + + // Looked bad so not used + /* + private static XmlNode CreateFadeCreditsFromList(XmlDocument doc, string title, string[] entries) + { + var rootSection = MakeNode(doc, "section", new Dictionary() + { + { "platform", "All" }, + { "type", "Fade" }, + { "fadeInTime", "1.3" }, + { "displayTime", "10" }, + { "fadeOutTime", "1.4" }, + { "waitTime", "0.5" }, + { "padding-bottom", "-8" }, + { "spacing", "16" } + }); + + var titleLayout = MakeNode(doc, "layout", new Dictionary() + { + { "type", "SingleColumnFadeCentered" } + }); + + var titleNode = MakeNode(doc, "title", new Dictionary() + { + {"text-align", "UpperCenter" }, + {"height", "122" } + }); + titleNode.InnerText = title; + titleLayout.AppendChild(titleNode); + + var type = "SingleColumnFadeCentered"; + var xmlText = $"\n"; + for (int i = 0; i < entries.Length; i++) + { + var entry = entries[i]; + + if (entry.Contains("#")) + { + // Replace first one with a space + entry = RemoveExcessSpaces(entry); + var indexOfColon = entry.IndexOf(":"); + var firstPart = entry.Substring(0, Math.Min(entry.IndexOf("#"), indexOfColon == -1 ? int.MaxValue : indexOfColon)); + entry = firstPart + ": " + entry.Substring(entry.IndexOf("#") + 1); + } + entry = entry.Replace("#", ", ").Replace("/n", ""); + + xmlText += $"{entry}\n"; + xmlText += "\n"; + } + xmlText += "\n"; + xmlText += ""; + + rootSection.AppendChild(titleLayout); + foreach (var node in StringToNodes(doc, xmlText)) rootSection.AppendChild(node); + + return rootSection; + } + + private static string RemoveExcessSpaces(string s) + { + var options = RegexOptions.None; + Regex regex = new Regex("[ ]{2,}", options); + return regex.Replace(s, " "); + } + */ + + private static XmlNode CreateScrollCreditsFromList(XmlDocument doc, string title, string[] entries) + { + var rootSection = MakeNode(doc, "section", new Dictionary() + { + { "platform", "All" }, + { "type", "Scroll" }, + { "scrollDuration", "214" }, + { "spacing", "12" }, + { "width", "1590" } + }); + + var titleLayout = MakeNode(doc, "layout", new Dictionary() + { + { "type", "SingleColumnScrollCentered" } + }); + + var titleNode = MakeNode(doc, "title", new Dictionary() + { + {"text-align", "UpperCenter" }, + {"height", "122" } + }); + titleNode.InnerText = title; + titleLayout.AppendChild(titleNode); + + + var xmlText = ""; + bool? flag = null; + for (int i = 0; i < entries.Length; i++) + { + var entry = entries[i]; + + var twoColumn = entry.Contains("#"); + if (flag != twoColumn) + { + if (i != 0) xmlText += ""; + var type = twoColumn ? "TwoColumnScrollAlignRightLeft" : "SingleColumnScrollCentered"; + xmlText += $"\n"; + flag = twoColumn; + } + + xmlText += $"{entry}\n"; + xmlText += ""; + } + xmlText += "\n"; + xmlText += ""; + + rootSection.AppendChild(titleLayout); + foreach(var node in StringToNodes(doc, xmlText)) rootSection.AppendChild(node); + + return rootSection; + } + + private static XmlNode[] StringToNodes(XmlDocument docContext, string text) + { + var doc = new XmlDocument(); + // Doing this funny thing so that theres a single parent root thing + doc.LoadXml("" + text + ""); + + // ArgumentException: The node to be inserted is from a different document context. + var nodes = new List(); + foreach (XmlNode node in doc.DocumentElement.ChildNodes) + { + nodes.Add(docContext.ImportNode(node, true)); + } + + return nodes.ToArray(); + } + + private static XmlNode MakeNode(XmlDocument doc, string nodeType, Dictionary attributes) + { + var xmlNode = doc.CreateElement(nodeType); + + if (attributes != null) + { + foreach (var pair in attributes) + { + var attribute = doc.CreateAttribute(pair.Key); + attribute.Value = pair.Value; + xmlNode.Attributes.Append(attribute); + } + } + + return xmlNode; + } + } +} diff --git a/NewHorizons/Handlers/PlanetCreationHandler.cs b/NewHorizons/Handlers/PlanetCreationHandler.cs index be8935f0..eba9965c 100644 --- a/NewHorizons/Handlers/PlanetCreationHandler.cs +++ b/NewHorizons/Handlers/PlanetCreationHandler.cs @@ -37,6 +37,7 @@ namespace NewHorizons.Handlers // Set up stars // Need to manage this when there are multiple stars var sun = SearchUtilities.Find("Sun_Body"); + SupernovaEffectHandler.RegisterSun(sun.GetComponent()); var starController = sun.AddComponent(); starController.Light = SearchUtilities.Find("Sun_Body/Sector_SUN/Effects_SUN/SunLight").GetComponent(); starController.AmbientLight = SearchUtilities.Find("Sun_Body/AmbientLight_SUN").GetComponent(); @@ -448,10 +449,7 @@ namespace NewHorizons.Handlers Delay.FireOnNextUpdate(() => OrbitlineBuilder.Make(body.Object, ao as NHAstroObject, body.Config.Orbit.isMoon, body.Config)); } - if (!body.Config.Orbit.isStatic) - { - DetectorBuilder.Make(go, owRigidBody, primaryBody, ao, body.Config); - } + DetectorBuilder.Make(go, owRigidBody, primaryBody, ao, body.Config); AstroObjectLocator.RegisterCustomAstroObject(ao); @@ -482,9 +480,10 @@ namespace NewHorizons.Handlers { var sphereOfInfluence = GetSphereOfInfluence(body); + Light ambientLight = null; if (body.Config.Base.ambientLight != 0) { - AmbientLightBuilder.Make(go, sector, sphereOfInfluence, body.Config.Base.ambientLight); + ambientLight = AmbientLightBuilder.Make(go, sector, sphereOfInfluence, body.Config.Base.ambientLight); } if (body.Config.Base.groundSize != 0) @@ -500,9 +499,10 @@ namespace NewHorizons.Handlers HeightMapBuilder.Make(go, sector, body.Config.HeightMap, body.Mod, res, true); } + GameObject procGen = null; if (body.Config.ProcGen != null) { - ProcGenBuilder.Make(go, sector, body.Config.ProcGen); + procGen = ProcGenBuilder.Make(go, sector, body.Config.ProcGen); } if (body.Config.Star != null) @@ -554,7 +554,8 @@ namespace NewHorizons.Handlers } var willHaveCloak = body.Config.Cloak != null && body.Config.Cloak.radius != 0f; - + PlanetaryFogController fog = null; + LODGroup atmosphere = null; if (body.Config.Atmosphere != null) { var surfaceSize = body.Config.Base.surfaceSize; @@ -571,9 +572,11 @@ namespace NewHorizons.Handlers EffectsBuilder.Make(go, sector, body.Config, surfaceSize); if (body.Config.Atmosphere.fogSize != 0) - FogBuilder.Make(go, sector, body.Config.Atmosphere); + { + fog = FogBuilder.Make(go, sector, body.Config.Atmosphere); + } - AtmosphereBuilder.Make(go, sector, body.Config.Atmosphere, surfaceSize); + atmosphere = AtmosphereBuilder.Make(go, sector, body.Config.Atmosphere, surfaceSize).GetComponentInChildren(); } if (body.Config.Props != null) @@ -592,6 +595,11 @@ namespace NewHorizons.Handlers CloakBuilder.Make(go, sector, rb, body.Config.Cloak, !body.Config.ReferenceFrame.hideInMap, body.Mod); } + if (body.Config.Base.hasSupernovaShockEffect && body.Config.Star == null && body.Config.name != "Sun" && body.Config.FocalPoint == null) + { + SupernovaEffectBuilder.Make(go, sector, body.Config, procGen, ambientLight, fog, atmosphere, null, fog?._fogImpostor); + } + return go; } diff --git a/NewHorizons/Handlers/SupernovaEffectHandler.cs b/NewHorizons/Handlers/SupernovaEffectHandler.cs new file mode 100644 index 00000000..35df25e5 --- /dev/null +++ b/NewHorizons/Handlers/SupernovaEffectHandler.cs @@ -0,0 +1,90 @@ +using NewHorizons.Components; +using NewHorizons.Components.SizeControllers; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NewHorizons.Handlers +{ + public class SupernovaEffectHandler + { + private static List _supernovaPlanetEffectControllers = new List(); + private static List _starEvolutionControllers = new List(); + private static SunController _sunController; + + public static void RegisterStar(StarEvolutionController starEvolutionController) + { + _starEvolutionControllers.SafeAdd(starEvolutionController); + } + + public static void UnregisterStar(StarEvolutionController starEvolutionController) + { + _starEvolutionControllers.Remove(starEvolutionController); + } + + public static void RegisterSun(SunController sunController) + { + _sunController = sunController; + } + + public static void UnregisterSun() + { + _sunController = null; + } + + public static void RegisterPlanetEffect(NHSupernovaPlanetEffectController supernovaPlanetEffectController) + { + _supernovaPlanetEffectControllers.SafeAdd(supernovaPlanetEffectController); + } + + public static void UnregisterPlanetEffect(NHSupernovaPlanetEffectController supernovaPlanetEffectController) + { + _supernovaPlanetEffectControllers.Remove(supernovaPlanetEffectController); + } + + public static void GetNearestStarSupernova(NHSupernovaPlanetEffectController supernovaPlanetEffectController) + { + if (supernovaPlanetEffectController == null) return; + + StarEvolutionController nearestStarEvolutionController = null; + float nearestDistance = float.MaxValue; + foreach (StarEvolutionController starEvolutionController in _starEvolutionControllers) + { + if (starEvolutionController == null) continue; + if (!(starEvolutionController.gameObject.activeSelf && starEvolutionController.gameObject.activeInHierarchy)) continue; + float distance = (supernovaPlanetEffectController.transform.position - starEvolutionController.transform.position).sqrMagnitude; + if (distance < (starEvolutionController.supernovaSize * starEvolutionController.supernovaSize) && distance < nearestDistance) + { + nearestDistance = distance; + nearestStarEvolutionController = starEvolutionController; + } + } + + if (_sunController != null && _sunController.gameObject.activeSelf) + { + float distance = (supernovaPlanetEffectController.transform.position - _sunController.transform.position).sqrMagnitude; + if (distance < 2500000000f && distance < nearestDistance) + { + supernovaPlanetEffectController._sunController = _sunController; + supernovaPlanetEffectController._starEvolutionController = null; + } + else + { + supernovaPlanetEffectController._sunController = null; + supernovaPlanetEffectController._starEvolutionController = nearestStarEvolutionController; + } + } + else + { + supernovaPlanetEffectController._sunController = null; + supernovaPlanetEffectController._starEvolutionController = nearestStarEvolutionController; + } + } + + public static SunController GetSunController() => _sunController; + + public static bool InPointInsideSunSupernova(NHSupernovaPlanetEffectController supernovaPlanetEffectController) => _sunController != null && (supernovaPlanetEffectController.transform.position - _sunController.transform.position).sqrMagnitude < 2500000000f;//(50000f*50000f); + } +} diff --git a/NewHorizons/Main.cs b/NewHorizons/Main.cs index f502a705..bc5b0c1a 100644 --- a/NewHorizons/Main.cs +++ b/NewHorizons/Main.cs @@ -201,6 +201,8 @@ namespace NewHorizons AchievementHandler.Init(); VoiceHandler.Init(); + + LoadAddonManifest("Assets/addon-manifest.json", this); } public void OnDestroy() @@ -377,6 +379,14 @@ namespace NewHorizons AtmosphereBuilder.Init(); BrambleNodeBuilder.Init(BodyDict[CurrentStarSystem].Select(x => x.Config).Where(x => x.Bramble?.dimension != null).ToArray()); + if (isSolarSystem) + { + foreach (var supernovaPlanetEffectController in GameObject.FindObjectsOfType()) + { + SupernovaEffectBuilder.ReplaceVanillaWithNH(supernovaPlanetEffectController); + } + } + PlanetCreationHandler.Init(BodyDict[CurrentStarSystem]); VesselWarpHandler.LoadVessel(); SystemCreationHandler.LoadSystem(SystemDict[CurrentStarSystem]); @@ -384,6 +394,7 @@ namespace NewHorizons LoadTranslations(ModHelper.Manifest.ModFolderPath + "Assets/", this); StarChartHandler.Init(SystemDict.Values.ToArray()); + if (isSolarSystem) { // Warp drive @@ -482,7 +493,17 @@ namespace NewHorizons ssrLight.spotAngle = 179; ssrLight.range = Main.FurthestOrbit * (4f/3f); ssrLight.intensity = 0.001f; - + + var fluid = playerBody.FindChild("PlayerDetector").GetComponent(); + fluid._splashEffects = fluid._splashEffects.AddToArray(new SplashEffect + { + fluidType = FluidVolume.Type.PLASMA, + ignoreSphereAligment = false, + minImpactSpeed = 15, + splashPrefab = SearchUtilities.Find("Probe_Body/ProbeDetector").GetComponent()._splashEffects.FirstOrDefault(sfx => sfx.fluidType == FluidVolume.Type.PLASMA).splashPrefab, + triggerEvent = SplashEffect.TriggerEvent.OnEntry + }); + try { Logger.Log($"Star system finished loading [{Instance.CurrentStarSystem}]"); @@ -601,9 +622,7 @@ namespace NewHorizons // Has to go before translations for achievements if (File.Exists(folder + "addon-manifest.json")) { - var addonConfig = mod.ModHelper.Storage.Load("addon-manifest.json"); - - AchievementHandler.RegisterAddon(addonConfig, mod as ModBehaviour); + LoadAddonManifest("addon-manifest.json", mod); } if (Directory.Exists(folder + @"translations\")) { @@ -617,6 +636,16 @@ namespace NewHorizons } } + private void LoadAddonManifest(string file, IModBehaviour mod) + { + Logger.LogVerbose($"Loading addon manifest for {mod.ModHelper.Manifest.Name}"); + + var addonConfig = mod.ModHelper.Storage.Load(file); + + if (addonConfig.achievements != null) AchievementHandler.RegisterAddon(addonConfig, mod as ModBehaviour); + if (addonConfig.credits != null) CreditsHandler.RegisterCredits(mod.ModHelper.Manifest.Name, addonConfig.credits); + } + private void LoadTranslations(string folder, IModBehaviour mod) { var foundFile = false; diff --git a/NewHorizons/Patches/CreditsScene/CreditsEntryPatches.cs b/NewHorizons/Patches/CreditsScene/CreditsEntryPatches.cs new file mode 100644 index 00000000..fe255ed6 --- /dev/null +++ b/NewHorizons/Patches/CreditsScene/CreditsEntryPatches.cs @@ -0,0 +1,33 @@ +using HarmonyLib; +using NewHorizons.Utility; +using System; + +namespace NewHorizons.Patches.CreditsScene +{ + [HarmonyPatch] + public static class CreditsEntryPatches + { + [HarmonyPrefix] + [HarmonyPatch(typeof(CreditsEntry), nameof(CreditsEntry.SetContents))] + public static bool CreditsEntry_SetContents(CreditsEntry __instance, string[] __0) + { + var columnTexts = __0; + + for (int i = 0; i < __instance._columns.Length; i++) + { + // Base method throws out of bounds exception sometimes (_columns length doesn't match columnTexts length) + // Trim also NREs sometimes because of the TrimHelper class Mobius has idk + try + { + __instance._columns[i].text = columnTexts[i].Trim(); + } + catch + { + // Error occurs when column 2 is empty + __instance._columns[i].text = " "; + } + } + return false; + } + } +} diff --git a/NewHorizons/Patches/CreditsScene/CreditsPatches.cs b/NewHorizons/Patches/CreditsScene/CreditsPatches.cs new file mode 100644 index 00000000..724ef696 --- /dev/null +++ b/NewHorizons/Patches/CreditsScene/CreditsPatches.cs @@ -0,0 +1,17 @@ +using HarmonyLib; +using NewHorizons.Handlers; + +namespace NewHorizons.Patches.CreditsScene +{ + [HarmonyPatch] + public static class CreditsPatches + { + [HarmonyPrefix] + [HarmonyPatch(typeof(Credits), nameof(Credits.Start))] + public static void Credits_Start(Credits __instance) + { + CreditsHandler.AddCredits(__instance); + } + } +} + diff --git a/NewHorizons/Patches/LocatorPatches.cs b/NewHorizons/Patches/LocatorPatches.cs index 5bc61cce..d3418ae0 100644 --- a/NewHorizons/Patches/LocatorPatches.cs +++ b/NewHorizons/Patches/LocatorPatches.cs @@ -1,12 +1,16 @@ using HarmonyLib; -using NewHorizons.Components; namespace NewHorizons.Patches { [HarmonyPatch] public static class LocatorPatches { + public static AstroObject _attlerock; public static AstroObject _eye; + public static AstroObject _focal; + public static AstroObject _hollowsLantern; + public static AstroObject _mapSatellite; + public static AstroObject _sunStation; [HarmonyPrefix] [HarmonyPatch(typeof(Locator), nameof(Locator.RegisterCloakFieldController))] @@ -36,14 +40,34 @@ namespace NewHorizons.Patches __result = __result || Components.CloakSectorController.isShipInside; } + // Locator Fixes + // Vanilla doesn't register these AstroObjects for some reason. So here is a fix. [HarmonyPrefix] [HarmonyPatch(typeof(Locator), nameof(Locator.GetAstroObject))] public static bool Locator_GetAstroObject(AstroObject.Name astroObjectName, ref AstroObject __result) { - if (astroObjectName == AstroObject.Name.Eye && _eye != null) + switch (astroObjectName) { - __result = _eye; - return false; + case AstroObject.Name.Eye: + __result = _eye; + return false; + case AstroObject.Name.HourglassTwins: + __result = _focal; + return false; + case AstroObject.Name.MapSatellite: + __result = _mapSatellite; + return false; + case AstroObject.Name.SunStation: + __result = _sunStation; + return false; + case AstroObject.Name.TimberMoon: + __result = _attlerock; + return false; + case AstroObject.Name.VolcanicMoon: + __result = _hollowsLantern; + return false; + default: + break; } return true; } @@ -52,10 +76,44 @@ namespace NewHorizons.Patches [HarmonyPatch(typeof(Locator), nameof(Locator.RegisterAstroObject))] public static bool Locator_RegisterAstroObject(AstroObject astroObject) { - if (astroObject._name == AstroObject.Name.Eye) + if (astroObject.GetAstroObjectName() == AstroObject.Name.None) return false; + + // Sun Station name change because for some dumb reason it doesn't use AstroObject.Name.SunStation + if (!string.IsNullOrEmpty(astroObject._customName) && astroObject._customName.Equals("Sun Station")) { - _eye = astroObject; - return false; + if (astroObject.gameObject.name == "SunStation_Body") + { + astroObject._name = AstroObject.Name.SunStation; + _sunStation = astroObject; + return false; + } + // Debris uses same custom name because morbius, so let us change that. + else if (astroObject.gameObject.name == "SS_Debris_Body") astroObject._customName = "Sun Station Debris"; + return true; + } + + switch (astroObject.GetAstroObjectName()) + { + case AstroObject.Name.Eye: + _eye = astroObject; + return false; + case AstroObject.Name.HourglassTwins: + _focal = astroObject; + return false; + case AstroObject.Name.MapSatellite: + _mapSatellite = astroObject; + return false; + case AstroObject.Name.SunStation: + _sunStation = astroObject; + return false; + case AstroObject.Name.TimberMoon: + _attlerock = astroObject; + return false; + case AstroObject.Name.VolcanicMoon: + _hollowsLantern = astroObject; + return false; + default: + break; } return true; } @@ -64,7 +122,12 @@ namespace NewHorizons.Patches [HarmonyPatch(typeof(Locator), nameof(Locator.ClearReferences))] public static void Locator_ClearReferences() { + _attlerock = null; _eye = null; + _focal = null; + _hollowsLantern = null; + _mapSatellite = null; + _sunStation = null; } } } diff --git a/NewHorizons/Patches/ProxyBodyPatches.cs b/NewHorizons/Patches/ProxyBodyPatches.cs index 3d03a55d..6e0e0cb2 100644 --- a/NewHorizons/Patches/ProxyBodyPatches.cs +++ b/NewHorizons/Patches/ProxyBodyPatches.cs @@ -1,4 +1,9 @@ using HarmonyLib; +using NewHorizons.Utility; +using System; +using System.Runtime.CompilerServices; +using UnityEngine; + namespace NewHorizons.Patches { [HarmonyPatch] @@ -53,5 +58,72 @@ namespace NewHorizons.Patches GlobalMessenger.RemoveListener("EnterMapView", __instance.OnEnterMapView); GlobalMessenger.RemoveListener("ExitMapView", __instance.OnExitMapView); } + + [HarmonyReversePatch] + [HarmonyPatch(typeof(ProxyPlanet), nameof(ProxyPlanet.Initialize))] + [MethodImpl(MethodImplOptions.NoInlining)] + public static void ProxyPlanet_Initialize(ProxyPlanet instance) { } + + [HarmonyPrefix] + [HarmonyPatch(typeof(ProxyBrittleHollow), nameof(ProxyBrittleHollow.Initialize))] + public static bool ProxyBrittleHollow_Initialize(ProxyBrittleHollow __instance) + { + try + { + ProxyPlanet_Initialize(__instance); + __instance._moon.SetOriginalBodies(Locator.GetAstroObject(AstroObject.Name.VolcanicMoon).transform, Locator.GetAstroObject(AstroObject.Name.BrittleHollow).transform); + if (!__instance._fragmentsResolved) __instance.ResolveFragments(); + __instance._blackHoleMaterial = new Material(__instance._blackHoleRenderer.sharedMaterial); + __instance._blackHoleRenderer.sharedMaterial = __instance._blackHoleMaterial; + } + catch (NullReferenceException ex) + { + __instance.PrintInitializeFailMessage(ex); + UnityEngine.Object.Destroy(__instance._moon.gameObject); + UnityEngine.Object.Destroy(__instance.gameObject); + } + return false; + } + + [HarmonyPrefix] + [HarmonyPatch(typeof(ProxyTimberHearth), nameof(ProxyTimberHearth.Initialize))] + public static bool ProxyTimberHearth_Initialize(ProxyTimberHearth __instance) + { + try + { + ProxyPlanet_Initialize(__instance); + __instance._moon.SetOriginalBodies(Locator.GetAstroObject(AstroObject.Name.TimberMoon).transform, Locator.GetAstroObject(AstroObject.Name.TimberHearth).transform); + } + catch (NullReferenceException ex) + { + __instance.PrintInitializeFailMessage(ex); + UnityEngine.Object.Destroy(__instance._moon.gameObject); + UnityEngine.Object.Destroy(__instance.gameObject); + } + return false; + } + + [HarmonyPrefix] + [HarmonyPatch(typeof(ProxyAshTwin), nameof(ProxyAshTwin.Initialize))] + public static bool ProxyAshTwin_Initialize(ProxyAshTwin __instance) + { + try + { + ProxyPlanet_Initialize(__instance); + __instance._realSandTransform = Locator.GetAstroObject(AstroObject.Name.TowerTwin).GetSandLevelController().transform; + SandFunnelController sandFunnelController = SearchUtilities.Find("SandFunnel_Body", false)?.GetComponent(); + if (sandFunnelController != null) + { + __instance._realSandColumnRoot = sandFunnelController.scaleRoot; + __instance._realSandColumnRenderObject = sandFunnelController.sandGeoObjects[0]; + } + } + catch (NullReferenceException ex) + { + __instance.PrintInitializeFailMessage(ex); + UnityEngine.Object.Destroy(__instance.gameObject); + } + return false; + } } } diff --git a/NewHorizons/Patches/VisionTorchPatches.cs b/NewHorizons/Patches/VisionTorchPatches.cs index fd4dd131..82c65832 100644 --- a/NewHorizons/Patches/VisionTorchPatches.cs +++ b/NewHorizons/Patches/VisionTorchPatches.cs @@ -71,6 +71,10 @@ namespace NewHorizons.Patches base_DropItem(__instance, position, normal, parent, sector, customDropTarget); } + if (__instance._wasProjecting) __instance._mindProjectorTrigger.SetProjectorActive(false); + + __instance.gameObject.GetComponent().enabled = true; + return true; } } diff --git a/NewHorizons/Schemas/addon_manifest_schema.json b/NewHorizons/Schemas/addon_manifest_schema.json index 4df4aa0f..bfe88b86 100644 --- a/NewHorizons/Schemas/addon_manifest_schema.json +++ b/NewHorizons/Schemas/addon_manifest_schema.json @@ -12,6 +12,13 @@ "$ref": "#/definitions/AchievementInfo" } }, + "credits": { + "type": "array", + "description": "Credits info for this mod. A list of contributors and their roles separated by #. For example: xen#New Horizons dev.", + "items": { + "type": "string" + } + }, "$schema": { "type": "string", "description": "The schema to validate with" diff --git a/NewHorizons/Schemas/body_schema.json b/NewHorizons/Schemas/body_schema.json index aecdc6be..d8d4db3c 100644 --- a/NewHorizons/Schemas/body_schema.json +++ b/NewHorizons/Schemas/body_schema.json @@ -364,9 +364,9 @@ }, "rotationSpeed": { "type": "number", - "description": "How fast the clouds will rotate in degrees per second.", + "description": "How fast the clouds will rotate relative to the planet in degrees per second.", "format": "float", - "default": 10.0 + "default": 0.0 } } }, @@ -450,6 +450,11 @@ "type": "boolean", "description": "If the body should have a marker on the map screen." }, + "hasSupernovaShockEffect": { + "type": "boolean", + "description": "Does this planet have a shock effect when the nearest star goes supernova?", + "default": true + }, "invulnerableToSun": { "type": "boolean", "description": "Can this planet survive entering a star?" diff --git a/NewHorizons/Utility/AstroObjectLocator.cs b/NewHorizons/Utility/AstroObjectLocator.cs index 93fe47d0..90552bb3 100644 --- a/NewHorizons/Utility/AstroObjectLocator.cs +++ b/NewHorizons/Utility/AstroObjectLocator.cs @@ -90,6 +90,16 @@ namespace NewHorizons.Utility return _customAstroObjectDictionary.Values.Where(x => x._primaryBody == primary).Select(x => x.gameObject).ToArray(); } + public static AstroObject[] GetAncestors(AstroObject astroObject) + { + List ancestors = new List(); + for (AstroObject primaryBody = astroObject._primaryBody; primaryBody != null && !ancestors.Contains(primaryBody); primaryBody = primaryBody._primaryBody) + { + ancestors.Add(primaryBody); + } + return ancestors.ToArray(); + } + public static GameObject[] GetChildren(AstroObject primary) { if (primary == null) return new GameObject[0]; @@ -143,7 +153,13 @@ namespace NewHorizons.Utility otherChildren.Add(SearchUtilities.Find("DB_SmallNest_Body")); otherChildren.Add(SearchUtilities.Find("DB_Elsinore_Body")); break; - // For some dumb reason the sun station doesn't use AstroObject.Name.SunStation + case AstroObject.Name.SunStation: + // there are multiple debris with the same name + otherChildren.AddRange(Object.FindObjectsOfType() + .Select(x => x.gameObject) + .Where(x => x.name == "SS_Debris_Body")); + break; + // Just in case GetChildren runs before sun station's name is changed case AstroObject.Name.CustomString: if (primary._customName.Equals("Sun Station")) { diff --git a/NewHorizons/Utility/MColor.cs b/NewHorizons/Utility/MColor.cs index 93d1781b..6ec161b7 100644 --- a/NewHorizons/Utility/MColor.cs +++ b/NewHorizons/Utility/MColor.cs @@ -1,4 +1,4 @@ -using System.ComponentModel; +using System.ComponentModel; using Newtonsoft.Json; using UnityEngine; namespace NewHorizons.Utility @@ -6,7 +6,7 @@ namespace NewHorizons.Utility [JsonObject] public class MColor { - public MColor(int r, int g, int b, int a) + public MColor(int r, int g, int b, int a = 255) { this.r = r; this.g = g; @@ -37,8 +37,30 @@ namespace NewHorizons.Utility /// [System.ComponentModel.DataAnnotations.Range(0, 255)] [DefaultValue(255)] - public int a; + public int a = 255; public Color ToColor() => new Color(r / 255f, g / 255f, b / 255f, a / 255f); + + public static MColor red => new MColor(255, 0, 0); + + public static MColor green => new MColor(0, 255, 0); + + public static MColor blue => new MColor(0, 0, 255); + + public static MColor white => new MColor(255, 255, 255); + + public static MColor black => new MColor(0, 0, 0); + + public static MColor yellow => new MColor(255, 235, 4); + + public static MColor cyan => new MColor(0, 255, 255); + + public static MColor magenta => new MColor(255, 0, 255); + + public static MColor gray => new MColor(127, 127, 127); + + public static MColor grey => new MColor(127, 127, 127); + + public static MColor clear => new MColor(0, 0, 0, 0); } }