mirror of
https://github.com/Outer-Wilds-New-Horizons/new-horizons.git
synced 2025-12-11 20:15:44 +01:00
commit
338baf21ff
5
.gitignore
vendored
5
.gitignore
vendored
@ -3,4 +3,7 @@ packages
|
||||
.vs
|
||||
bin
|
||||
obj
|
||||
Build
|
||||
zip
|
||||
*.zip
|
||||
|
||||
*/Build/*
|
||||
@ -23,8 +23,6 @@ namespace NewHorizons.Builder.Body
|
||||
int count = (int)(2f * Mathf.PI * belt.InnerRadius / (10f * maxSize));
|
||||
if (count > 200) count = 200;
|
||||
|
||||
Logger.Log($"Making {count} asteroids around {bodyName}");
|
||||
|
||||
Random.InitState(belt.RandomSeed);
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
|
||||
@ -17,7 +17,7 @@ namespace NewHorizons.Builder.Body
|
||||
cometTail.transform.localPosition = Vector3.zero;
|
||||
cometTail.name = "CometTail";
|
||||
cometTail.transform.localScale = Vector3.one * module.SurfaceSize / 110;
|
||||
cometTail.transform.localRotation = Quaternion.Euler(0, 180, 90);
|
||||
cometTail.transform.localRotation = Quaternion.Euler(0, 90, 90);
|
||||
/*
|
||||
var alignment = cometTail.AddComponent<AlignWithTargetBody>();
|
||||
alignment.SetTargetBody(primary.GetAttachedOWRigidbody());
|
||||
|
||||
@ -36,7 +36,7 @@ namespace NewHorizons.Builder.General
|
||||
|
||||
ParameterizedAstroObject astroObject = body.AddComponent<ParameterizedAstroObject>();
|
||||
|
||||
if (config.Orbit != null) astroObject.keplerElements = KeplerElements.FromOrbitModule(config.Orbit);
|
||||
if (config.Orbit != null) astroObject.SetKeplerCoordinatesFromOrbitModule(config.Orbit);
|
||||
|
||||
var type = AstroObject.Type.Planet;
|
||||
if (config.Orbit.IsMoon) type = AstroObject.Type.Moon;
|
||||
|
||||
@ -79,7 +79,6 @@ namespace NewHorizons.Builder.General
|
||||
var secondary = point.Secondary;
|
||||
var planets = point.Planets;
|
||||
|
||||
|
||||
// Binaries have to use the same gravity exponent
|
||||
var primaryGV = primary.GetGravityVolume();
|
||||
var secondaryGV = secondary.GetGravityVolume();
|
||||
@ -90,123 +89,26 @@ namespace NewHorizons.Builder.General
|
||||
return;
|
||||
}
|
||||
|
||||
// Have to use fall off type rn instead of exponent since it the exponent doesnt update until the Awake method I think
|
||||
var exponent = 0f;
|
||||
if (primaryGV.GetFalloffType() == OrbitalHelper.FalloffType.linear) exponent = 1f;
|
||||
if (primaryGV.GetFalloffType() == OrbitalHelper.FalloffType.inverseSquared) exponent = 2f;
|
||||
|
||||
// Very specific distance between them
|
||||
Vector3 separation = primary.transform.position - secondary.transform.position;
|
||||
var Gm1 = primaryGV.GetStandardGravitationalParameter();
|
||||
var Gm2 = secondaryGV.GetStandardGravitationalParameter();
|
||||
|
||||
// One of the two is zero if it just loaded
|
||||
if (Gm1 == 0) Gm1 = GravityVolume.GRAVITATIONAL_CONSTANT * primaryGV.GetValue<float>("_surfaceAcceleration") * Mathf.Pow(primaryGV.GetValue<float>("_upperSurfaceRadius"), exponent) / 0.001f;
|
||||
if (Gm2 == 0) Gm2 = GravityVolume.GRAVITATIONAL_CONSTANT * secondaryGV.GetValue<float>("_surfaceAcceleration") * Mathf.Pow(secondaryGV.GetValue<float>("_upperSurfaceRadius"), exponent) / 0.001f;
|
||||
|
||||
float r1 = separation.magnitude * Gm2 / (Gm1 + Gm2);
|
||||
float r2 = separation.magnitude * Gm1 / (Gm1 + Gm2);
|
||||
|
||||
primary.transform.position = point.transform.position + r1 * separation.normalized;
|
||||
secondary.transform.position = point.transform.position - r2 * separation.normalized;
|
||||
var pointForceDetector = point.GetAttachedOWRigidbody().GetAttachedForceDetector();
|
||||
|
||||
// Set detectable fields
|
||||
primaryCFD.SetValue("_detectableFields", new ForceVolume[] { secondaryGV });
|
||||
primaryCFD.SetValue("_inheritDetector", point.GetAttachedOWRigidbody().GetAttachedForceDetector());
|
||||
primaryCFD.SetValue("_activeInheritedDetector", point.GetAttachedOWRigidbody().GetAttachedForceDetector());
|
||||
primaryCFD.SetValue("_inheritDetector", pointForceDetector);
|
||||
primaryCFD.SetValue("_activeInheritedDetector", pointForceDetector);
|
||||
primaryCFD.SetValue("_inheritElement0", false);
|
||||
|
||||
secondaryCFD.SetValue("_detectableFields", new ForceVolume[] { primaryGV });
|
||||
secondaryCFD.SetValue("_inheritDetector", point.GetAttachedOWRigidbody().GetAttachedForceDetector());
|
||||
secondaryCFD.SetValue("_activeInheritedDetector", point.GetAttachedOWRigidbody().GetAttachedForceDetector());
|
||||
secondaryCFD.SetValue("_inheritDetector", pointForceDetector);
|
||||
secondaryCFD.SetValue("_activeInheritedDetector", pointForceDetector);
|
||||
secondaryCFD.SetValue("_inheritElement0", false);
|
||||
|
||||
// They must have the same eccentricity
|
||||
var parameterizedAstroObject = primary.GetComponent<ParameterizedAstroObject>();
|
||||
var parameterizedAstroObject2 = secondary.GetComponent<ParameterizedAstroObject>();
|
||||
|
||||
float ecc = 0;
|
||||
float i = 0;
|
||||
float l = 0;
|
||||
float p = 0;
|
||||
if (parameterizedAstroObject != null)
|
||||
foreach(var planet in planets)
|
||||
{
|
||||
ecc = parameterizedAstroObject.keplerElements.Eccentricity;
|
||||
i = parameterizedAstroObject.keplerElements.Inclination;
|
||||
l = parameterizedAstroObject.keplerElements.LongitudeOfAscendingNode;
|
||||
p = parameterizedAstroObject.keplerElements.ArgumentOfPeriapsis;
|
||||
}
|
||||
|
||||
// Update speeds
|
||||
var direction = Vector3.Cross(separation, Vector3.up).normalized;
|
||||
if (direction.sqrMagnitude == 0) direction = Vector3.left;
|
||||
|
||||
var m1 = Gm1 / GravityVolume.GRAVITATIONAL_CONSTANT;
|
||||
var m2 = Gm2 / GravityVolume.GRAVITATIONAL_CONSTANT;
|
||||
var reducedMass = m1 * m2 / (m1 + m2);
|
||||
var totalMass = m1 + m2;
|
||||
|
||||
var r = separation.magnitude;
|
||||
|
||||
// Start them off at their periapsis
|
||||
var primaryKeplerElements = KeplerElements.FromTrueAnomaly(ecc, r1 / (1f - ecc), i, l, p, 0);
|
||||
var secondaryKeplerElements = KeplerElements.FromTrueAnomaly(ecc, r2 / (1f - ecc), i, l, p, 180);
|
||||
|
||||
// Maybe we'll need these orbital parameters later
|
||||
if(parameterizedAstroObject != null) parameterizedAstroObject.keplerElements = primaryKeplerElements;
|
||||
if(parameterizedAstroObject2 != null) parameterizedAstroObject2.keplerElements = secondaryKeplerElements;
|
||||
|
||||
// Finally we update the speeds
|
||||
float v = Mathf.Sqrt(GravityVolume.GRAVITATIONAL_CONSTANT * totalMass * (1 - ecc * ecc) / Mathf.Pow(r, exponent - 1));
|
||||
var v2 = v / (1f + (m2 / m1));
|
||||
var v1 = v - v2;
|
||||
|
||||
// Rotate
|
||||
var rot = Quaternion.AngleAxis(l + p + 180f, Vector3.up);
|
||||
var incAxis = Quaternion.AngleAxis(l, Vector3.up) * Vector3.left;
|
||||
var incRot = Quaternion.AngleAxis(i, incAxis);
|
||||
|
||||
//Do this next tick for... reasons?
|
||||
var focalPointMotion = point.gameObject.GetComponent<InitialMotion>();
|
||||
var focalPointVelocity = focalPointMotion == null ? Vector3.zero : focalPointMotion.GetInitVelocity();
|
||||
|
||||
var d1 = Vector3.Cross(OrbitalHelper.RotateTo(Vector3.up, primaryKeplerElements), separation.normalized);
|
||||
var d2 = Vector3.Cross(OrbitalHelper.RotateTo(Vector3.up, primaryKeplerElements), separation.normalized);
|
||||
|
||||
var primaryInitialMotion = primary.gameObject.GetComponent<InitialMotion>();
|
||||
primaryInitialMotion.SetValue("_initLinearDirection", d1);
|
||||
primaryInitialMotion.SetValue("_initLinearSpeed", v1);
|
||||
|
||||
var secondaryInitialMotion = secondary.gameObject.GetComponent<InitialMotion>();
|
||||
secondaryInitialMotion.SetValue("_initLinearDirection", d2);
|
||||
secondaryInitialMotion.SetValue("_initLinearSpeed", -v2);
|
||||
|
||||
// InitialMotion already set its speed so we overwrite that
|
||||
if (!primaryInitialMotion.GetValue<bool>("_isInitVelocityDirty"))
|
||||
{
|
||||
Main.Instance.ModHelper.Events.Unity.FireOnNextUpdate(() => primaryRB.SetVelocity(d1 * v1 + focalPointVelocity));
|
||||
}
|
||||
if (!secondaryInitialMotion.GetValue<bool>("_isInitVelocityDirty"))
|
||||
{
|
||||
Main.Instance.ModHelper.Events.Unity.FireOnNextUpdate(() => primaryRB.SetVelocity(d2 * -v2 + focalPointVelocity));
|
||||
}
|
||||
|
||||
// If they have tracking orbits set the period
|
||||
var period = 2 * Mathf.PI * Mathf.Sqrt(Mathf.Pow(r, exponent + 1) / (GravityVolume.GRAVITATIONAL_CONSTANT * totalMass));
|
||||
|
||||
if (exponent == 1) period /= 3f;
|
||||
|
||||
// Only one of these won't be null, the other one gets done next tick
|
||||
var trackingOrbitPrimary = primary.GetComponentInChildren<TrackingOrbitLine>();
|
||||
if (trackingOrbitPrimary != null)
|
||||
{
|
||||
trackingOrbitPrimary.TrailTime = period;
|
||||
}
|
||||
|
||||
var trackingOrbitSecondary = secondary.GetComponentInChildren<TrackingOrbitLine>();
|
||||
if (trackingOrbitSecondary != null)
|
||||
{
|
||||
trackingOrbitSecondary.TrailTime = period;
|
||||
var planetCFD = planet.GetAttachedOWRigidbody().GetAttachedForceDetector() as ConstantForceDetector;
|
||||
planetCFD._detectableFields = new ForceVolume[] { primaryGV, secondaryGV };
|
||||
planetCFD._inheritDetector = pointForceDetector;
|
||||
planetCFD._activeInheritedDetector = pointForceDetector;
|
||||
planetCFD._inheritElement0 = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -19,6 +19,11 @@ namespace NewHorizons.Builder.General
|
||||
var gravityRadius = GM / 0.1f;
|
||||
if (exponent == 2f) gravityRadius = Mathf.Sqrt(gravityRadius);
|
||||
|
||||
// To let you actually orbit things the way you would expect we cap this at 4x the diameter if its not a star or black hole (this is what giants deep has)
|
||||
if (config.Star != null || config.Singularity != null) gravityRadius = Mathf.Min(gravityRadius, 4 * config.Base.SurfaceSize);
|
||||
else gravityRadius = Mathf.Min(gravityRadius, 15 * config.Base.SurfaceSize);
|
||||
if (config.Base.SphereOfInfluence != 0f) gravityRadius = config.Base.SphereOfInfluence;
|
||||
|
||||
GameObject gravityGO = new GameObject("GravityWell");
|
||||
gravityGO.transform.parent = body.transform;
|
||||
gravityGO.transform.localPosition = Vector3.zero;
|
||||
|
||||
251
NewHorizons/Builder/General/HeavenlyBodyBuilder.cs
Normal file
251
NewHorizons/Builder/General/HeavenlyBodyBuilder.cs
Normal file
@ -0,0 +1,251 @@
|
||||
using NewHorizons.External;
|
||||
using NewHorizons.OrbitalPhysics;
|
||||
using NewHorizons.Utility;
|
||||
using OWML.Common;
|
||||
using OWML.Utils;
|
||||
using PacificEngine.OW_CommonResources.Game;
|
||||
using PacificEngine.OW_CommonResources.Game.Resource;
|
||||
using PacificEngine.OW_CommonResources.Game.State;
|
||||
using PacificEngine.OW_CommonResources.Geometry.Orbits;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
using Logger = NewHorizons.Utility.Logger;
|
||||
|
||||
namespace NewHorizons.Builder.General
|
||||
{
|
||||
public static class HeavenlyBodyBuilder
|
||||
{
|
||||
private static readonly Dictionary<string, HeavenlyBody> _bodyMap = new Dictionary<string, HeavenlyBody>();
|
||||
|
||||
public static void Make(GameObject body, IPlanetConfig config, float SOI, GravityVolume bodyGravity, InitialMotion initialMotion)
|
||||
{
|
||||
var size = new Position.Size(config.Base.SurfaceSize, SOI);
|
||||
var gravity = GetGravity(bodyGravity);
|
||||
var parent = config.Orbit.PrimaryBody != null ? GetBody(config.Orbit.PrimaryBody) : HeavenlyBody.None;
|
||||
|
||||
if (config.Orbit.PrimaryBody != null && parent == HeavenlyBody.None)
|
||||
Logger.LogWarning($"Could not find [{config.Orbit.PrimaryBody}] parent of [{config.Name}]");
|
||||
|
||||
var orbit = OrbitalHelper.KeplerCoordinatesFromOrbitModule(config.Orbit);
|
||||
|
||||
var hb = GetBody(config.Name);
|
||||
if (hb == null) hb = AddHeavenlyBody(config.Name, config.FocalPoint != null);
|
||||
|
||||
Planet.Plantoid planetoid;
|
||||
|
||||
if (!config.Orbit.IsStatic) planetoid = new Planet.Plantoid(size, gravity, body.transform.rotation, initialMotion._initAngularSpeed, parent, orbit);
|
||||
else planetoid = new Planet.Plantoid(size, gravity, body.transform.rotation, 0f, HeavenlyBody.None, body.transform.position, Vector3.zero);
|
||||
|
||||
var mapping = Planet.defaultMapping;
|
||||
mapping[hb] = planetoid;
|
||||
|
||||
// Fix for binary focal points
|
||||
if(parent != HeavenlyBody.None)
|
||||
{
|
||||
var focalPoint = Position.AstroLookup[parent].Invoke()?.gameObject.GetComponent<BinaryFocalPoint>();
|
||||
if (focalPoint != null && mapping.ContainsKey(parent))
|
||||
{
|
||||
GameObject primary = null;
|
||||
GameObject secondary = null;
|
||||
|
||||
Gravity primaryGravity = null;
|
||||
Gravity secondaryGravity = null;
|
||||
|
||||
// One of them is null if it's the one being loaded
|
||||
if(config.Name.Equals(focalPoint.PrimaryName))
|
||||
{
|
||||
primary = body;
|
||||
primaryGravity = GetGravity(bodyGravity);
|
||||
secondary = Position.getBody(GetBody(focalPoint.SecondaryName))?.gameObject;
|
||||
var secondaryGV = Position.getBody(GetBody(focalPoint.SecondaryName))?.GetAttachedGravityVolume();
|
||||
if (secondaryGV != null) secondaryGravity = GetGravity(secondaryGV);
|
||||
}
|
||||
else if (config.Name.Equals(focalPoint.SecondaryName))
|
||||
{
|
||||
secondary = body;
|
||||
secondaryGravity = GetGravity(bodyGravity);
|
||||
primary = Position.getBody(GetBody(focalPoint.PrimaryName))?.gameObject;
|
||||
var primaryGV = Position.getBody(GetBody(focalPoint.PrimaryName))?.GetAttachedGravityVolume();
|
||||
if (primaryGV != null) primaryGravity = GetGravity(primaryGV);
|
||||
}
|
||||
|
||||
if (primaryGravity != null && secondaryGravity != null)
|
||||
{
|
||||
|
||||
// Also have to fix the children
|
||||
var primaryHB = GetBody(focalPoint.PrimaryName);
|
||||
var secondaryHB = GetBody(focalPoint.SecondaryName);
|
||||
|
||||
var r = primary.transform.position - secondary.transform.position;
|
||||
|
||||
var m1 = primaryGravity.mass;
|
||||
var m2 = secondaryGravity.mass;
|
||||
|
||||
float r1 = r.magnitude * m2 / (m1 + m2);
|
||||
float r2 = r.magnitude * m1 / (m1 + m2);
|
||||
|
||||
ParameterizedAstroObject primaryAO = Position.AstroLookup[primaryHB].Invoke() as ParameterizedAstroObject;
|
||||
ParameterizedAstroObject secondaryAO = Position.AstroLookup[secondaryHB].Invoke() as ParameterizedAstroObject;
|
||||
|
||||
float ecc = primaryAO.Eccentricity;
|
||||
float i = primaryAO.Inclination;
|
||||
float l = primaryAO.LongitudeOfAscendingNode;
|
||||
float p = primaryAO.ArgumentOfPeriapsis;
|
||||
|
||||
var primaryKeplerCoordinates = KeplerCoordinates.fromEccentricAnomaly(ecc, r1 / (1 - ecc), i, p, l, 0);
|
||||
var secondaryKeplerCoordinates = KeplerCoordinates.fromEccentricAnomaly(ecc, r2 / (1 - ecc), i, p, l, 180);
|
||||
|
||||
var totalMass = m1 + m2;
|
||||
|
||||
var exponent = (primaryGravity.exponent + secondaryGravity.exponent) / 2f;
|
||||
var primaryCartesianState = OrbitHelper.toCartesian(Gravity.of(exponent, totalMass), 0, primaryKeplerCoordinates);
|
||||
var secondaryCartesianState = OrbitHelper.toCartesian(Gravity.of(exponent, totalMass), 0, secondaryKeplerCoordinates);
|
||||
|
||||
var point = Position.AstroLookup[parent].Invoke();
|
||||
|
||||
primary.transform.position = point.transform.position + primaryCartesianState.Item1;
|
||||
secondary.transform.position = point.transform.position + secondaryCartesianState.Item1;
|
||||
|
||||
Logger.Log($"Positions: {primary.transform.position}, {secondary.transform.position}");
|
||||
|
||||
var primaryOriginal = mapping[primaryHB];
|
||||
var secondaryOriginal = mapping[secondaryHB];
|
||||
|
||||
// TODO: Idk if this works at all... probably not
|
||||
var primaryRotation = 0f;
|
||||
try
|
||||
{
|
||||
primaryRotation = primaryOriginal.state.relative.angularVelocity.magnitude;
|
||||
}
|
||||
catch (Exception) { };
|
||||
|
||||
var secondaryRotation = 0f;
|
||||
try
|
||||
{
|
||||
secondaryRotation = secondaryOriginal.state.relative.angularVelocity.magnitude;
|
||||
}
|
||||
catch (Exception) { };
|
||||
|
||||
mapping[primaryHB] = new Planet.Plantoid(
|
||||
primaryOriginal.size,
|
||||
primaryOriginal.gravity,
|
||||
primary.transform.rotation,
|
||||
primaryRotation,
|
||||
parent,
|
||||
primaryKeplerCoordinates);
|
||||
|
||||
mapping[secondaryHB] = new Planet.Plantoid(
|
||||
secondaryOriginal.size,
|
||||
secondaryOriginal.gravity,
|
||||
secondary.transform.rotation,
|
||||
secondaryRotation,
|
||||
parent,
|
||||
secondaryKeplerCoordinates);
|
||||
|
||||
var period = 2 * Mathf.PI * Mathf.Sqrt(Mathf.Pow(r.magnitude, exponent + 1) / (GravityVolume.GRAVITATIONAL_CONSTANT * totalMass));
|
||||
|
||||
var trackingOrbitPrimary = primary.GetComponentInChildren<TrackingOrbitLine>();
|
||||
if (trackingOrbitPrimary != null)
|
||||
{
|
||||
trackingOrbitPrimary.TrailTime = period;
|
||||
}
|
||||
|
||||
var trackingOrbitSecondary = secondary.GetComponentInChildren<TrackingOrbitLine>();
|
||||
if (trackingOrbitSecondary != null)
|
||||
{
|
||||
trackingOrbitSecondary.TrailTime = period;
|
||||
}
|
||||
|
||||
Logger.Log($"{parent}: {mapping[parent]}");
|
||||
Logger.Log($"{primaryHB}: {mapping[primaryHB]}");
|
||||
Logger.Log($"{secondaryHB}: {mapping[secondaryHB]}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Planet.defaultMapping = mapping;
|
||||
Planet.mapping = mapping;
|
||||
}
|
||||
|
||||
public static void Remove(AstroObject obj)
|
||||
{
|
||||
var astro = Position.find(obj);
|
||||
var mapping = Planet.defaultMapping;
|
||||
mapping.Remove(astro);
|
||||
Planet.defaultMapping = mapping;
|
||||
Planet.mapping = mapping;
|
||||
}
|
||||
|
||||
private static Gravity GetGravity(GravityVolume volume)
|
||||
{
|
||||
if (volume == null)
|
||||
{
|
||||
return Gravity.of(2, 0);
|
||||
}
|
||||
|
||||
var exponent = volume._falloffType != GravityVolume.FalloffType.linear ? 2f : 1f;
|
||||
var mass = (volume._surfaceAcceleration * Mathf.Pow(volume._upperSurfaceRadius, exponent)) / GravityVolume.GRAVITATIONAL_CONSTANT;
|
||||
|
||||
return Gravity.of(exponent, mass);
|
||||
}
|
||||
|
||||
private static HeavenlyBody AddHeavenlyBody(string name, bool isFocalPoint)
|
||||
{
|
||||
var hb = new HeavenlyBody(name, isFocalPoint);
|
||||
_bodyMap.Add(name, hb);
|
||||
|
||||
var astroLookup = Position.AstroLookup;
|
||||
var bodyLookup = Position.BodyLookup;
|
||||
|
||||
astroLookup.Add(hb, () => GetAstroObject(name));
|
||||
bodyLookup.Add(hb, () => GetOWRigidbody(name));
|
||||
|
||||
Position.AstroLookup = astroLookup;
|
||||
Position.BodyLookup = bodyLookup;
|
||||
|
||||
return hb;
|
||||
}
|
||||
|
||||
private static HeavenlyBody GetBody(string name)
|
||||
{
|
||||
if (_bodyMap.ContainsKey(name))
|
||||
{
|
||||
return _bodyMap[name];
|
||||
}
|
||||
|
||||
var hb = Position.find(AstroObjectLocator.GetAstroObject(name));
|
||||
if (hb != null)
|
||||
{
|
||||
_bodyMap.Add(name, hb);
|
||||
}
|
||||
return hb;
|
||||
}
|
||||
|
||||
public static void Reset()
|
||||
{
|
||||
Planet.defaultMapping = Planet.standardMapping;
|
||||
}
|
||||
|
||||
private static AstroObject GetAstroObject(string name)
|
||||
{
|
||||
var astroBody = AstroObjectLocator.GetAstroObject(name);
|
||||
if (astroBody == null
|
||||
|| astroBody.gameObject == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return astroBody;
|
||||
}
|
||||
|
||||
private static OWRigidbody GetOWRigidbody(string name)
|
||||
{
|
||||
var astroBody = GetAstroObject(name);
|
||||
return astroBody?.GetOWRigidbody();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -128,6 +128,8 @@ namespace NewHorizons.Builder.General
|
||||
Main.Instance.ModHelper.Events.Unity.FireOnNextUpdate(() => RemoveProxy(ao.name.Replace("_Body", "")));
|
||||
|
||||
ao.transform.root.gameObject.SetActive(false);
|
||||
|
||||
HeavenlyBodyBuilder.Remove(ao);
|
||||
}
|
||||
|
||||
public static void RemoveDistantProxyClones()
|
||||
|
||||
@ -20,10 +20,10 @@ namespace NewHorizons.Builder.General
|
||||
|
||||
spawnGO.transform.localPosition = module.PlayerSpawnPoint;
|
||||
|
||||
// Move it up a bit more
|
||||
spawnGO.transform.position = spawnGO.transform.position + spawnGO.transform.TransformDirection(Vector3.up) * 1f;
|
||||
|
||||
playerSpawn = spawnGO.AddComponent<SpawnPoint>();
|
||||
spawnGO.transform.rotation = Quaternion.FromToRotation(Vector3.up, (playerSpawn.transform.position - body.transform.position).normalized);
|
||||
spawnGO.transform.position = spawnGO.transform.position + spawnGO.transform.TransformDirection(Vector3.up) * 2f;
|
||||
|
||||
GameObject.FindObjectOfType<PlayerSpawner>().SetInitialSpawnPoint(playerSpawn);
|
||||
}
|
||||
if(module.ShipSpawnPoint != null)
|
||||
|
||||
@ -23,29 +23,30 @@ namespace NewHorizons.Builder.Orbital
|
||||
|
||||
public static InitialMotion Update(InitialMotion initialMotion, GameObject body, AstroObject primaryBody, OWRigidbody OWRB, OrbitModule orbit)
|
||||
{
|
||||
if (!orbit.IsStatic)
|
||||
{
|
||||
initialMotion.SetPrimaryBody(primaryBody?.GetAttachedOWRigidbody());
|
||||
initialMotion.SetValue("_orbitAngle", orbit.Inclination);
|
||||
initialMotion.SetValue("_isGlobalAxis", false);
|
||||
if (orbit.Eccentricity != 0 && primaryBody?.GetGravityVolume() != null)
|
||||
{
|
||||
// Calculate speed at apoapsis
|
||||
KeplerElements kepler = KeplerElements.FromOrbitModule(orbit);
|
||||
Gravity gravity = new Gravity(primaryBody.GetGravityVolume());
|
||||
|
||||
var eccSpeed = OrbitalHelper.GetOrbitalVelocity(kepler.Apoapsis, gravity, kepler);
|
||||
var circularSpeed = OWPhysics.CalculateOrbitVelocity(primaryBody.GetAttachedOWRigidbody(), OWRB).magnitude;
|
||||
|
||||
initialMotion.SetValue("_orbitImpulseScalar", eccSpeed / circularSpeed);
|
||||
}
|
||||
}
|
||||
|
||||
// Rotation
|
||||
initialMotion.SetValue("_initAngularSpeed", orbit.SiderealPeriod == 0 ? 0f : 1.0f / orbit.SiderealPeriod);
|
||||
var rotationAxis = Quaternion.AngleAxis(orbit.AxialTilt + orbit.Inclination, Vector3.right) * Vector3.up;
|
||||
|
||||
var rotationAxis = Quaternion.AngleAxis(orbit.AxialTilt + orbit.Inclination + 90f, Vector3.right) * Vector3.up;
|
||||
body.transform.rotation = Quaternion.FromToRotation(Vector3.up, rotationAxis);
|
||||
|
||||
initialMotion._orbitImpulseScalar = 0f;
|
||||
if (!orbit.IsStatic)
|
||||
{
|
||||
if(primaryBody != null)
|
||||
{
|
||||
initialMotion.SetPrimaryBody(primaryBody.GetAttachedOWRigidbody());
|
||||
var gv = primaryBody.GetGravityVolume();
|
||||
if(gv != null)
|
||||
{
|
||||
var velocity = OrbitalHelper.GetCartesian(new OrbitalHelper.Gravity(primaryBody.GetGravityVolume()), orbit).Item2;
|
||||
|
||||
// For some stupid reason the InitialMotion awake method transforms the perfectly fine direction vector you give it so we preemptively do the inverse so it all cancels out
|
||||
initialMotion._initLinearDirection = body.transform.InverseTransformDirection(velocity.normalized);
|
||||
initialMotion._initLinearSpeed = velocity.magnitude;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return initialMotion;
|
||||
}
|
||||
}
|
||||
|
||||
@ -21,15 +21,18 @@ namespace NewHorizons.Builder.Orbital
|
||||
lineRenderer.useWorldSpace = false;
|
||||
lineRenderer.loop = false;
|
||||
|
||||
var ecc = config.Orbit.Eccentricity;
|
||||
|
||||
var parentGravity = astroobject.GetPrimaryBody()?.GetGravityVolume();
|
||||
|
||||
OrbitLine orbitLine;
|
||||
if (config.Orbit.Eccentricity == 0)
|
||||
{
|
||||
if (ecc == 0)
|
||||
orbitLine = orbitGO.AddComponent<OrbitLine>();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Doesn't work for linear eccentric falloff
|
||||
else if (ecc > 0 && ecc < 1 && (parentGravity != null && parentGravity._falloffType == GravityVolume.FalloffType.inverseSquared))
|
||||
orbitLine = orbitGO.AddComponent<EllipticOrbitLine>();
|
||||
else
|
||||
orbitLine = orbitGO.AddComponent<TrackingOrbitLine>();
|
||||
}
|
||||
|
||||
var color = Color.white;
|
||||
if (config.Orbit.Tint != null) color = config.Orbit.Tint.ToColor32();
|
||||
|
||||
@ -94,8 +94,8 @@ namespace NewHorizons.Builder.Props
|
||||
prop.transform.parent = go.transform;
|
||||
prop.transform.localPosition = position == null ? Vector3.zero : (Vector3)position;
|
||||
|
||||
Quaternion rot = rotation == null ? prefab.transform.rotation : Quaternion.Euler((Vector3)rotation);
|
||||
prop.transform.rotation = rot;
|
||||
Quaternion rot = rotation == null ? Quaternion.identity : Quaternion.Euler((Vector3)rotation);
|
||||
prop.transform.localRotation = rot;
|
||||
if (alignWithNormal)
|
||||
{
|
||||
var up = prop.transform.localPosition.normalized;
|
||||
@ -116,7 +116,7 @@ namespace NewHorizons.Builder.Props
|
||||
private static void MakeScatter(GameObject go, PropModule.ScatterInfo[] scatterInfo, float radius, Sector sector, IModAssets assets, string uniqueModName)
|
||||
{
|
||||
var area = 4f * Mathf.PI * radius * radius;
|
||||
var points = FibonacciSphere((int)area);
|
||||
var points = RandomUtility.FibonacciSphere((int)area);
|
||||
|
||||
foreach (var propInfo in scatterInfo)
|
||||
{
|
||||
@ -136,27 +136,6 @@ namespace NewHorizons.Builder.Props
|
||||
}
|
||||
}
|
||||
|
||||
private static List<Vector3> FibonacciSphere(int samples)
|
||||
{
|
||||
List<Vector3> points = new List<Vector3>();
|
||||
|
||||
var phi = Mathf.PI * (3f - Mathf.Sqrt(5f));
|
||||
|
||||
for(int i = 0; i < samples; i++)
|
||||
{
|
||||
var y = 1 - (i / (float)(samples - 1)) * 2f;
|
||||
var radius = Mathf.Sqrt(1 - y * y);
|
||||
|
||||
var theta = phi * i;
|
||||
|
||||
var x = Mathf.Cos(theta) * radius;
|
||||
var z = Mathf.Sin(theta) * radius;
|
||||
|
||||
points.Add(new Vector3(x, y, z));
|
||||
}
|
||||
return points;
|
||||
}
|
||||
|
||||
private static GameObject LoadPrefab(string assetBundle, string path, string uniqueModName, IModAssets assets)
|
||||
{
|
||||
string key = uniqueModName + "." + assetBundle;
|
||||
|
||||
22
NewHorizons/Components/MapSatelliteOrbitFix.cs
Normal file
22
NewHorizons/Components/MapSatelliteOrbitFix.cs
Normal file
@ -0,0 +1,22 @@
|
||||
using NewHorizons.Builder.General;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NewHorizons.Components
|
||||
{
|
||||
public class MapSatelliteOrbitFix : MonoBehaviour
|
||||
{
|
||||
public void Awake()
|
||||
{
|
||||
var detector = base.transform.GetComponentInChildren<DynamicForceDetector>();
|
||||
var ao = base.GetComponent<AstroObject>();
|
||||
var newDetector = DetectorBuilder.Make(base.gameObject, ao.GetAttachedOWRigidbody(), ao.GetPrimaryBody(), ao);
|
||||
newDetector.transform.parent = detector.transform.parent;
|
||||
GameObject.Destroy(detector);
|
||||
}
|
||||
}
|
||||
}
|
||||
1
NewHorizons/External/BaseModule.cs
vendored
1
NewHorizons/External/BaseModule.cs
vendored
@ -14,6 +14,7 @@ namespace NewHorizons.External
|
||||
public float SurfaceGravity { get; set; }
|
||||
public string GravityFallOff { get; set; } = "linear";
|
||||
public float SurfaceSize { get; set; }
|
||||
public float SphereOfInfluence { get; set; }
|
||||
public float WaterSize { get; set; }
|
||||
public float GroundSize { get; set; }
|
||||
public float LavaSize { get; set; }
|
||||
|
||||
@ -4,6 +4,7 @@ using NewHorizons.Builder.Body;
|
||||
using NewHorizons.Builder.General;
|
||||
using NewHorizons.Builder.Orbital;
|
||||
using NewHorizons.Builder.Props;
|
||||
using NewHorizons.Components;
|
||||
using NewHorizons.External;
|
||||
using NewHorizons.OrbitalPhysics;
|
||||
using NewHorizons.Utility;
|
||||
@ -24,7 +25,6 @@ namespace NewHorizons
|
||||
{
|
||||
public class Main : ModBehaviour
|
||||
{
|
||||
|
||||
public static AssetBundle ShaderBundle;
|
||||
public static Main Instance { get; private set; }
|
||||
|
||||
@ -34,7 +34,8 @@ namespace NewHorizons
|
||||
public static float FurthestOrbit { get; set; } = 50000f;
|
||||
public StarLightController StarLightController { get; private set; }
|
||||
|
||||
private static string _currentStarSystem = "SolarSystem";
|
||||
private string _currentStarSystem = "SolarSystem";
|
||||
private bool _isChangingStarSystem = false;
|
||||
|
||||
public override object GetApi()
|
||||
{
|
||||
@ -45,6 +46,7 @@ namespace NewHorizons
|
||||
{
|
||||
SceneManager.sceneLoaded += OnSceneLoaded;
|
||||
Instance = this;
|
||||
GlobalMessenger<DeathType>.AddListener("PlayerDeath", OnDeath);
|
||||
ShaderBundle = Main.Instance.ModHelper.Assets.LoadBundle("AssetBundle/shader");
|
||||
|
||||
Utility.Patches.Apply();
|
||||
@ -60,7 +62,7 @@ namespace NewHorizons
|
||||
Logger.LogWarning("Couldn't find planets folder");
|
||||
}
|
||||
|
||||
//UnityEngine.Random.InitState();
|
||||
UnityEngine.Random.InitState((int)DateTime.Now.Ticks);
|
||||
Instance.ModHelper.Events.Unity.FireOnNextUpdate(() => OnSceneLoaded(SceneManager.GetActiveScene(), LoadSceneMode.Single));
|
||||
}
|
||||
|
||||
@ -68,19 +70,36 @@ namespace NewHorizons
|
||||
{
|
||||
Logger.Log($"Destroying NewHorizons");
|
||||
SceneManager.sceneLoaded -= OnSceneLoaded;
|
||||
GlobalMessenger<DeathType>.RemoveListener("PlayerDeath", OnDeath);
|
||||
}
|
||||
|
||||
void OnDeath(DeathType _)
|
||||
{
|
||||
// We reset the solar system on death (unless we just killed the player)
|
||||
if (!_isChangingStarSystem) _currentStarSystem = "SolarSystem";
|
||||
}
|
||||
|
||||
void OnSceneLoaded(Scene scene, LoadSceneMode mode)
|
||||
{
|
||||
Logger.Log($"Scene Loaded: {scene.name} {mode}");
|
||||
|
||||
_isChangingStarSystem = false;
|
||||
|
||||
HeavenlyBodyBuilder.Reset();
|
||||
|
||||
if (scene.name.Equals("TitleScreen")) DisplayBodyOnTitleScreen();
|
||||
|
||||
if (scene.name != "SolarSystem") return;
|
||||
if (scene.name != "SolarSystem")
|
||||
{
|
||||
// Reset back to original solar system after going to main menu.
|
||||
_currentStarSystem = "SolarSystem";
|
||||
return;
|
||||
}
|
||||
|
||||
NewHorizonsData.Load();
|
||||
|
||||
Instance.ModHelper.Events.Unity.FireOnNextUpdate(() => ShipLogBuilder.Init());
|
||||
Instance.ModHelper.Events.Unity.FireOnNextUpdate(() => AstroObjectLocator.GetAstroObject("MapSatellite").gameObject.AddComponent<MapSatelliteOrbitFix>());
|
||||
|
||||
// Need to manage this when there are multiple stars
|
||||
var sun = GameObject.Find("Sun_Body");
|
||||
@ -186,60 +205,84 @@ namespace NewHorizons
|
||||
public void DisplayBodyOnTitleScreen()
|
||||
{
|
||||
//Try loading one planet why not
|
||||
GameObject titleScreenGO = new GameObject("TitleScreenPlanet");
|
||||
var eligible = BodyList.Where(b => b.Config.Ring != null && (b.Config.HeightMap != null || (b.Config.Atmosphere?.Cloud != null))).ToArray();
|
||||
var body = eligible[UnityEngine.Random.Range(0, eligible.Count())];
|
||||
var eligible = BodyList.Where(b => b.Config.HeightMap != null || b.Config.Atmosphere?.Cloud != null).ToArray();
|
||||
var eligibleCount = eligible.Count();
|
||||
if (eligibleCount == 0) return;
|
||||
|
||||
var selectionCount = Mathf.Min(eligibleCount, 3);
|
||||
var indices = RandomUtility.GetUniqueRandomArray(0, eligible.Count(), selectionCount);
|
||||
|
||||
Logger.Log($"Displaying {selectionCount} bodies on the title screen");
|
||||
|
||||
GameObject body1, body2, body3;
|
||||
|
||||
body1 = LoadTitleScreenBody(eligible[indices[0]]);
|
||||
Logger.LogPath(body1);
|
||||
if (selectionCount > 1)
|
||||
{
|
||||
body1.transform.localScale = Vector3.one * (body1.transform.localScale.x) * 0.3f;
|
||||
body1.transform.localPosition = new Vector3(0, -20, 0);
|
||||
body2 = LoadTitleScreenBody(eligible[indices[1]]);
|
||||
body2.transform.localScale = Vector3.one * (body2.transform.localScale.x) * 0.3f;
|
||||
body2.transform.localPosition = new Vector3(7, 40, 0);
|
||||
}
|
||||
if (selectionCount > 2)
|
||||
{
|
||||
body3 = LoadTitleScreenBody(eligible[indices[2]]);
|
||||
body3.transform.localScale = Vector3.one * (body3.transform.localScale.x) * 0.3f;
|
||||
body3.transform.localPosition = new Vector3(-5, 10, 0);
|
||||
}
|
||||
|
||||
GameObject.Find("Scene/Background/PlanetPivot/Prefab_HEA_Campfire").SetActive(false);
|
||||
GameObject.Find("Scene/Background/PlanetPivot/PlanetRoot").SetActive(false);
|
||||
|
||||
var lightGO = new GameObject("Light");
|
||||
lightGO.transform.parent = GameObject.Find("Scene/Background").transform;
|
||||
lightGO.transform.localPosition = new Vector3(-47.9203f, 145.7596f, 43.1802f);
|
||||
var light = lightGO.AddComponent<Light>();
|
||||
light.color = new Color(1f, 1f, 1f, 1f);
|
||||
light.range = 100;
|
||||
light.intensity = 0.8f;
|
||||
}
|
||||
|
||||
private GameObject LoadTitleScreenBody(NewHorizonsBody body)
|
||||
{
|
||||
Logger.Log($"Displaying {body.Config.Name} on the title screen");
|
||||
|
||||
var flag = false;
|
||||
GameObject titleScreenGO = new GameObject(body.Config.Name + "_TitleScreen");
|
||||
HeightMapModule heightMap = new HeightMapModule();
|
||||
var minSize = 20;
|
||||
var maxSize = 35;
|
||||
var minSize = 15;
|
||||
var maxSize = 30;
|
||||
float size = minSize;
|
||||
if (body.Config.HeightMap != null)
|
||||
{
|
||||
size = Mathf.Clamp(body.Config.HeightMap.MaxHeight / 10, minSize, maxSize);
|
||||
size = Mathf.Clamp(body.Config.HeightMap.MaxHeight / 10, minSize, maxSize);
|
||||
heightMap.TextureMap = body.Config.HeightMap.TextureMap;
|
||||
heightMap.HeightMap = body.Config.HeightMap.HeightMap;
|
||||
heightMap.MaxHeight = size;
|
||||
heightMap.MinHeight = body.Config.HeightMap.MinHeight * size / body.Config.HeightMap.MaxHeight;
|
||||
flag = true;
|
||||
}
|
||||
if (body.Config.Atmosphere != null && body.Config.Atmosphere.Cloud != null)
|
||||
{
|
||||
// Hacky but whatever I just want a sphere
|
||||
size = Mathf.Clamp(body.Config.Atmosphere.Size / 10, minSize, maxSize);
|
||||
heightMap.MaxHeight = heightMap.MinHeight = size+1;
|
||||
heightMap.MaxHeight = heightMap.MinHeight = size + 1;
|
||||
heightMap.TextureMap = body.Config.Atmosphere.Cloud;
|
||||
flag = true;
|
||||
}
|
||||
|
||||
if (flag)
|
||||
HeightMapBuilder.Make(titleScreenGO, heightMap, body.Assets);
|
||||
if (body.Config.Ring != null)
|
||||
{
|
||||
HeightMapBuilder.Make(titleScreenGO, heightMap, body.Assets);
|
||||
if (body.Config.Ring != null)
|
||||
{
|
||||
RingModule newRing = new RingModule();
|
||||
newRing.InnerRadius = size * 1.2f;
|
||||
newRing.OuterRadius = size * 2f;
|
||||
newRing.Texture = body.Config.Ring.Texture;
|
||||
RingBuilder.Make(titleScreenGO, newRing, body.Assets);
|
||||
titleScreenGO.transform.localScale = Vector3.one * 0.8f;
|
||||
}
|
||||
GameObject.Find("Scene/Background/PlanetPivot/Prefab_HEA_Campfire").SetActive(false);
|
||||
GameObject.Find("Scene/Background/PlanetPivot/PlanetRoot").SetActive(false);
|
||||
titleScreenGO.transform.parent = GameObject.Find("Scene/Background/PlanetPivot/").transform;
|
||||
titleScreenGO.transform.localPosition = Vector3.zero;
|
||||
|
||||
var lightGO = new GameObject("Light");
|
||||
lightGO.transform.parent = titleScreenGO.transform.parent.parent;
|
||||
lightGO.transform.localPosition = new Vector3(-47.9203f, 145.7596f, 43.1802f);
|
||||
var light = lightGO.AddComponent<Light>();
|
||||
light.color = new Color(1f, 1f, 1f, 1f);
|
||||
light.range = 100;
|
||||
light.intensity = 0.8f;
|
||||
RingModule newRing = new RingModule();
|
||||
newRing.InnerRadius = size * 1.2f;
|
||||
newRing.OuterRadius = size * 2f;
|
||||
newRing.Texture = body.Config.Ring.Texture;
|
||||
RingBuilder.Make(titleScreenGO, newRing, body.Assets);
|
||||
titleScreenGO.transform.localScale = Vector3.one * 0.8f;
|
||||
}
|
||||
titleScreenGO.transform.parent = GameObject.Find("Scene/Background/PlanetPivot/").transform;
|
||||
titleScreenGO.transform.localPosition = Vector3.zero;
|
||||
|
||||
return titleScreenGO;
|
||||
}
|
||||
|
||||
private bool LoadBody(NewHorizonsBody body, bool defaultPrimaryToSun = false)
|
||||
@ -401,8 +444,7 @@ namespace NewHorizons
|
||||
|
||||
// Now that we're done move the planet into place
|
||||
go.transform.parent = Locator.GetRootTransform();
|
||||
var positionVector = OrbitalHelper.RotateTo(Vector3.left * body.Config.Orbit.SemiMajorAxis * (1 + body.Config.Orbit.Eccentricity), body.Config.Orbit);
|
||||
go.transform.position = positionVector + (primaryBody == null ? Vector3.zero : primaryBody.transform.position);
|
||||
go.transform.position = OrbitalHelper.GetCartesian(new OrbitalHelper.Gravity(1, 100), body.Config.Orbit).Item1 + (primaryBody == null ? Vector3.zero : primaryBody.transform.position);
|
||||
|
||||
if (go.transform.position.magnitude > FurthestOrbit)
|
||||
{
|
||||
@ -424,6 +466,8 @@ namespace NewHorizons
|
||||
|
||||
if (ao.GetAstroObjectName() == AstroObject.Name.CustomString) AstroObjectLocator.RegisterCustomAstroObject(ao);
|
||||
|
||||
HeavenlyBodyBuilder.Make(go, body.Config, sphereOfInfluence, gv, initialMotion);
|
||||
|
||||
return go;
|
||||
}
|
||||
|
||||
@ -477,6 +521,8 @@ namespace NewHorizons
|
||||
public void ChangeCurrentStarSystem(string newStarSystem)
|
||||
{
|
||||
_currentStarSystem = newStarSystem;
|
||||
_isChangingStarSystem = true;
|
||||
Locator.GetDeathManager().KillPlayer(DeathType.Meditation);
|
||||
LoadManager.LoadSceneAsync(OWScene.SolarSystem, true, LoadManager.FadeType.ToBlack, 0.1f, true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -30,6 +30,12 @@
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="PacificEngine.OW_CommonResources">
|
||||
<HintPath>$(OuterWildsModsDirectory)\PacificEngine.OW_CommonResources\PacificEngine.OW_CommonResources.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="NewHorizons.csproj.user" />
|
||||
</ItemGroup>
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<ProjectView>ProjectFiles</ProjectView>
|
||||
<OutputPath>C:\Users\Nicholas\AppData\Roaming\OuterWildsModManager\OWML\Mods\xen.NewHorizons</OutputPath>
|
||||
<OutputPath>$(AppData)\OuterWildsModManager\OWML\Mods\xen.NewHorizons</OutputPath>
|
||||
<OuterWildsModsDirectory>$(AppData)\OuterWildsModManager\OWML\Mods</OuterWildsModsDirectory>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
|
||||
@ -1,27 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NewHorizons.OrbitalPhysics
|
||||
{
|
||||
public class CartesianStateVectors
|
||||
{
|
||||
public Vector3 Position { get; set; }
|
||||
public Vector3 Velocity { get; set; }
|
||||
|
||||
public CartesianStateVectors()
|
||||
{
|
||||
Position = Vector3.zero;
|
||||
Velocity = Vector3.zero;
|
||||
}
|
||||
|
||||
public CartesianStateVectors(Vector3 pos, Vector3 vel)
|
||||
{
|
||||
Position = pos;
|
||||
Velocity = vel;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,27 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using NewHorizons.Utility;
|
||||
|
||||
namespace NewHorizons.OrbitalPhysics
|
||||
{
|
||||
public class Gravity
|
||||
{
|
||||
public float Exponent { get; }
|
||||
public float Mass { get; }
|
||||
|
||||
public Gravity(float exponent, float mass)
|
||||
{
|
||||
Exponent = exponent;
|
||||
Mass = mass;
|
||||
}
|
||||
|
||||
public Gravity(GravityVolume gv)
|
||||
{
|
||||
Exponent = gv.GetFalloffExponent();
|
||||
Mass = gv.GetStandardGravitationalParameter() / GravityVolume.GRAVITATIONAL_CONSTANT;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,127 +0,0 @@
|
||||
using NewHorizons.External;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NewHorizons.OrbitalPhysics
|
||||
{
|
||||
public class KeplerElements
|
||||
{
|
||||
public float LongitudeOfAscendingNode { get; }
|
||||
public float Eccentricity { get; }
|
||||
public float SemiMajorAxis { get; }
|
||||
public float Inclination { get; }
|
||||
public float ArgumentOfPeriapsis { get; }
|
||||
public float TrueAnomaly { get; private set; }
|
||||
public float EccentricAnomaly { get; private set; }
|
||||
public float MeanAnomaly { get; private set; }
|
||||
public float SemiMinorAxis { get; }
|
||||
public float Focus { get; }
|
||||
public float Apoapsis { get; }
|
||||
public float Periapsis { get; }
|
||||
|
||||
private KeplerElements(float e, float a, float i, float longitudeOfAscendingNode, float argumentOfPeriapsis, float trueAnomaly, float eccentricAnomaly, float meanAnomaly)
|
||||
{
|
||||
LongitudeOfAscendingNode = longitudeOfAscendingNode;
|
||||
Eccentricity = e;
|
||||
SemiMajorAxis = a;
|
||||
Inclination = i;
|
||||
ArgumentOfPeriapsis = argumentOfPeriapsis;
|
||||
TrueAnomaly = trueAnomaly;
|
||||
|
||||
SemiMinorAxis = SemiMajorAxis * Mathf.Sqrt(1 - Eccentricity * Eccentricity);
|
||||
Focus = Mathf.Sqrt((SemiMajorAxis * SemiMajorAxis) - (SemiMinorAxis * SemiMinorAxis));
|
||||
Apoapsis = SemiMajorAxis + Focus;
|
||||
Periapsis = SemiMajorAxis - Focus;
|
||||
|
||||
EccentricAnomaly = eccentricAnomaly;
|
||||
MeanAnomaly = meanAnomaly;
|
||||
}
|
||||
|
||||
public static KeplerElements FromOrbitModule(OrbitModule module)
|
||||
{
|
||||
return FromTrueAnomaly(module.Eccentricity, module.SemiMajorAxis, module.Inclination, module.LongitudeOfAscendingNode, module.ArgumentOfPeriapsis, module.TrueAnomaly);
|
||||
}
|
||||
|
||||
public static KeplerElements FromTrueAnomaly(float e, float a, float i, float longitudeOfAscendingNode, float argumentOfPeriapsis, float trueAnomaly)
|
||||
{
|
||||
var newKeplerElements = new KeplerElements(e, a, i, longitudeOfAscendingNode, argumentOfPeriapsis, 0, 0, 0);
|
||||
newKeplerElements.SetTrueAnomaly(trueAnomaly);
|
||||
return newKeplerElements;
|
||||
}
|
||||
|
||||
public static KeplerElements FromMeanAnomaly(float e, float a, float i, float longitudeOfAscendingNode, float argumentOfPeriapsis, float meanAnomaly)
|
||||
{
|
||||
var newKeplerElements = new KeplerElements(e, a, i, longitudeOfAscendingNode, argumentOfPeriapsis, 0, 0, 0);
|
||||
newKeplerElements.SetMeanAnomaly(meanAnomaly);
|
||||
return newKeplerElements;
|
||||
}
|
||||
|
||||
public static KeplerElements FromEccentricAnomaly(float e, float a, float i, float longitudeOfAscendingNode, float argumentOfPeriapsis, float eccentricAnomaly)
|
||||
{
|
||||
var newKeplerElements = new KeplerElements(e, a, i, longitudeOfAscendingNode, argumentOfPeriapsis, 0, 0, 0);
|
||||
newKeplerElements.SetEccentricAnomaly(eccentricAnomaly);
|
||||
return newKeplerElements;
|
||||
}
|
||||
|
||||
public static KeplerElements Copy(KeplerElements original)
|
||||
{
|
||||
return KeplerElements.FromTrueAnomaly(original.Eccentricity, original.SemiMajorAxis, original.Inclination, original.LongitudeOfAscendingNode, original.ArgumentOfPeriapsis, original.TrueAnomaly);
|
||||
}
|
||||
|
||||
public void SetTrueAnomaly(float trueAnomaly)
|
||||
{
|
||||
TrueAnomaly = trueAnomaly;
|
||||
EccentricAnomaly = EccentricAnomalyFromTrueAnomaly(trueAnomaly, Eccentricity);
|
||||
MeanAnomaly = MeanAnomalyFromEccentricAnomaly(EccentricAnomaly, Eccentricity);
|
||||
}
|
||||
|
||||
public void SetMeanAnomaly(float meanAnomaly)
|
||||
{
|
||||
MeanAnomaly = meanAnomaly;
|
||||
TrueAnomaly = TrueAnomalyFromMeanAnomaly(meanAnomaly, Eccentricity);
|
||||
EccentricAnomaly = EccentricAnomalyFromTrueAnomaly(TrueAnomaly, Eccentricity);
|
||||
}
|
||||
|
||||
public void SetEccentricAnomaly(float eccentricAnomaly)
|
||||
{
|
||||
EccentricAnomaly = eccentricAnomaly;
|
||||
TrueAnomaly = TrueAnomalyFromEccentricAnomaly(eccentricAnomaly, Eccentricity);
|
||||
MeanAnomaly = MeanAnomalyFromEccentricAnomaly(eccentricAnomaly, Eccentricity);
|
||||
}
|
||||
|
||||
private static float MeanAnomalyFromEccentricAnomaly(float eccentricAnomaly, float eccentricity)
|
||||
{
|
||||
return eccentricAnomaly - eccentricity * Mathf.Sin(eccentricAnomaly);
|
||||
}
|
||||
|
||||
private static float TrueAnomalyFromEccentricAnomaly(float eccentricAnomaly, float eccentricity)
|
||||
{
|
||||
var a = Mathf.Cos(eccentricAnomaly) - eccentricity;
|
||||
var h = 1 - eccentricity * Mathf.Cos(eccentricAnomaly);
|
||||
var o = h * h - a * a;
|
||||
return Mathf.Atan2(o, a);
|
||||
}
|
||||
|
||||
private static float EccentricAnomalyFromTrueAnomaly(float trueAnomaly, float eccentricity)
|
||||
{
|
||||
var a = Mathf.Cos(trueAnomaly) + eccentricity;
|
||||
var h = 1 + eccentricity * Mathf.Cos(trueAnomaly);
|
||||
var o = h * h - a * a;
|
||||
return Mathf.Atan2(o, a);
|
||||
}
|
||||
|
||||
private static float TrueAnomalyFromMeanAnomaly(float meanAnomaly, float eccentricity)
|
||||
{
|
||||
// Fourier expansion
|
||||
var term1 = meanAnomaly;
|
||||
var term2 = (2 * eccentricity - eccentricity * eccentricity * eccentricity / 4f) * Mathf.Sin(meanAnomaly);
|
||||
var term3 = (eccentricity * eccentricity * Mathf.Sin(2 * meanAnomaly) * 5f / 4f);
|
||||
var term4 = (eccentricity * eccentricity * eccentricity * Mathf.Sin(3 * meanAnomaly) * 13f / 12f);
|
||||
return term1 + term2 + term3 + term4;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,86 +1,88 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
using NewHorizons.Utility;
|
||||
using Logger = NewHorizons.Utility.Logger;
|
||||
using NewHorizons.External;
|
||||
|
||||
namespace NewHorizons.OrbitalPhysics
|
||||
{
|
||||
public static class OrbitalHelper
|
||||
{
|
||||
public enum FalloffType
|
||||
{
|
||||
inverseSquared,
|
||||
linear,
|
||||
none
|
||||
}
|
||||
|
||||
public static Vector3 RotateTo(Vector3 vector, KeplerElements elements)
|
||||
{
|
||||
// For now, eccentric orbits gotta start at apoapsis and cant be inclined
|
||||
var rot = Quaternion.AngleAxis(elements.LongitudeOfAscendingNode + elements.TrueAnomaly + elements.ArgumentOfPeriapsis + 180f, Vector3.up);
|
||||
if (elements.Eccentricity != 0)
|
||||
{
|
||||
rot = Quaternion.AngleAxis(elements.LongitudeOfAscendingNode + elements.ArgumentOfPeriapsis + 180f, Vector3.up);
|
||||
}
|
||||
|
||||
var incAxis = Quaternion.AngleAxis(elements.LongitudeOfAscendingNode, Vector3.up) * Vector3.left;
|
||||
var incRot = Quaternion.AngleAxis(elements.Inclination, incAxis);
|
||||
|
||||
return rot * incRot * vector;
|
||||
}
|
||||
|
||||
public static Vector3 RotateTo(Vector3 vector, OrbitModule module)
|
||||
{
|
||||
return RotateTo(vector, KeplerElements.FromOrbitModule(module));
|
||||
}
|
||||
|
||||
public static Vector3 VelocityDirection(Vector3 separation, KeplerElements elements)
|
||||
{
|
||||
var incAxis = Quaternion.AngleAxis(elements.LongitudeOfAscendingNode, Vector3.up) * Vector3.left;
|
||||
var incRot = Quaternion.AngleAxis(elements.Inclination, incAxis);
|
||||
return Vector3.Cross(RotateTo(Vector3.up, elements), separation);
|
||||
}
|
||||
|
||||
public static float GetOrbitalVelocity(float distance, Gravity gravity, KeplerElements kepler)
|
||||
{
|
||||
if (kepler.Eccentricity == 0) return GetCircularOrbitVelocity(distance, gravity, kepler);
|
||||
|
||||
if (gravity.Exponent == 2)
|
||||
{
|
||||
return Mathf.Sqrt(GravityVolume.GRAVITATIONAL_CONSTANT * gravity.Mass * (2f / distance - 1f / kepler.SemiMajorAxis));
|
||||
}
|
||||
if(gravity.Exponent == 1)
|
||||
{
|
||||
var mu = GravityVolume.GRAVITATIONAL_CONSTANT * gravity.Mass;
|
||||
var rp2 = kepler.Periapsis * kepler.Periapsis;
|
||||
var ra2 = kepler.Apoapsis * kepler.Apoapsis;
|
||||
float term1 = 0;
|
||||
if(kepler.Eccentricity < 1)
|
||||
term1 = mu * Mathf.Log(kepler.Periapsis / kepler.Apoapsis) * rp2 / (rp2 - ra2);
|
||||
var term2 = mu * Mathf.Log(kepler.Apoapsis / distance);
|
||||
return Mathf.Sqrt(2 * (term1 + term2));
|
||||
}
|
||||
Logger.LogError($"Invalid exponent {gravity.Exponent}");
|
||||
return 0f;
|
||||
}
|
||||
|
||||
public static float GetCircularOrbitVelocity(float distance, Gravity gravity, KeplerElements kepler)
|
||||
{
|
||||
if (gravity.Exponent == 2)
|
||||
{
|
||||
return Mathf.Sqrt(GravityVolume.GRAVITATIONAL_CONSTANT * gravity.Mass / distance);
|
||||
}
|
||||
if(gravity.Exponent == 1)
|
||||
{
|
||||
return Mathf.Sqrt(GravityVolume.GRAVITATIONAL_CONSTANT * gravity.Mass);
|
||||
}
|
||||
Logger.LogError($"Invalid exponent {gravity.Exponent}");
|
||||
return 0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
using NewHorizons.Utility;
|
||||
using Logger = NewHorizons.Utility.Logger;
|
||||
using NewHorizons.External;
|
||||
using CRGravity = PacificEngine.OW_CommonResources.Geometry.Orbits.Gravity;
|
||||
using KeplerCoordinates = PacificEngine.OW_CommonResources.Geometry.Orbits.KeplerCoordinates;
|
||||
|
||||
/*
|
||||
* Wrapper class for OW_CommonResources.Geometry.Orbits functions
|
||||
*/
|
||||
namespace NewHorizons.OrbitalPhysics
|
||||
{
|
||||
public static class OrbitalHelper
|
||||
{
|
||||
public enum FalloffType
|
||||
{
|
||||
inverseSquared,
|
||||
linear,
|
||||
none
|
||||
}
|
||||
|
||||
public static Tuple<Vector3, Vector3> GetCartesian(Gravity gravity, OrbitModule orbit)
|
||||
{
|
||||
if (orbit.SemiMajorAxis == 0)
|
||||
{
|
||||
return Tuple.Create(Vector3.zero, Vector3.zero);
|
||||
}
|
||||
|
||||
var crGravity = new CRGravity(GravityVolume.GRAVITATIONAL_CONSTANT, gravity.Exponent, gravity.Mass);
|
||||
var kepler = KeplerCoordinates.fromTrueAnomaly(orbit.Eccentricity, orbit.SemiMajorAxis, orbit.Inclination, orbit.ArgumentOfPeriapsis, orbit.LongitudeOfAscendingNode, orbit.TrueAnomaly);
|
||||
var cartesian = PacificEngine.OW_CommonResources.Geometry.Orbits.OrbitHelper.toCartesian(crGravity, 0f, kepler);
|
||||
|
||||
if (cartesian == null)
|
||||
{
|
||||
cartesian = Tuple.Create(Vector3.zero, Vector3.zero);
|
||||
}
|
||||
|
||||
return cartesian;
|
||||
}
|
||||
|
||||
public static Tuple<Vector3, Vector3> GetCartesian(Gravity gravity, ParameterizedAstroObject ao)
|
||||
{
|
||||
if (ao.SemiMajorAxis == 0)
|
||||
{
|
||||
return Tuple.Create(Vector3.zero, Vector3.zero);
|
||||
}
|
||||
|
||||
var crGravity = new CRGravity(GravityVolume.GRAVITATIONAL_CONSTANT, gravity.Exponent, gravity.Mass);
|
||||
var kepler = KeplerCoordinates.fromTrueAnomaly(ao.Eccentricity, ao.SemiMajorAxis, ao.Inclination, ao.ArgumentOfPeriapsis, ao.LongitudeOfAscendingNode, ao.TrueAnomaly);
|
||||
var cartesian = PacificEngine.OW_CommonResources.Geometry.Orbits.OrbitHelper.toCartesian(crGravity, 0f, kepler);
|
||||
|
||||
if (cartesian == null)
|
||||
{
|
||||
cartesian = Tuple.Create(Vector3.zero, Vector3.zero);
|
||||
}
|
||||
|
||||
return cartesian;
|
||||
}
|
||||
|
||||
public static KeplerCoordinates KeplerCoordinatesFromOrbitModule(OrbitModule orbit)
|
||||
{
|
||||
return KeplerCoordinates.fromTrueAnomaly(orbit.Eccentricity, orbit.SemiMajorAxis, orbit.Inclination, orbit.ArgumentOfPeriapsis, orbit.LongitudeOfAscendingNode, orbit.TrueAnomaly);
|
||||
}
|
||||
|
||||
public class Gravity
|
||||
{
|
||||
public float Exponent { get; }
|
||||
public float Mass { get; }
|
||||
|
||||
public Gravity(float exponent, float mass)
|
||||
{
|
||||
Exponent = exponent;
|
||||
Mass = mass;
|
||||
}
|
||||
|
||||
public Gravity(GravityVolume gv)
|
||||
{
|
||||
Exponent = gv.GetFalloffExponent();
|
||||
Mass = gv.GetStandardGravitationalParameter() / GravityVolume.GRAVITATIONAL_CONSTANT;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,6 @@
|
||||
using System;
|
||||
using NewHorizons.External;
|
||||
using PacificEngine.OW_CommonResources.Geometry.Orbits;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
@ -8,6 +10,51 @@ namespace NewHorizons.OrbitalPhysics
|
||||
{
|
||||
public class ParameterizedAstroObject : AstroObject
|
||||
{
|
||||
public KeplerElements keplerElements;
|
||||
private KeplerCoordinates _keplerCoordinates;
|
||||
|
||||
public float Eccentricity
|
||||
{
|
||||
get { return _keplerCoordinates.eccentricity; }
|
||||
}
|
||||
|
||||
public float SemiMajorAxis
|
||||
{
|
||||
get { return _keplerCoordinates.semiMajorRadius; }
|
||||
}
|
||||
|
||||
public float Inclination
|
||||
{
|
||||
get { return _keplerCoordinates.inclinationAngle; }
|
||||
}
|
||||
|
||||
public float ArgumentOfPeriapsis
|
||||
{
|
||||
get { return _keplerCoordinates.periapseAngle; }
|
||||
}
|
||||
|
||||
public float LongitudeOfAscendingNode
|
||||
{
|
||||
get { return _keplerCoordinates.ascendingAngle; }
|
||||
}
|
||||
|
||||
public float TrueAnomaly
|
||||
{
|
||||
get { return _keplerCoordinates.trueAnomaly; }
|
||||
}
|
||||
|
||||
public void SetKeplerCoordinatesFromOrbitModule(OrbitModule orbit)
|
||||
{
|
||||
_keplerCoordinates = KeplerCoordinates.fromTrueAnomaly(orbit.Eccentricity, orbit.SemiMajorAxis, orbit.Inclination, orbit.ArgumentOfPeriapsis, orbit.LongitudeOfAscendingNode, orbit.TrueAnomaly);
|
||||
}
|
||||
|
||||
public void SetKeplerCoordinatesFromTrueAnomaly(float ecc, float a, float i, float p, float l, float trueAnomaly)
|
||||
{
|
||||
_keplerCoordinates = KeplerCoordinates.fromTrueAnomaly(ecc, a, i, p, l, trueAnomaly);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"ParameterizedAstroObject: Eccentricity {Eccentricity}, SemiMajorAxis {SemiMajorAxis}, Inclination {Inclination}, ArgumentOfPeriapsis {ArgumentOfPeriapsis}, LongitudeOfAscendingNode {LongitudeOfAscendingNode}, TrueAnomaly {TrueAnomaly}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -19,7 +19,7 @@ namespace NewHorizons.Utility
|
||||
|
||||
public static AstroObject GetAstroObject(string name)
|
||||
{
|
||||
if (name.Equals("MAP_SATELLITE"))
|
||||
if (name.ToUpper().Replace("_", "").Equals("MAPSATELLITE"))
|
||||
return GetAstroObject(AstroObject.Name.MapSatellite);
|
||||
var aoName = AstroObject.StringIDToAstroObjectName(name);
|
||||
if(aoName == AstroObject.Name.None) aoName = AstroObject.StringIDToAstroObjectName(name.ToUpper().Replace(" ", "_"));
|
||||
|
||||
@ -30,7 +30,10 @@ namespace NewHorizons.Utility
|
||||
public static float GetFalloffExponent(this GravityVolume gv)
|
||||
{
|
||||
if (gv == null) return 0;
|
||||
return (float)typeof(GravityVolume).GetField("_falloffExponent", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(gv);
|
||||
if (gv._falloffType == GravityVolume.FalloffType.linear) return 1;
|
||||
if (gv._falloffType == GravityVolume.FalloffType.inverseSquared) return 2;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static string ToCamelCase(this string str)
|
||||
|
||||
51
NewHorizons/Utility/RandomUtility.cs
Normal file
51
NewHorizons/Utility/RandomUtility.cs
Normal file
@ -0,0 +1,51 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NewHorizons.Utility
|
||||
{
|
||||
public static class RandomUtility
|
||||
{
|
||||
public static int[] GetUniqueRandomArray(int min, int max, int count)
|
||||
{
|
||||
int[] result = new int[count];
|
||||
List<int> numbersInOrder = new List<int>();
|
||||
for (var x = min; x < max; x++)
|
||||
{
|
||||
numbersInOrder.Add(x);
|
||||
}
|
||||
for (var x = 0; x < count; x++)
|
||||
{
|
||||
var randomIndex = UnityEngine.Random.Range(0, numbersInOrder.Count);
|
||||
result[x] = numbersInOrder[randomIndex];
|
||||
numbersInOrder.RemoveAt(randomIndex);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static List<Vector3> FibonacciSphere(int samples)
|
||||
{
|
||||
List<Vector3> points = new List<Vector3>();
|
||||
|
||||
var phi = Mathf.PI * (3f - Mathf.Sqrt(5f));
|
||||
|
||||
for (int i = 0; i < samples; i++)
|
||||
{
|
||||
var y = 1 - (i / (float)(samples - 1)) * 2f;
|
||||
var radius = Mathf.Sqrt(1 - y * y);
|
||||
|
||||
var theta = phi * i;
|
||||
|
||||
var x = Mathf.Cos(theta) * radius;
|
||||
var z = Mathf.Sin(theta) * radius;
|
||||
|
||||
points.Add(new Vector3(x, y, z));
|
||||
}
|
||||
return points;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3,6 +3,7 @@
|
||||
"author": "xen",
|
||||
"name": "New Horizons",
|
||||
"uniqueName": "xen.NewHorizons",
|
||||
"version": "0.4.0",
|
||||
"owmlVersion": "2.1.0"
|
||||
"version": "0.5.0",
|
||||
"owmlVersion": "2.1.0",
|
||||
"dependencies": [ "PacificEngine.OW_CommonResources" ]
|
||||
}
|
||||
|
||||
@ -453,6 +453,9 @@ Authors:
|
||||
- xen (from New Horizons v0.1.0 onwards)
|
||||
- Mister_Nebula (created original titled Marshmallow)
|
||||
|
||||
New Horizons contributors:
|
||||
- salomj (Implemented [OW_CommonResources](https://github.com/PacificEngine/OW_CommonResources) support)
|
||||
|
||||
Marshmallow was made with help from:
|
||||
- TAImatem
|
||||
- AmazingAlek
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user