diff --git a/NewHorizons/Builder/Body/StellarRemnantBuilder.cs b/NewHorizons/Builder/Body/StellarRemnantBuilder.cs index 5dd00158..8cfd7520 100644 --- a/NewHorizons/Builder/Body/StellarRemnantBuilder.cs +++ b/NewHorizons/Builder/Body/StellarRemnantBuilder.cs @@ -42,6 +42,11 @@ namespace NewHorizons.Builder.Body case StellarRemnantType.NeutronStar: MakeNeutronStar(go, sector, mod, star.Config.Star); + break; + case StellarRemnantType.Pulsar: + MakeNeutronStar(go, sector, mod, star.Config.Star); + // TODO: add jets, up rotation speed (use a RotateTransform on the star instead of changing sidereal period) + break; case StellarRemnantType.BlackHole: MakeBlackhole(go, sector, star.Config.Star); @@ -141,6 +146,8 @@ namespace NewHorizons.Builder.Body return MakeWhiteDwarf(planet, null, mod, progenitor, proxy); case StellarRemnantType.NeutronStar: return MakeNeutronStar(planet, null, mod, progenitor, proxy); + case StellarRemnantType.Pulsar: + return MakeNeutronStar(planet, null, mod, progenitor, proxy); case StellarRemnantType.BlackHole: return MakeBlackhole(planet, null, progenitor, proxy); default: diff --git a/NewHorizons/Builder/General/DetectorBuilder.cs b/NewHorizons/Builder/General/DetectorBuilder.cs index 9da557ec..4a62d5b6 100644 --- a/NewHorizons/Builder/General/DetectorBuilder.cs +++ b/NewHorizons/Builder/General/DetectorBuilder.cs @@ -143,13 +143,15 @@ namespace NewHorizons.Builder.General // It's a planet if (binaryFocalPoint.Primary != null && binaryFocalPoint.Secondary != null) { - forceDetector._detectableFields = new ForceVolume[] { parentGravityVolume }; + if (!parentGravityVolume) NHLogger.LogError($"{astroObject?.name} trying to orbit {primaryBody?.name}, which has no gravity volume!"); + forceDetector._detectableFields = parentGravityVolume ? new ForceVolume[] { parentGravityVolume } : new ForceVolume[0]; } } } else { - forceDetector._detectableFields = new ForceVolume[] { parentGravityVolume }; + if (!parentGravityVolume) NHLogger.LogError($"{astroObject?.name} trying to orbit {primaryBody?.name}, which has no gravity volume!"); + forceDetector._detectableFields = parentGravityVolume ? new ForceVolume[] { parentGravityVolume } : new ForceVolume[0]; } } @@ -164,7 +166,7 @@ namespace NewHorizons.Builder.General var primaryGV = primary.GetGravityVolume(); var secondaryGV = secondary.GetGravityVolume(); - if (primaryGV._falloffType != secondaryGV._falloffType) + if (primaryGV && secondaryGV && primaryGV._falloffType != secondaryGV._falloffType) { NHLogger.LogError($"Binaries must have the same gravity falloff! {primaryGV._falloffType} != {secondaryGV._falloffType}"); return; @@ -173,15 +175,17 @@ namespace NewHorizons.Builder.General var pointForceDetector = point.GetAttachedOWRigidbody().GetAttachedForceDetector(); // Set detectable fields - primaryCFD._detectableFields = new ForceVolume[] { secondaryGV }; + if (!secondaryGV) NHLogger.LogError($"{point.PrimaryName} trying to orbit {point.SecondaryName}, which has no gravity volume!"); + primaryCFD._detectableFields = secondaryGV ? new ForceVolume[] { secondaryGV } : new ForceVolume[0]; primaryCFD._inheritDetector = pointForceDetector; primaryCFD._activeInheritedDetector = pointForceDetector; primaryCFD._inheritElement0 = false; - secondaryCFD._detectableFields = new ForceVolume[] { primaryGV }; + if (!primaryGV) NHLogger.LogError($"{point.SecondaryName} trying to orbit {point.PrimaryName}, which has no gravity volume!"); + secondaryCFD._detectableFields = primaryGV ? new ForceVolume[] { primaryGV } : new ForceVolume[0]; secondaryCFD._inheritDetector = pointForceDetector; secondaryCFD._activeInheritedDetector = pointForceDetector; secondaryCFD._inheritElement0 = false; } } -} \ No newline at end of file +} diff --git a/NewHorizons/Builder/Props/DetailBuilder.cs b/NewHorizons/Builder/Props/DetailBuilder.cs index 5e9c80d9..66c16a95 100644 --- a/NewHorizons/Builder/Props/DetailBuilder.cs +++ b/NewHorizons/Builder/Props/DetailBuilder.cs @@ -382,8 +382,9 @@ namespace NewHorizons.Builder.Props else if (component is NomaiInterfaceOrb orb) { // detect planet gravity + // somehow Intervention has GetAttachedOWRigidbody as null sometimes, idk why var gravityVolume = planetGO.GetAttachedOWRigidbody()?.GetAttachedGravityVolume(); - orb.GetComponent()._detectableFields = gravityVolume ? new ForceVolume[] { gravityVolume } : new ForceVolume[] { }; + orb.GetComponent()._detectableFields = gravityVolume ? new ForceVolume[] { gravityVolume } : new ForceVolume[0]; } else if (component is VisionTorchItem torchItem) diff --git a/NewHorizons/Builder/Props/GeneralPropBuilder.cs b/NewHorizons/Builder/Props/GeneralPropBuilder.cs index 70c164c2..9b709bae 100644 --- a/NewHorizons/Builder/Props/GeneralPropBuilder.cs +++ b/NewHorizons/Builder/Props/GeneralPropBuilder.cs @@ -11,11 +11,11 @@ namespace NewHorizons.Builder.Props { public static GameObject MakeFromExisting(GameObject go, GameObject planetGO, Sector sector, GeneralPointPropInfo info, - MVector3 defaultPosition = null, string defaultParentPath = null, Transform parentOverride = null) + MVector3 defaultPosition = null, string defaultParentPath = null, Transform defaultParent = null) { if (info == null) return go; - go.transform.parent = parentOverride ?? sector?.transform ?? planetGO?.transform; + go.transform.parent = defaultParent ?? sector?.transform ?? planetGO?.transform; if (info is GeneralSolarSystemPropInfo solarSystemInfo && !string.IsNullOrEmpty(solarSystemInfo.parentBody)) { @@ -87,20 +87,20 @@ namespace NewHorizons.Builder.Props public static GameObject MakeNew(string defaultName, GameObject planetGO, Sector sector, GeneralPointPropInfo info, - MVector3 defaultPosition = null, string defaultParentPath = null, Transform parentOverride = null) + MVector3 defaultPosition = null, string defaultParentPath = null, Transform defaultParent = null) { var go = new GameObject(defaultName); go.SetActive(false); - return MakeFromExisting(go, planetGO, sector, info, defaultPosition, defaultParentPath, parentOverride); + return MakeFromExisting(go, planetGO, sector, info, defaultPosition, defaultParentPath, defaultParent); } public static GameObject MakeFromPrefab(GameObject prefab, string defaultName, GameObject planetGO, Sector sector, GeneralPointPropInfo info, - MVector3 defaultPosition = null, string defaultParentPath = null, Transform parentOverride = null) + MVector3 defaultPosition = null, string defaultParentPath = null, Transform defaultParent = null) { var go = prefab.InstantiateInactive(); go.name = defaultName; - return MakeFromExisting(go, planetGO, sector, info, defaultPosition, defaultParentPath, parentOverride); + return MakeFromExisting(go, planetGO, sector, info, defaultPosition, defaultParentPath, defaultParent); } } } diff --git a/NewHorizons/Builder/Props/GravityCannonBuilder.cs b/NewHorizons/Builder/Props/GravityCannonBuilder.cs index e86ccd42..44b1f075 100644 --- a/NewHorizons/Builder/Props/GravityCannonBuilder.cs +++ b/NewHorizons/Builder/Props/GravityCannonBuilder.cs @@ -137,7 +137,10 @@ namespace NewHorizons.Builder.Props orbBody._lastVelocity = velocity; orbBody._currentVelocity = velocity; - orb.GetComponent()._detectableFields = new ForceVolume[] { planetGO.GetComponentInChildren() }; + // detect planet gravity + // somehow Intervention has GetAttachedOWRigidbody as null sometimes, idk why + var gravityVolume = planetGO.GetAttachedOWRigidbody()?.GetAttachedGravityVolume(); + orb.GetComponent()._detectableFields = gravityVolume ? new ForceVolume[] { gravityVolume } : new ForceVolume[0]; Delay.RunWhenAndInNUpdates(() => { diff --git a/NewHorizons/Builder/Props/ProjectionBuilder.cs b/NewHorizons/Builder/Props/ProjectionBuilder.cs index cbc10091..c73b330e 100644 --- a/NewHorizons/Builder/Props/ProjectionBuilder.cs +++ b/NewHorizons/Builder/Props/ProjectionBuilder.cs @@ -214,7 +214,7 @@ namespace NewHorizons.Builder.Props // The number of slides is unlimited, 15 is only for texturing the actual slide reel item. This is not a slide reel item var slides = info.slides; var slidesCount = slides.Length; - var slideCollection = new SlideCollection(slidesCount); + var slideCollection = new SlideCollection(slidesCount); // TODO: uh I think that info.slides[i].playTimeDuration is not being read here... note to self for when I implement support for that: 0.7 is what to default to if playTimeDuration turns out to be 0 var imageLoader = AddAsyncLoader(g, mod, info.slides, ref slideCollection); imageLoader.imageLoadedEvent.AddListener((Texture2D tex, int index) => { slideCollection.slides[index]._image = tex; }); diff --git a/NewHorizons/Builder/Props/QuantumBuilder.cs b/NewHorizons/Builder/Props/QuantumBuilder.cs index 2848ee87..dff1d3a7 100644 --- a/NewHorizons/Builder/Props/QuantumBuilder.cs +++ b/NewHorizons/Builder/Props/QuantumBuilder.cs @@ -8,17 +8,6 @@ using System.Collections.Generic; using System.Linq; using UnityEngine; - -// BUGS THAT REQUIRE REWRITING MOBIUS CODE -// 1) FIXED! - MultiStateQuantumObjects don't check to see if the new state would be visible before choosing it -// 2) FIXED? no longer supporting shuffle - QuantumShuffleObjects don't respect rotation, they set rotation to 0 on collapse -// 3) - MultiStateQuantumObjects don't get locked by pictures - -// New features to support -// 1) multiState._prerequisiteObjects -// 2) Socket groups that have an equal number of props and sockets -// 3) Nice to have: socket groups that specify a filledSocketObject and an emptySocketObject (eg the archway in the giant's deep tower) - namespace NewHorizons.Builder.Props { public static class QuantumBuilder @@ -34,6 +23,8 @@ namespace NewHorizons.Builder.Props } } + // TODO: Socket groups that have an equal number of props and sockets + // Nice to have: socket groups that specify a filledSocketObject and an emptySocketObject (eg the archway in the giant's deep tower) public static void MakeSocketGroup(GameObject go, Sector sector, PlanetConfig config, IModBehaviour mod, QuantumGroupInfo quantumGroup, GameObject[] propsInGroup) { var groupRoot = new GameObject("Quantum Sockets - " + quantumGroup.id); @@ -46,10 +37,10 @@ namespace NewHorizons.Builder.Props { var socketInfo = quantumGroup.sockets[i]; - var socket = GeneralPropBuilder.MakeNew("Socket " + i, go, sector, socketInfo, parentOverride: groupRoot.transform); + var socket = GeneralPropBuilder.MakeNew("Socket " + i, go, sector, socketInfo, defaultParent: groupRoot.transform); sockets[i] = socket.AddComponent(); - sockets[i]._lightSources = new Light[0]; + sockets[i]._lightSources = new Light[0]; // TODO: make this customizable? socket.SetActive(true); } @@ -70,6 +61,12 @@ namespace NewHorizons.Builder.Props public static void MakeStateGroup(GameObject go, Sector sector, PlanetConfig config, IModBehaviour mod, QuantumGroupInfo quantumGroup, GameObject[] propsInGroup) { + // NOTE: States groups need special consideration that socket groups don't + // this is because the base class QuantumObject (and this is important) IGNORES PICTURES TAKEN FROM OVER 100 METERS AWAY + // why does this affect states and not sockets? Well because sockets put the QuantumObject component (QuantumSocketedObject) on the actual props themselves + // while states put the QuantumObject component (NHMultiStateQuantumObject) on the parent, which is located at the center of the planet + // this means that the distance measured by QuantumObject is not accurate, since it's not measuring from the active prop, but from the center of the planet + var groupRoot = new GameObject("Quantum States - " + quantumGroup.id); groupRoot.transform.parent = sector?.transform ?? go.transform; groupRoot.transform.localPosition = Vector3.zero; @@ -110,8 +107,10 @@ namespace NewHorizons.Builder.Props multiState._loop = quantumGroup.loop; multiState._sequential = quantumGroup.sequential; multiState._states = states.ToArray(); - multiState._prerequisiteObjects = new MultiStateQuantumObject[0]; // TODO: support this + multiState._prerequisiteObjects = new MultiStateQuantumObject[0]; // TODO: _prerequisiteObjects multiState._initialState = 0; + // snapshot events arent listened to outside of the sector, so fortunately this isnt really infinite + multiState._maxSnapshotLockRange = Mathf.Infinity; // TODO: maybe expose this at some point if it breaks a puzzle or something groupRoot.SetActive(true); } @@ -126,7 +125,7 @@ namespace NewHorizons.Builder.Props var shuffle = shuffleParent.AddComponent(); shuffle._shuffledObjects = propsInGroup.Select(p => p.transform).ToArray(); - shuffle.Awake(); // this doesn't get called on its own for some reason + shuffle.Awake(); // this doesn't get called on its own for some reason. what? how? AddBoundsVisibility(shuffleParent); shuffleParent.SetActive(true); @@ -165,6 +164,7 @@ namespace NewHorizons.Builder.Props } } + // BUG: ignores skinned guys. this coincidentally makes it work without BoxShapeFixer public static Bounds GetBoundsOfSelfAndChildMeshes(GameObject g) { var meshFilters = g.GetComponentsInChildren(); @@ -200,6 +200,13 @@ namespace NewHorizons.Builder.Props } } + /// + /// for some reason mesh bounds are wrong unless we wait a bit + /// so this script contiously checks everything until it is correct + /// + /// this actually only seems to be a problem with skinned renderers. normal ones work fine + /// TODO: at some point narrow this down to just skinned, instead of doing everything and checking every frame + /// public class BoxShapeFixer : MonoBehaviour { public BoxShape shape; diff --git a/NewHorizons/Components/Quantum/NHMultiStateQuantumObject.cs b/NewHorizons/Components/Quantum/NHMultiStateQuantumObject.cs index 17279ec5..7f11f8d7 100644 --- a/NewHorizons/Components/Quantum/NHMultiStateQuantumObject.cs +++ b/NewHorizons/Components/Quantum/NHMultiStateQuantumObject.cs @@ -4,9 +4,12 @@ using UnityEngine; namespace NewHorizons.Components.Quantum { + /// + /// exists because MultiStateQuantumObject only checks visibility on the current state, + /// whereas this one also checks on each new state, in case they are bigger + /// public class NHMultiStateQuantumObject : MultiStateQuantumObject { - public override bool ChangeQuantumState(bool skipInstantVisibilityCheck) { for (int i = 0; i < _prerequisiteObjects.Length; i++) @@ -43,15 +46,9 @@ namespace NewHorizons.Components.Quantum else { - // TODO: perform this roll for number of states, each time adding the selected state to the end of a list and removing it from the source list - // this gets us a randomly ordered list that respects states' probability - // then we can sequentially attempt collapsing to them, checking at each state whether the new state is invalid due to the player being able to see it, according to this: - // - // if (!((!IsPlayerEntangled()) ? (CheckIllumination() ? CheckVisibilityInstantly() : CheckPointInside(Locator.GetPlayerCamera().transform.position)) : CheckIllumination())) - // { - // return true; // this is a valid state - // } - // + // Iterate over list of possible states to find a valid state to collapse to + // current state is excluded, and states are randomly ordered using a weighted random roll to prioritize states with higher probability + // NOTE: they aren't actually pre-sorted into this random order, this random ordering is done on the fly using RollState List indices = new List(); for (var i = 0; i < _states.Length; i++) if (i != stateIndex) indices.Add(i); @@ -94,17 +91,15 @@ namespace NewHorizons.Components.Quantum { var isPlayerEntangled = IsPlayerEntangled(); var illumination = CheckIllumination(); + // faster than full CheckVisibility var visibility = CheckVisibilityInstantly(); var playerInside = CheckPointInside(Locator.GetPlayerCamera().transform.position); + // does not check probe, but thats okay - var isVisible = - isPlayerEntangled - ? illumination - : - illumination - ? visibility - : playerInside - ; + var notEntangledCheck = illumination ? visibility : playerInside; + var isVisible = isPlayerEntangled ? illumination : notEntangledCheck; + // I think this is what the above two lines simplify to but I don't want to test this: + // illumination ? visibility || isPlayerEntangled : playerInside return !isVisible; } diff --git a/NewHorizons/External/Modules/VariableSize/StarModule.cs b/NewHorizons/External/Modules/VariableSize/StarModule.cs index 21875dd8..3b833051 100644 --- a/NewHorizons/External/Modules/VariableSize/StarModule.cs +++ b/NewHorizons/External/Modules/VariableSize/StarModule.cs @@ -154,6 +154,7 @@ namespace NewHorizons.External.Modules.VariableSize [EnumMember(Value = @"default")] Default, [EnumMember(Value = @"whiteDwarf")] WhiteDwarf, [EnumMember(Value = @"neutronStar")] NeutronStar, + [EnumMember(Value = @"pulsar")] Pulsar, [EnumMember(Value = @"blackHole")] BlackHole, [EnumMember(Value = @"custom")] Custom } diff --git a/NewHorizons/Handlers/VesselWarpHandler.cs b/NewHorizons/Handlers/VesselWarpHandler.cs index 07277776..12859c3a 100644 --- a/NewHorizons/Handlers/VesselWarpHandler.cs +++ b/NewHorizons/Handlers/VesselWarpHandler.cs @@ -169,7 +169,7 @@ namespace NewHorizons.Handlers var attachWarpExitToVessel = system.Config.Vessel?.warpExit?.attachToVessel ?? false; var warpExitParent = vesselWarpController._targetWarpPlatform.transform.parent; - var warpExit = GeneralPropBuilder.MakeFromExisting(vesselWarpController._targetWarpPlatform.gameObject, planetGO, null, system.Config.Vessel?.warpExit, parentOverride: attachWarpExitToVessel ? warpExitParent : null); + var warpExit = GeneralPropBuilder.MakeFromExisting(vesselWarpController._targetWarpPlatform.gameObject, planetGO, null, system.Config.Vessel?.warpExit, defaultParent: attachWarpExitToVessel ? warpExitParent : null); if (attachWarpExitToVessel) { warpExit.transform.parent = warpExitParent; diff --git a/NewHorizons/NewHorizons.csproj b/NewHorizons/NewHorizons.csproj index 8b620bac..97051df9 100644 --- a/NewHorizons/NewHorizons.csproj +++ b/NewHorizons/NewHorizons.csproj @@ -15,9 +15,8 @@ none - - + diff --git a/NewHorizons/Patches/PlayerPatches/PlayerHazardDetectorPatches.cs b/NewHorizons/Patches/DetectorPatches/PlayerHazardDetectorPatches.cs similarity index 93% rename from NewHorizons/Patches/PlayerPatches/PlayerHazardDetectorPatches.cs rename to NewHorizons/Patches/DetectorPatches/PlayerHazardDetectorPatches.cs index 032f8f9b..0584023d 100644 --- a/NewHorizons/Patches/PlayerPatches/PlayerHazardDetectorPatches.cs +++ b/NewHorizons/Patches/DetectorPatches/PlayerHazardDetectorPatches.cs @@ -1,7 +1,7 @@ using HarmonyLib; using NewHorizons.Utility.OWML; -namespace NewHorizons.Patches.PlayerPatches +namespace NewHorizons.Patches.DetectorPatches { [HarmonyPatch(typeof(HazardDetector))] public static class PlayerHazardDetectorPatches diff --git a/NewHorizons/Schemas/body_schema.json b/NewHorizons/Schemas/body_schema.json index 1cb51aec..a63e8eb5 100644 --- a/NewHorizons/Schemas/body_schema.json +++ b/NewHorizons/Schemas/body_schema.json @@ -2047,13 +2047,11 @@ "description": "", "x-enumNames": [ "Sockets", - "States", - "FailedValidation" + "States" ], "enum": [ "sockets", - "states", - "FailedValidation" + "states" ] }, "QuantumSocketInfo": { @@ -3509,6 +3507,7 @@ "Default", "WhiteDwarf", "NeutronStar", + "Pulsar", "BlackHole", "Custom" ], @@ -3516,6 +3515,7 @@ "default", "whiteDwarf", "neutronStar", + "pulsar", "blackHole", "custom" ] diff --git a/NewHorizons/manifest.json b/NewHorizons/manifest.json index 0c3366f1..42fe40e5 100644 --- a/NewHorizons/manifest.json +++ b/NewHorizons/manifest.json @@ -4,8 +4,8 @@ "author": "xen, Bwc9876, clay, MegaPiggy, John, Trifid, Hawkbar, Book", "name": "New Horizons", "uniqueName": "xen.NewHorizons", - "version": "1.16.3", - "owmlVersion": "2.9.3", + "version": "1.16.4", + "owmlVersion": "2.9.7", "dependencies": [ "JohnCorby.VanillaFix", "_nebula.MenuFramework", "xen.CommonCameraUtility", "dgarro.CustomShipLogModes" ], "conflicts": [ "Raicuparta.QuantumSpaceBuddies", "PacificEngine.OW_CommonResources" ], "pathsToPreserve": [ "planets", "systems", "translations" ] diff --git a/SchemaExporter/SchemaExporter.cs b/SchemaExporter/SchemaExporter.cs index 557679ac..6aa43dcd 100644 --- a/SchemaExporter/SchemaExporter.cs +++ b/SchemaExporter/SchemaExporter.cs @@ -86,6 +86,8 @@ public static class SchemaExporter schema.Definitions["NomaiTextType"].EnumerationNames.Remove("Cairn"); schema.Definitions["NomaiTextType"].Enumeration.Remove("cairnVariant"); schema.Definitions["NomaiTextType"].EnumerationNames.Remove("CairnVariant"); + schema.Definitions["QuantumGroupType"].Enumeration.Remove("FailedValidation"); + schema.Definitions["QuantumGroupType"].EnumerationNames.Remove("FailedValidation"); break; case "Star System Schema": schema.Definitions["NomaiCoordinates"].Properties["x"].UniqueItems = true;