using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using UnityEngine; using UnityEngine.UI; using crecheng.DSPModSave; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: InternalsVisibleTo("DSPMultiStarSystems.PatchVerifier")] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("DSPMultiStarSystems")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.3.4.0")] [assembly: AssemblyInformationalVersion("1.3.4")] [assembly: AssemblyProduct("DSPMultiStarSystems")] [assembly: AssemblyTitle("DSPMultiStarSystems")] [assembly: AssemblyVersion("1.3.4.0")] namespace DSPMultiStarSystems; internal static class CompanionLightController { private const double UniverseUnitsPerAu = 40000.0; private const float MaximumTwilightIntensity = 0.35f; private static Light companionLight; internal static void Refresh(SunLightHandler sunLightHandler) { //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_01e4: Unknown result type (might be due to invalid IL or missing references) //IL_01e9: Unknown result type (might be due to invalid IL or missing references) //IL_01ee: Unknown result type (might be due to invalid IL or missing references) //IL_01f1: Unknown result type (might be due to invalid IL or missing references) //IL_01f6: Unknown result type (might be due to invalid IL or missing references) //IL_01fb: Unknown result type (might be due to invalid IL or missing references) //IL_01fd: Unknown result type (might be due to invalid IL or missing references) //IL_0202: Unknown result type (might be due to invalid IL or missing references) //IL_020e: Unknown result type (might be due to invalid IL or missing references) //IL_0210: Unknown result type (might be due to invalid IL or missing references) //IL_0215: Unknown result type (might be due to invalid IL or missing references) //IL_021a: Unknown result type (might be due to invalid IL or missing references) //IL_0229: Unknown result type (might be due to invalid IL or missing references) //IL_022d: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) PlanetData localPlanet = GameMain.localPlanet; if (localPlanet == null || localPlanet.star == null || !MultiStarRuntimeRegistry.TryGetSystem(localPlanet.star, out var system) || system.RealStarId != localPlanet.star.id) { SetEnabled(enabled: false); return; } VectorLF3 val = VectorLF3.zero; double num = 0.0; Color val2 = Color.black; for (int i = 0; i < system.StarCount; i++) { if (i == system.RealMemberIndex) { continue; } StarData val3 = localPlanet.galaxy.StarById(system.FirstStarId + i); if (val3 != null && !(val3.luminosity <= 0f) && system.StellarKinds[i] != StellarKind.BlackHole) { VectorLF3 val4 = val3.uPosition - localPlanet.uPosition; double num2 = Math.Max(0.1, ((VectorLF3)(ref val4)).magnitude / 40000.0); double num3 = (double)val3.luminosity / (num2 * num2); if (!(num3 <= 0.0)) { val += val4 * (num3 / Math.Max(0.0001, ((VectorLF3)(ref val4)).magnitude)); val2 += GetStellarColor(system.StellarKinds[i]) * (float)num3; num += num3; } } } if (num <= 1E-06 || ((VectorLF3)(ref val)).magnitude <= 1E-06) { SetEnabled(enabled: false); return; } Light val5 = (((Object)(object)sunLightHandler != (Object)null) ? ((Component)sunLightHandler).GetComponent() : null); EnsureLight(val5); double num4 = Math.Max(0.1, localPlanet.sunDistance); double num5 = Math.Max(0.0001, localPlanet.star.luminosity) / (num4 * num4); float num6 = Mathf.Clamp((float)(num / num5), 0.02f, 0.35f); Vector3 val6 = VectorLF3.op_Implicit(((VectorLF3)(ref val)).normalized); Vector3 val7 = Quaternion.Inverse(localPlanet.runtimeRotation) * val6; ((Component)companionLight).transform.rotation = Quaternion.LookRotation(-val7, Vector3.up); companionLight.color = val2 / (float)num; companionLight.intensity = Math.Max(0.01f, (val5 != null) ? val5.intensity : 1f) * num6; ((Behaviour)companionLight).enabled = true; } internal static void Dispose() { if ((Object)(object)companionLight != (Object)null) { Object.Destroy((Object)(object)((Component)companionLight).gameObject); companionLight = null; } } private static void EnsureLight(Light source) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Expected O, but got Unknown if (!((Object)(object)companionLight != (Object)null)) { GameObject val = new GameObject("DSPMultiStarCompanionLight") { hideFlags = (HideFlags)52 }; if ((Object)(object)source != (Object)null) { val.layer = ((Component)source).gameObject.layer; } companionLight = val.AddComponent(); companionLight.type = (LightType)1; companionLight.shadows = (LightShadows)0; companionLight.renderMode = (LightRenderMode)2; companionLight.cullingMask = ((source != null) ? source.cullingMask : (-1)); } } private static void SetEnabled(bool enabled) { if ((Object)(object)companionLight != (Object)null) { ((Behaviour)companionLight).enabled = enabled; } } private static Color GetStellarColor(StellarKind kind) { //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) switch (kind) { case StellarKind.MainM: case StellarKind.GiantRed: return new Color(1f, 0.42f, 0.28f); case StellarKind.MainK: case StellarKind.GiantYellow: return new Color(1f, 0.72f, 0.38f); case StellarKind.MainG: return new Color(1f, 0.94f, 0.74f); case StellarKind.MainF: case StellarKind.GiantWhite: return new Color(1f, 0.98f, 0.9f); case StellarKind.MainA: case StellarKind.MainB: case StellarKind.MainO: case StellarKind.GiantBlue: case StellarKind.WhiteDwarf: case StellarKind.NeutronStar: return new Color(0.58f, 0.76f, 1f); default: return Color.black; } } } [HarmonyPatch(typeof(SunLightHandler), "LateUpdate")] internal static class CompanionLightingPatch { [HarmonyPostfix] private static void Postfix(SunLightHandler __instance) { CompanionLightController.Refresh(__instance); } } [HarmonyPatch(typeof(SpaceSector), "TryCreateNewHive", new Type[] { typeof(StarData) })] internal static class VirtualStarHiveCreationPatch { [HarmonyPrefix] [HarmonyPriority(800)] private static bool Prefix(StarData __0, ref EnemyDFHiveSystem __result) { if (!MultiStarRuntimeRegistry.IsVirtualStar(__0)) { return true; } __result = null; return false; } } internal sealed class DeterministicRandom { private ulong state; internal DeterministicRandom(int seed) { state = (ulong)((uint)seed + -7046029254386353131L); NextUInt64(); } internal ulong NextUInt64() { ulong num = state; num ^= num >> 12; num ^= num << 25; return (state = num ^ (num >> 27)) * 2685821657736338717L; } internal double NextDouble() { return (double)(NextUInt64() >> 11) * 1.1102230246251565E-16; } internal int NextInt(int maximumExclusive) { if (maximumExclusive <= 0) { throw new ArgumentOutOfRangeException("maximumExclusive"); } return (int)(NextDouble() * (double)maximumExclusive); } internal bool Chance(double probability) { return NextDouble() < probability; } internal double Range(double minimum, double maximum) { return minimum + (maximum - minimum) * NextDouble(); } } internal static class DysonLuminosityCalculator { internal static float Combine(float realLuminosity, float companionLuminosity) { return (float)(Math.Round(Math.Pow(Math.Max(1E-06, (double)realLuminosity + (double)companionLuminosity), 0.33000001311302185) * 1000.0) / 1000.0); } } [HarmonyPatch(typeof(GameData), "ArriveStar", new Type[] { typeof(StarData) })] internal static class ArriveStarPatch { [HarmonyPrefix] [HarmonyPriority(800)] private static void Prefix(ref StarData __0) { __0 = MultiStarRuntimeRegistry.ResolveTravelStar(__0); MultiStarRuntimeRegistry.SynchronizeForImmediateTravel(__0?.galaxy); } } [HarmonyPatch(typeof(GameData), "ArrivePlanet", new Type[] { typeof(PlanetData) })] internal static class ArrivePlanetPatch { [HarmonyPrefix] [HarmonyPriority(800)] private static void Prefix(PlanetData __0) { MultiStarRuntimeRegistry.SynchronizeForImmediateTravel(__0?.galaxy); } } [HarmonyPatch(typeof(UIStarmap), "SetViewStar", new Type[] { typeof(StarData), typeof(bool) })] internal static class StarmapViewStarPatch { [HarmonyPrefix] [HarmonyPriority(800)] private static void Prefix(ref StarData __0) { __0 = MultiStarRuntimeRegistry.ResolveTravelStar(__0); } } [HarmonyPatch(typeof(UIStarmap), "OnStarClickInRouteSelectMode", new Type[] { typeof(StarData) })] internal static class StarmapRouteStarPatch { [HarmonyPrefix] [HarmonyPriority(800)] private static void Prefix(ref StarData __0) { __0 = MultiStarRuntimeRegistry.ResolveTravelStar(__0); } } [HarmonyPatch(typeof(DESelection), "SetViewStar", new Type[] { typeof(StarData) })] internal static class DysonSelectionStarPatch { [HarmonyPrefix] [HarmonyPriority(800)] private static void Prefix(ref StarData __0) { __0 = MultiStarRuntimeRegistry.ResolveDysonStar(__0); } } [HarmonyPatch(typeof(GameData), "CreateDysonSphere", new Type[] { typeof(int) })] internal static class CreateDysonSpherePatch { [HarmonyPrefix] [HarmonyPriority(800)] private static void Prefix(GameData __instance, ref int starIndex) { if (__instance?.galaxy != null && starIndex >= 0 && starIndex < __instance.galaxy.starCount) { StarData val = MultiStarRuntimeRegistry.ResolveDysonStar(__instance.galaxy.stars[starIndex]); if (val != null) { starIndex = val.index; } } } } [HarmonyPatch(typeof(StarData), "get_dysonLumino")] internal static class CombinedBinaryLuminosityPatch { [HarmonyPostfix] private static void Postfix(StarData __instance, ref float __result) { if (__instance == null || !MultiStarRuntimeRegistry.TryGetSystem(__instance, out var system) || system.RealStarId != __instance.id) { return; } int dysonCompanionStarId = system.GetDysonCompanionStarId(); if (dysonCompanionStarId > 0) { StarData val = __instance.galaxy.StarById(dysonCompanionStarId); if (val != null) { __result = DysonLuminosityCalculator.Combine(__instance.luminosity, val.luminosity); } } } } internal enum SystemTopology : byte { Binary = 2, Triangle, BinaryWithMassiveOuter, Square, DoubleBinary, TripleWithMassiveOuter, Pentagon, Hexagon } internal enum InnerTripleTopology : byte { None, Triangle, BinaryWithMassiveOuter } internal enum MultiStarSpacingProfile : byte { Legacy = 1, Expanded } internal enum StellarKind : byte { MainM, MainK, MainG, MainF, MainA, MainB, MainO, GiantRed, GiantYellow, GiantWhite, GiantBlue, WhiteDwarf, NeutronStar, BlackHole } internal sealed class MultiStarSystemPlan { internal int FirstStarId; internal int StarCount; internal int RealMemberIndex; internal SystemTopology Topology; internal InnerTripleTopology InnerTopology; internal StellarKind[] StellarKinds; internal int DysonCompanionMemberIndex = -1; internal bool AllowOuterPlanetOwners = true; internal double RealSystemDiameterFactor; internal double VirtualSubsystemFactor; internal double SecondaryVirtualSubsystemFactor; internal double Phase; internal double InnerPhase; internal double OuterPhase; internal double Longitude; internal double Inclination; internal int RealStarId => FirstStarId + RealMemberIndex; internal bool ContainsStar(int starId) { if (starId >= FirstStarId) { return starId < FirstStarId + StarCount; } return false; } internal int GetMemberIndex(int starId) { if (!ContainsStar(starId)) { return -1; } return starId - FirstStarId; } internal int GetDysonCompanionStarId() { if (DysonCompanionMemberIndex >= 0) { return FirstStarId + DysonCompanionMemberIndex; } return 0; } internal int GetOuterPlanetOwnerMemberIndex() { if (!AllowOuterPlanetOwners) { return -1; } switch (Topology) { case SystemTopology.BinaryWithMassiveOuter: return 2; case SystemTopology.TripleWithMassiveOuter: return 3; case SystemTopology.DoubleBinary: if (RealMemberIndex >= 2) { return 0; } return 2; default: return -1; } } internal bool IsPlanetOwnerMember(int memberIndex) { if (memberIndex != RealMemberIndex) { return memberIndex == GetOuterPlanetOwnerMemberIndex(); } return true; } internal bool IsPlanetOwnerStarId(int starId) { int memberIndex = GetMemberIndex(starId); if (memberIndex >= 0) { return IsPlanetOwnerMember(memberIndex); } return false; } internal bool HasSpecialStar() { for (int i = 0; i < StellarKinds.Length; i++) { if (GenerationPlanner.IsSpecial(StellarKinds[i])) { return true; } } return false; } internal void Write(BinaryWriter writer) { writer.Write(FirstStarId); writer.Write(StarCount); writer.Write(RealMemberIndex); writer.Write((byte)Topology); writer.Write((byte)InnerTopology); writer.Write(DysonCompanionMemberIndex); writer.Write(RealSystemDiameterFactor); writer.Write(VirtualSubsystemFactor); writer.Write(SecondaryVirtualSubsystemFactor); writer.Write(Phase); writer.Write(InnerPhase); writer.Write(OuterPhase); writer.Write(Longitude); writer.Write(Inclination); writer.Write(StellarKinds.Length); for (int i = 0; i < StellarKinds.Length; i++) { writer.Write((byte)StellarKinds[i]); } } internal static MultiStarSystemPlan Read(BinaryReader reader) { MultiStarSystemPlan multiStarSystemPlan = new MultiStarSystemPlan { FirstStarId = reader.ReadInt32(), StarCount = reader.ReadInt32(), RealMemberIndex = reader.ReadInt32(), Topology = (SystemTopology)reader.ReadByte(), InnerTopology = (InnerTripleTopology)reader.ReadByte(), DysonCompanionMemberIndex = reader.ReadInt32(), RealSystemDiameterFactor = reader.ReadDouble(), VirtualSubsystemFactor = reader.ReadDouble(), SecondaryVirtualSubsystemFactor = reader.ReadDouble(), Phase = reader.ReadDouble(), InnerPhase = reader.ReadDouble(), OuterPhase = reader.ReadDouble(), Longitude = reader.ReadDouble(), Inclination = reader.ReadDouble() }; int num = reader.ReadInt32(); if (num != multiStarSystemPlan.StarCount || num < 2 || num > 6) { throw new InvalidDataException("Invalid multi-star member count."); } multiStarSystemPlan.StellarKinds = new StellarKind[num]; for (int i = 0; i < num; i++) { multiStarSystemPlan.StellarKinds[i] = (StellarKind)reader.ReadByte(); } return multiStarSystemPlan; } } internal sealed class MultiStarGenerationPlan { internal const ushort SaveVersion = 3; private readonly Dictionary byStarId = new Dictionary(); internal int GalaxySeed; internal int PhysicalStarCount; internal MultiStarSpacingProfile SpacingProfile = MultiStarSpacingProfile.Expanded; internal bool AllowOuterPlanetOwners = true; internal List Systems = new List(); internal void BuildIndex() { byStarId.Clear(); for (int i = 0; i < Systems.Count; i++) { MultiStarSystemPlan multiStarSystemPlan = Systems[i]; for (int j = 0; j < multiStarSystemPlan.StarCount; j++) { int key = multiStarSystemPlan.FirstStarId + j; if (byStarId.ContainsKey(key)) { throw new InvalidDataException("A star belongs to multiple multi-star systems."); } byStarId.Add(key, multiStarSystemPlan); } } } internal bool TryGetSystem(int starId, out MultiStarSystemPlan system) { return byStarId.TryGetValue(starId, out system); } internal bool IsVirtualStar(int starId) { if (byStarId.TryGetValue(starId, out var value)) { return value.RealStarId != starId; } return false; } internal void Write(BinaryWriter writer) { writer.Write((ushort)3); writer.Write((byte)SpacingProfile); writer.Write(AllowOuterPlanetOwners); writer.Write(GalaxySeed); writer.Write(PhysicalStarCount); writer.Write(Systems.Count); for (int i = 0; i < Systems.Count; i++) { Systems[i].Write(writer); } } internal static MultiStarGenerationPlan Read(BinaryReader reader) { ushort num = reader.ReadUInt16(); if (num < 1 || num > 3) { throw new InvalidDataException("Unsupported multi-star save version " + num + "."); } MultiStarGenerationPlan multiStarGenerationPlan = new MultiStarGenerationPlan { SpacingProfile = (MultiStarSpacingProfile)((num == 1) ? 1 : reader.ReadByte()), AllowOuterPlanetOwners = (num >= 3 && reader.ReadBoolean()), GalaxySeed = reader.ReadInt32(), PhysicalStarCount = reader.ReadInt32() }; int num2 = reader.ReadInt32(); if (num2 < 0 || num2 > multiStarGenerationPlan.PhysicalStarCount / 2 + 1) { throw new InvalidDataException("Invalid multi-star system count."); } for (int i = 0; i < num2; i++) { MultiStarSystemPlan multiStarSystemPlan = MultiStarSystemPlan.Read(reader); multiStarSystemPlan.AllowOuterPlanetOwners = multiStarGenerationPlan.AllowOuterPlanetOwners; multiStarGenerationPlan.Systems.Add(multiStarSystemPlan); } multiStarGenerationPlan.BuildIndex(); GenerationPlanner.Validate(multiStarGenerationPlan); return multiStarGenerationPlan; } } [HarmonyPatch(typeof(GameData), "Import", new Type[] { typeof(BinaryReader) })] internal static class GameImportPatch { [HarmonyPrefix] [HarmonyPriority(800)] private static void Prefix() { GenerationSession.BeginImport(); } [HarmonyFinalizer] [HarmonyPriority(0)] private static Exception Finalizer(Exception __exception) { GenerationSession.EndImport(); return __exception; } } [HarmonyPatch(typeof(UniverseGen), "CreateGalaxy", new Type[] { typeof(GameDesc) })] internal static class GalaxyGenerationPatch { [HarmonyPrefix] [HarmonyPriority(0)] [HarmonyAfter(new string[] { "Zincon.CustomCreateBirthStarLite", "Zincon.DSPAddPlanetMoon2Patch", "IndexOutOfRange.DSPAddPlanet", "Zincon.DSPNestedMoons" })] private static void Prefix(GameDesc gameDesc) { GenerationSession.BeginGalaxy(gameDesc); } [HarmonyPostfix] [HarmonyPriority(0)] [HarmonyAfter(new string[] { "Zincon.CustomCreateBirthStarLite", "Zincon.DSPAddPlanetMoon2Patch", "IndexOutOfRange.DSPAddPlanet", "Zincon.DSPNestedMoons" })] [HarmonyBefore(new string[] { "Zincon.DSPWanderingPlanets" })] private static void Postfix(GalaxyData __result) { MultiStarGenerationPlan activePlan = GenerationSession.ActivePlan; if (__result == null || activePlan == null) { return; } if (__result.starCount != activePlan.PhysicalStarCount) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogError((object)("Multi-star galaxy generation produced " + __result.starCount + " stars, but the saved plan requires " + activePlan.PhysicalStarCount + ". Skipping runtime registration to protect this save from a mismatched topology.")); } } else { MultiStarRuntimeRegistry.RegisterGalaxy(__result, activePlan); } } [HarmonyFinalizer] [HarmonyPriority(0)] private static Exception Finalizer(Exception __exception) { GenerationSession.EndGalaxy(); return __exception; } } [HarmonyPatch(typeof(StarGen), "CreateStar", new Type[] { typeof(GalaxyData), typeof(VectorLF3), typeof(GameDesc), typeof(int), typeof(int), typeof(EStarType), typeof(ESpectrType) })] internal static class StarCreationPatch { [HarmonyPrefix] [HarmonyPriority(0)] [HarmonyAfter(new string[] { "Zincon.CustomCreateBirthStarLite" })] private static void Prefix(int id, ref EStarType needtype, ref ESpectrType needSpectr) { if (GenerationSession.TryGetSystem(id, out var system)) { StellarKindMapper.Apply(system.StellarKinds[system.GetMemberIndex(id)], ref needtype, ref needSpectr); } } [HarmonyPostfix] [HarmonyPriority(0)] [HarmonyAfter(new string[] { "Zincon.CustomCreateBirthStarLite" })] private static void Postfix(StarData __result, int id) { if (__result != null && GenerationSession.TryGetSystem(id, out var system) && system.RealStarId != id) { SuppressVirtualStarGameplay(__result); } } internal static void SuppressVirtualStarGameplay(StarData star) { star.initialHiveCount = 0; star.maxHiveCount = 0; star.hivePatternLevel = 0; star.hiveAstroOrbits = (AstroOrbitData[])(object)new AstroOrbitData[0]; star.asterBelt1OrbitIndex = 0f; star.asterBelt2OrbitIndex = 0f; star.asterBelt1Radius = 0f; star.asterBelt2Radius = 0f; } } [HarmonyPatch(typeof(StarGen), "CreateStarPlanets", new Type[] { typeof(GalaxyData), typeof(StarData), typeof(GameDesc) })] internal static class VirtualStarPlanetGenerationPatch { [HarmonyPrefix] [HarmonyPriority(800)] private static bool Prefix(StarData star) { if (star == null || !IsNonPlanetOwningVirtualDuringGeneration(star.id)) { return true; } ClearVirtualStar(star.galaxy, star); return false; } [HarmonyPostfix] [HarmonyPriority(0)] [HarmonyAfter(new string[] { "Zincon.CustomCreateBirthStarLite", "Zincon.DSPAddPlanetMoon2Patch", "IndexOutOfRange.DSPAddPlanet", "Zincon.DSPNestedMoons" })] private static void Postfix(GalaxyData galaxy, StarData star) { if (star != null) { if (IsNonPlanetOwningVirtualDuringGeneration(star.id)) { ClearVirtualStar(galaxy, star); } else if (IsExpandedRealStarDuringGeneration(star.id)) { ReserveInnerPrimaryOrbits(star); } } } private static bool IsNonPlanetOwningVirtualDuringGeneration(int starId) { if (GenerationSession.TryGetSystem(starId, out var system)) { return !system.IsPlanetOwnerStarId(starId); } return false; } private static bool IsExpandedRealStarDuringGeneration(int starId) { MultiStarGenerationPlan activePlan = GenerationSession.ActivePlan; if (activePlan != null && activePlan.SpacingProfile == MultiStarSpacingProfile.Expanded && GenerationSession.TryGetSystem(starId, out var system)) { return system.RealStarId == starId; } return false; } private static void ReserveInnerPrimaryOrbits(StarData star) { if (star.planets == null) { return; } List list = new List(); for (int i = 0; i < star.planets.Length; i++) { PlanetData val = star.planets[i]; if (val != null && val.orbitAroundPlanet == null) { list.Add(val); } } for (int j = 0; j < list.Count; j++) { PlanetData val2 = list[j]; int num = Math.Max(1, val2.orbitIndex); val2.orbitIndex = num + 5; val2.orbitRadius = GetPrimaryOrbitRadius(star, val2.orbitIndex); val2.sunDistance = val2.orbitRadius; val2.orbitalPeriod = CalculateStarOrbitalPeriod(star, val2.orbitRadius); } for (int k = 0; k < star.planets.Length; k++) { PlanetData val3 = star.planets[k]; PlanetData val4 = FindRootPlanet(val3); if (val4 != null) { val3.sunDistance = val4.orbitRadius; val3.luminosity = CalculatePlanetLuminosity(star, val3.sunDistance); } } } private static PlanetData FindRootPlanet(PlanetData planet) { PlanetData val = planet; int num = 0; while (val != null && num < 64) { if (val.orbitAroundPlanet == null) { return val; } val = val.orbitAroundPlanet; num++; } return null; } private static float GetPrimaryOrbitRadius(StarData star, int orbitIndex) { int num = Math.Max(1, orbitIndex); float[] orbitRadius = StarGen.orbitRadius; float num2; if (num < orbitRadius.Length) { num2 = orbitRadius[num]; } else { int num3 = orbitRadius.Length - 1; float num4 = orbitRadius[num3] - orbitRadius[num3 - 1]; num2 = orbitRadius[num3] + num4 * (float)(num - num3); } return num2 * Math.Max(0.01f, star.orbitScaler); } private static double CalculateStarOrbitalPeriod(StarData star, float radius) { return Math.Sqrt(39.47841760435743 * Math.Pow(radius, 3.0) / (1.3538551990520382E-06 * Math.Max(0.01, star.mass))); } private static float CalculatePlanetLuminosity(StarData star, float sunDistance) { double num = Math.Pow(Math.Max(0.0001, star.lightBalanceRadius) / Math.Max(0.01, sunDistance + 0.01f), 0.6); for (int i = 0; i < 3; i++) { if (!(num > 1.0)) { break; } num = Math.Log(num) + 1.0; } return (float)(Math.Round(num * 100.0) / 100.0); } private static void ClearVirtualStar(GalaxyData galaxy, StarData star) { star.planetCount = 0; star.planets = (PlanetData[])(object)new PlanetData[0]; StarCreationPatch.SuppressVirtualStarGameplay(star); if (galaxy?.astrosData == null) { return; } int num = Math.Min(galaxy.astrosData.Length, star.astroId + 100); for (int i = star.astroId + 1; i < num; i++) { ((AstroData)(ref galaxy.astrosData[i])).SetEmpty(); if (galaxy.astrosFactory != null && i < galaxy.astrosFactory.Length) { galaxy.astrosFactory[i] = null; } } } } internal static class GenerationPlanner { private const double MultiSystemChance = 0.25; private static readonly StellarKind[] OrdinaryKinds = new StellarKind[10] { StellarKind.MainM, StellarKind.MainK, StellarKind.MainG, StellarKind.MainF, StellarKind.MainA, StellarKind.MainB, StellarKind.GiantRed, StellarKind.GiantYellow, StellarKind.GiantWhite, StellarKind.WhiteDwarf }; private static readonly StellarKind[] SpecialKinds = new StellarKind[4] { StellarKind.MainO, StellarKind.GiantBlue, StellarKind.NeutronStar, StellarKind.BlackHole }; internal static MultiStarGenerationPlan Create(int galaxySeed, int starCount) { if (starCount < 2) { throw new ArgumentOutOfRangeException("starCount"); } DeterministicRandom deterministicRandom = new DeterministicRandom(galaxySeed ^ (starCount * 7919) ^ 0x4D535953); MultiStarGenerationPlan multiStarGenerationPlan = new MultiStarGenerationPlan { GalaxySeed = galaxySeed, PhysicalStarCount = starCount, SpacingProfile = MultiStarSpacingProfile.Expanded }; int num = 1; while (num <= starCount) { int num2 = starCount - num + 1; if (num2 >= 2 && deterministicRandom.Chance(0.25)) { int num3 = ChooseMemberCount(deterministicRandom, num2); multiStarGenerationPlan.Systems.Add(CreateSystem(deterministicRandom, num, num3)); num += num3; } else { num++; } } if (multiStarGenerationPlan.Systems.Count == 0) { multiStarGenerationPlan.Systems.Add(CreateSystem(deterministicRandom, 1, 2)); } EnsureSpecialStar(multiStarGenerationPlan.Systems, deterministicRandom); EnsureOStar(multiStarGenerationPlan.Systems, deterministicRandom); EnsureVisibleMassiveVirtualCompanion(multiStarGenerationPlan.Systems); multiStarGenerationPlan.BuildIndex(); Validate(multiStarGenerationPlan); return multiStarGenerationPlan; } internal static MultiStarGenerationPlan CreateForGameplayStarCount(int galaxySeed, int gameplayStarCount) { if (gameplayStarCount < 2) { throw new ArgumentOutOfRangeException("gameplayStarCount"); } MultiStarGenerationPlan multiStarGenerationPlan = null; int num = gameplayStarCount * 3; for (int i = gameplayStarCount; i <= num; i++) { MultiStarGenerationPlan multiStarGenerationPlan2 = Create(galaxySeed, i); int gameplayStarCount2 = GetGameplayStarCount(multiStarGenerationPlan2); if (gameplayStarCount2 == gameplayStarCount) { return multiStarGenerationPlan2; } if (gameplayStarCount2 < gameplayStarCount && TryPromoteVirtualSystems(multiStarGenerationPlan2, gameplayStarCount - gameplayStarCount2)) { multiStarGenerationPlan2.BuildIndex(); Validate(multiStarGenerationPlan2); return multiStarGenerationPlan2; } if (gameplayStarCount2 >= gameplayStarCount && (multiStarGenerationPlan == null || gameplayStarCount2 < GetGameplayStarCount(multiStarGenerationPlan))) { multiStarGenerationPlan = multiStarGenerationPlan2; } } if (multiStarGenerationPlan == null) { throw new InvalidOperationException("Could not allocate enough physical stars for the requested gameplay star count."); } return multiStarGenerationPlan; } private static bool TryPromoteVirtualSystems(MultiStarGenerationPlan plan, int requiredGameplayStars) { if (requiredGameplayStars <= 0) { return requiredGameplayStars == 0; } List list = new List(); for (int i = 0; i < plan.Systems.Count; i++) { if (!plan.Systems[i].HasSpecialStar()) { list.Add(i); } } int[] array = new int[requiredGameplayStars + 1]; int[] array2 = new int[requiredGameplayStars + 1]; for (int j = 0; j < array.Length; j++) { array[j] = -1; array2[j] = -1; } array[0] = -2; for (int k = 0; k < list.Count; k++) { int num = list[k]; int num2 = plan.Systems[num].StarCount - 1; for (int num3 = requiredGameplayStars; num3 >= num2; num3--) { if (array[num3] == -1 && array[num3 - num2] != -1) { array[num3] = num; array2[num3] = num3 - num2; } } } if (array[requiredGameplayStars] == -1) { return false; } HashSet hashSet = new HashSet(); for (int num4 = requiredGameplayStars; num4 > 0; num4 = array2[num4]) { hashSet.Add(array[num4]); } for (int num5 = plan.Systems.Count - 1; num5 >= 0; num5--) { if (hashSet.Contains(num5)) { plan.Systems.RemoveAt(num5); } } return true; } internal static int GetGameplayStarCount(MultiStarGenerationPlan plan) { if (plan == null) { return 0; } int num = 0; for (int i = 0; i < plan.Systems.Count; i++) { num += plan.Systems[i].StarCount - 1; } return plan.PhysicalStarCount - num; } private static int ChooseMemberCount(DeterministicRandom random, int remaining) { double num = 0.0; for (int i = 2; i <= Math.Min(6, remaining); i++) { num += GetMemberWeight(i); } double num2 = random.Range(0.0, num); for (int j = 2; j <= Math.Min(6, remaining); j++) { num2 -= GetMemberWeight(j); if (num2 < 0.0) { return j; } } return Math.Min(6, remaining); } private static double GetMemberWeight(int count) { return count switch { 2 => 0.4, 3 => 0.25, 4 => 0.2, 5 => 0.1, 6 => 0.05, _ => 0.0, }; } private static MultiStarSystemPlan CreateSystem(DeterministicRandom random, int firstStarId, int starCount) { MultiStarSystemPlan obj = new MultiStarSystemPlan { FirstStarId = firstStarId, StarCount = starCount, RealMemberIndex = ((firstStarId != 1) ? random.NextInt(starCount) : 0), StellarKinds = new StellarKind[starCount], RealSystemDiameterFactor = random.Range(3.0, 5.5), VirtualSubsystemFactor = random.Range(1.0, 5.0), SecondaryVirtualSubsystemFactor = random.Range(1.0, 5.0), Phase = random.Range(0.0, Math.PI * 2.0), InnerPhase = random.Range(0.0, Math.PI * 2.0), OuterPhase = random.Range(0.0, Math.PI * 2.0), Longitude = random.Range(0.0, Math.PI * 2.0), Inclination = random.Range(-Math.PI / 6.0, Math.PI / 6.0) }; AssignTopology(obj, random); AssignStellarKinds(obj, random); AssignDysonCompanion(obj); return obj; } private static void AssignTopology(MultiStarSystemPlan system, DeterministicRandom random) { switch (system.StarCount) { case 2: system.Topology = SystemTopology.Binary; break; case 3: system.Topology = (random.Chance(0.5) ? SystemTopology.Triangle : SystemTopology.BinaryWithMassiveOuter); if (system.Topology == SystemTopology.BinaryWithMassiveOuter && system.FirstStarId != 1) { system.RealMemberIndex = random.NextInt(2); } break; case 4: { double num = random.NextDouble(); if (num < 0.3) { system.Topology = SystemTopology.Square; break; } if (num < 0.6) { system.Topology = SystemTopology.DoubleBinary; break; } system.Topology = SystemTopology.TripleWithMassiveOuter; system.InnerTopology = (random.Chance(0.5) ? InnerTripleTopology.Triangle : InnerTripleTopology.BinaryWithMassiveOuter); if (system.FirstStarId != 1) { system.RealMemberIndex = random.NextInt(3); } break; } case 5: system.Topology = SystemTopology.Pentagon; break; case 6: system.Topology = SystemTopology.Hexagon; break; default: throw new InvalidOperationException("Unsupported multi-star member count."); } } private static void AssignStellarKinds(MultiStarSystemPlan system, DeterministicRandom random) { for (int i = 0; i < system.StellarKinds.Length; i++) { system.StellarKinds[i] = OrdinaryKinds[random.NextInt(OrdinaryKinds.Length)]; } foreach (int[] binaryPair in GetBinaryPairs(system)) { AssignOrdinaryCompatiblePair(system.StellarKinds, binaryPair[0], binaryPair[1], random); } bool mandatorySpecial = AssignMandatorySpecialStars(system, random); if (ShouldAssignOptionalSpecial(system, mandatorySpecial, random)) { AssignOptionalSpecial(system, random); } } private static bool AssignMandatorySpecialStars(MultiStarSystemPlan system, DeterministicRandom random) { if (system.Topology == SystemTopology.BinaryWithMassiveOuter) { system.StellarKinds[2] = ChooseMassiveOuterKind(random); return true; } if (system.Topology == SystemTopology.TripleWithMassiveOuter) { system.StellarKinds[3] = ChooseMassiveOuterKind(random); if (system.InnerTopology == InnerTripleTopology.BinaryWithMassiveOuter) { system.StellarKinds[2] = ChooseMassiveOuterKind(random); } return true; } return false; } private static bool ShouldAssignOptionalSpecial(MultiStarSystemPlan system, bool mandatorySpecial, DeterministicRandom random) { if (mandatorySpecial) { return false; } if (system.StarCount == 3) { return false; } if (system.StarCount == 4) { return random.Chance(1.0 / 6.0); } return random.Chance(0.5); } private static void AssignOptionalSpecial(MultiStarSystemPlan system, DeterministicRandom random) { int num = random.NextInt(system.StarCount); StellarKind stellarKind = SpecialKinds[random.NextInt(SpecialKinds.Length)]; int num2 = FindBinaryPartner(system, num); if (num2 >= 0) { AssignCompatiblePairWithSpecial(system.StellarKinds, num, num2, stellarKind, random); } else { system.StellarKinds[num] = stellarKind; } } private static void EnsureSpecialStar(IList systems, DeterministicRandom random) { for (int i = 0; i < systems.Count; i++) { if (systems[i].HasSpecialStar()) { return; } } AssignOptionalSpecial(systems[0], random); AssignDysonCompanion(systems[0]); } private static void EnsureOStar(IList systems, DeterministicRandom random) { for (int i = 0; i < systems.Count; i++) { MultiStarSystemPlan multiStarSystemPlan = systems[i]; for (int j = 0; j < multiStarSystemPlan.StarCount; j++) { if (multiStarSystemPlan.StellarKinds[j] == StellarKind.MainO) { return; } } } MultiStarSystemPlan multiStarSystemPlan2 = systems[0]; for (int k = 0; k < systems.Count; k++) { if (systems[k].HasSpecialStar()) { multiStarSystemPlan2 = systems[k]; break; } } int num = ((multiStarSystemPlan2.Topology != SystemTopology.BinaryWithMassiveOuter && multiStarSystemPlan2.Topology != SystemTopology.TripleWithMassiveOuter) ? random.NextInt(multiStarSystemPlan2.StarCount) : 0); int num2 = FindBinaryPartner(multiStarSystemPlan2, num); if (num2 >= 0) { AssignCompatiblePairWithSpecial(multiStarSystemPlan2.StellarKinds, num, num2, StellarKind.MainO, random); } else { multiStarSystemPlan2.StellarKinds[num] = StellarKind.MainO; } AssignDysonCompanion(multiStarSystemPlan2); } internal static void EnsureVisibleMassiveVirtualCompanion(IList systems) { if (HasVisibleMassiveVirtualCompanion(systems)) { return; } MultiStarSystemPlan multiStarSystemPlan = FindExternalMassiveSystem(systems); if (multiStarSystemPlan == null) { multiStarSystemPlan = PromoteExternalMassiveSystem(systems); } if (multiStarSystemPlan == null) { multiStarSystemPlan = FindWideBinaryFallback(systems); } if (multiStarSystemPlan != null) { int externalMassiveMember = GetExternalMassiveMember(multiStarSystemPlan); multiStarSystemPlan.StellarKinds[externalMassiveMember] = StellarKind.GiantBlue; int num = FindBinaryPartner(multiStarSystemPlan, externalMassiveMember); if (num >= 0) { multiStarSystemPlan.StellarKinds[num] = StellarKind.GiantWhite; } AssignDysonCompanion(multiStarSystemPlan); } } internal static bool HasVisibleMassiveVirtualCompanion(MultiStarGenerationPlan plan) { if (plan != null) { return HasVisibleMassiveVirtualCompanion(plan.Systems); } return false; } private static bool HasVisibleMassiveVirtualCompanion(IList systems) { for (int i = 0; i < systems.Count; i++) { MultiStarSystemPlan multiStarSystemPlan = systems[i]; int externalMassiveMember = GetExternalMassiveMember(multiStarSystemPlan); if (externalMassiveMember >= 0 && externalMassiveMember != multiStarSystemPlan.RealMemberIndex && (multiStarSystemPlan.StellarKinds[externalMassiveMember] == StellarKind.MainO || multiStarSystemPlan.StellarKinds[externalMassiveMember] == StellarKind.GiantBlue)) { return true; } } return false; } private static MultiStarSystemPlan FindExternalMassiveSystem(IList systems) { for (int i = 0; i < systems.Count; i++) { MultiStarSystemPlan multiStarSystemPlan = systems[i]; int externalMassiveMember = GetExternalMassiveMember(multiStarSystemPlan); if (externalMassiveMember >= 0 && externalMassiveMember != multiStarSystemPlan.RealMemberIndex && multiStarSystemPlan.Topology != SystemTopology.Binary) { return multiStarSystemPlan; } } return null; } private static MultiStarSystemPlan PromoteExternalMassiveSystem(IList systems) { MultiStarSystemPlan multiStarSystemPlan = FindConvertibleSystem(systems, 3, requireExistingSpecial: true) ?? FindConvertibleSystem(systems, 4, requireExistingSpecial: true) ?? FindConvertibleSystem(systems, 3, requireExistingSpecial: false) ?? FindConvertibleSystem(systems, 4, requireExistingSpecial: false); if (multiStarSystemPlan == null) { return null; } if (multiStarSystemPlan.StarCount == 3) { multiStarSystemPlan.Topology = SystemTopology.BinaryWithMassiveOuter; multiStarSystemPlan.InnerTopology = InnerTripleTopology.None; multiStarSystemPlan.RealMemberIndex = 0; multiStarSystemPlan.StellarKinds[0] = StellarKind.MainB; multiStarSystemPlan.StellarKinds[1] = StellarKind.MainB; multiStarSystemPlan.StellarKinds[2] = StellarKind.GiantBlue; } else { multiStarSystemPlan.Topology = SystemTopology.TripleWithMassiveOuter; multiStarSystemPlan.InnerTopology = InnerTripleTopology.Triangle; multiStarSystemPlan.RealMemberIndex = 0; multiStarSystemPlan.StellarKinds[0] = StellarKind.MainB; multiStarSystemPlan.StellarKinds[1] = StellarKind.MainB; multiStarSystemPlan.StellarKinds[2] = StellarKind.MainB; multiStarSystemPlan.StellarKinds[3] = StellarKind.GiantBlue; } AssignDysonCompanion(multiStarSystemPlan); return multiStarSystemPlan; } private static MultiStarSystemPlan FindConvertibleSystem(IList systems, int starCount, bool requireExistingSpecial) { for (int i = 0; i < systems.Count; i++) { MultiStarSystemPlan multiStarSystemPlan = systems[i]; if (multiStarSystemPlan.StarCount == starCount && Array.IndexOf(multiStarSystemPlan.StellarKinds, StellarKind.MainO) < 0 && (!requireExistingSpecial || multiStarSystemPlan.HasSpecialStar())) { return multiStarSystemPlan; } } return null; } private static MultiStarSystemPlan FindWideBinaryFallback(IList systems) { for (int i = 0; i < 2; i++) { for (int j = 0; j < systems.Count; j++) { MultiStarSystemPlan multiStarSystemPlan = systems[j]; if (multiStarSystemPlan.Topology == SystemTopology.Binary && Array.IndexOf(multiStarSystemPlan.StellarKinds, StellarKind.MainO) < 0 && (i != 0 || multiStarSystemPlan.HasSpecialStar())) { int num = ((multiStarSystemPlan.RealMemberIndex == 0) ? 1 : 0); multiStarSystemPlan.StellarKinds[num] = StellarKind.GiantBlue; multiStarSystemPlan.StellarKinds[multiStarSystemPlan.RealMemberIndex] = StellarKind.GiantWhite; AssignDysonCompanion(multiStarSystemPlan); return multiStarSystemPlan; } } } for (int k = 0; k < systems.Count; k++) { MultiStarSystemPlan multiStarSystemPlan2 = systems[k]; if (multiStarSystemPlan2.Topology == SystemTopology.Binary) { int num2 = ((multiStarSystemPlan2.RealMemberIndex == 0) ? 1 : 0); multiStarSystemPlan2.StellarKinds[num2] = StellarKind.MainO; multiStarSystemPlan2.StellarKinds[multiStarSystemPlan2.RealMemberIndex] = StellarKind.MainO; AssignDysonCompanion(multiStarSystemPlan2); return multiStarSystemPlan2; } } return null; } private static int GetExternalMassiveMember(MultiStarSystemPlan system) { if (system.Topology == SystemTopology.BinaryWithMassiveOuter) { return 2; } if (system.Topology == SystemTopology.TripleWithMassiveOuter) { return 3; } if (system.Topology == SystemTopology.Binary) { return (system.RealMemberIndex == 0) ? 1 : 0; } return -1; } private static void AssignOrdinaryCompatiblePair(StellarKind[] kinds, int first, int second, DeterministicRandom random) { switch (random.NextInt(3)) { case 0: { int num4 = random.NextInt(6); int num5 = random.NextInt(3) - 1; int num6 = Math.Max(0, Math.Min(5, num4 + num5)); kinds[first] = (StellarKind)num4; kinds[second] = (StellarKind)num6; break; } case 1: { int num = random.NextInt(3); int num2 = random.NextInt(3) - 1; int num3 = Math.Max(0, Math.Min(2, num + num2)); kinds[first] = (StellarKind)(7 + num); kinds[second] = (StellarKind)(7 + num3); break; } default: kinds[first] = StellarKind.WhiteDwarf; kinds[second] = StellarKind.WhiteDwarf; break; } } private static void AssignCompatiblePairWithSpecial(StellarKind[] kinds, int specialMember, int partner, StellarKind special, DeterministicRandom random) { kinds[specialMember] = special; switch (special) { case StellarKind.MainO: kinds[partner] = (random.Chance(0.5) ? StellarKind.MainB : StellarKind.MainO); break; case StellarKind.GiantBlue: kinds[partner] = (random.Chance(0.5) ? StellarKind.GiantWhite : StellarKind.GiantBlue); break; case StellarKind.NeutronStar: { StellarKind[] array = new StellarKind[2] { StellarKind.NeutronStar, StellarKind.BlackHole }; kinds[partner] = array[random.NextInt(array.Length)]; break; } case StellarKind.BlackHole: kinds[partner] = (random.Chance(0.5) ? StellarKind.NeutronStar : StellarKind.BlackHole); break; } } private static StellarKind ChooseMassiveOuterKind(DeterministicRandom random) { StellarKind[] array = new StellarKind[3] { StellarKind.GiantBlue, StellarKind.NeutronStar, StellarKind.BlackHole }; return array[random.NextInt(array.Length)]; } private static IEnumerable GetBinaryPairs(MultiStarSystemPlan system) { if (system.Topology == SystemTopology.Binary || system.Topology == SystemTopology.BinaryWithMassiveOuter) { yield return new int[2] { 0, 1 }; } else if (system.Topology == SystemTopology.DoubleBinary) { yield return new int[2] { 0, 1 }; yield return new int[2] { 2, 3 }; } else if (system.Topology == SystemTopology.TripleWithMassiveOuter && system.InnerTopology == InnerTripleTopology.BinaryWithMassiveOuter) { yield return new int[2] { 0, 1 }; } } private static int FindBinaryPartner(MultiStarSystemPlan system, int member) { foreach (int[] binaryPair in GetBinaryPairs(system)) { if (binaryPair[0] == member) { return binaryPair[1]; } if (binaryPair[1] == member) { return binaryPair[0]; } } return -1; } private static void AssignDysonCompanion(MultiStarSystemPlan system) { system.DysonCompanionMemberIndex = FindBinaryPartner(system, system.RealMemberIndex); } internal static bool IsSpecial(StellarKind kind) { if (kind != StellarKind.MainO && kind != StellarKind.GiantBlue && kind != StellarKind.NeutronStar) { return kind == StellarKind.BlackHole; } return true; } internal static bool AreBinaryCompatible(StellarKind first, StellarKind second) { GetBranchAndGrade(first, out var branch, out var grade); GetBranchAndGrade(second, out var branch2, out var grade2); if (branch == branch2) { return Math.Abs(grade - grade2) <= 1; } return false; } private static void GetBranchAndGrade(StellarKind kind, out int branch, out int grade) { if ((int)kind >= 0 && (int)kind <= 6) { branch = 0; grade = (int)kind; } else if ((int)kind >= 7 && (int)kind <= 10) { branch = 1; grade = (int)(kind - 7); } else if (kind == StellarKind.WhiteDwarf) { branch = 2; grade = 0; } else { branch = 3; grade = (int)(kind - 12); } } internal static void Validate(MultiStarGenerationPlan plan) { if (plan == null || plan.PhysicalStarCount < 2 || (plan.SpacingProfile != MultiStarSpacingProfile.Legacy && plan.SpacingProfile != MultiStarSpacingProfile.Expanded)) { throw new InvalidOperationException("Invalid multi-star galaxy plan."); } bool flag = false; HashSet hashSet = new HashSet(); for (int i = 0; i < plan.Systems.Count; i++) { MultiStarSystemPlan multiStarSystemPlan = plan.Systems[i]; if (multiStarSystemPlan.StarCount < 2 || multiStarSystemPlan.StarCount > 6 || multiStarSystemPlan.RealMemberIndex < 0 || multiStarSystemPlan.RealMemberIndex >= multiStarSystemPlan.StarCount || multiStarSystemPlan.StellarKinds == null || multiStarSystemPlan.StellarKinds.Length != multiStarSystemPlan.StarCount) { throw new InvalidOperationException("Invalid multi-star system plan."); } if (!IsTopologyValid(multiStarSystemPlan) || !AreSpacingFactorsValid(plan.SpacingProfile, multiStarSystemPlan) || !IsFinite(multiStarSystemPlan.Phase) || !IsFinite(multiStarSystemPlan.InnerPhase) || !IsFinite(multiStarSystemPlan.OuterPhase) || !IsFinite(multiStarSystemPlan.Longitude) || !IsFinite(multiStarSystemPlan.Inclination)) { throw new InvalidOperationException("Invalid multi-star topology or orbit data."); } int num = FindBinaryPartner(multiStarSystemPlan, multiStarSystemPlan.RealMemberIndex); if (multiStarSystemPlan.DysonCompanionMemberIndex != num) { throw new InvalidOperationException("Invalid binary Dyson companion."); } for (int j = 0; j < multiStarSystemPlan.StarCount; j++) { int num2 = multiStarSystemPlan.FirstStarId + j; if (num2 < 1 || num2 > plan.PhysicalStarCount || !hashSet.Add(num2)) { throw new InvalidOperationException("Invalid or duplicate multi-star member ID."); } if ((int)multiStarSystemPlan.StellarKinds[j] < 0 || (int)multiStarSystemPlan.StellarKinds[j] > 13) { throw new InvalidOperationException("Invalid stellar kind."); } } foreach (int[] binaryPair in GetBinaryPairs(multiStarSystemPlan)) { if (!AreBinaryCompatible(multiStarSystemPlan.StellarKinds[binaryPair[0]], multiStarSystemPlan.StellarKinds[binaryPair[1]])) { throw new InvalidOperationException("Generated an incompatible binary pair."); } } flag |= multiStarSystemPlan.HasSpecialStar(); } if (plan.Systems.Count == 0 || !flag) { throw new InvalidOperationException("The galaxy must contain a special multi-star system."); } } private static bool IsTopologyValid(MultiStarSystemPlan system) { switch (system.StarCount) { case 2: if (system.Topology == SystemTopology.Binary) { return system.InnerTopology == InnerTripleTopology.None; } return false; case 3: if (system.Topology == SystemTopology.Triangle || system.Topology == SystemTopology.BinaryWithMassiveOuter) { return system.InnerTopology == InnerTripleTopology.None; } return false; case 4: if (system.Topology == SystemTopology.Square || system.Topology == SystemTopology.DoubleBinary) { return system.InnerTopology == InnerTripleTopology.None; } if (system.Topology == SystemTopology.TripleWithMassiveOuter) { if (system.InnerTopology != InnerTripleTopology.Triangle) { return system.InnerTopology == InnerTripleTopology.BinaryWithMassiveOuter; } return true; } return false; case 5: if (system.Topology == SystemTopology.Pentagon) { return system.InnerTopology == InnerTripleTopology.None; } return false; case 6: if (system.Topology == SystemTopology.Hexagon) { return system.InnerTopology == InnerTripleTopology.None; } return false; default: return false; } } private static bool AreSpacingFactorsValid(MultiStarSpacingProfile profile, MultiStarSystemPlan system) { switch (profile) { case MultiStarSpacingProfile.Legacy: if (IsFiniteInRange(system.RealSystemDiameterFactor, 0.5, 0.8) && IsFiniteInRange(system.VirtualSubsystemFactor, 1.1, 1.5)) { return IsFiniteInRange(system.SecondaryVirtualSubsystemFactor, 1.1, 1.5); } return false; case MultiStarSpacingProfile.Expanded: if (IsFiniteInRange(system.RealSystemDiameterFactor, 3.0, 5.5) && IsFiniteInRange(system.VirtualSubsystemFactor, 1.0, 5.0)) { return IsFiniteInRange(system.SecondaryVirtualSubsystemFactor, 1.0, 5.0); } return false; default: return false; } } private static bool IsFiniteInRange(double value, double minimum, double maximum) { if (IsFinite(value) && value >= minimum) { return value <= maximum; } return false; } private static bool IsFinite(double value) { if (!double.IsNaN(value)) { return !double.IsInfinity(value); } return false; } } internal static class GenerationSession { private static int importDepth; private static int generationDepth; private static MultiStarGenerationPlan activePlan; internal static bool IsImporting => importDepth > 0; internal static bool IsGenerating => generationDepth > 0; internal static MultiStarGenerationPlan ActivePlan => activePlan; internal static void BeginImport() { importDepth++; } internal static void EndImport() { importDepth = Math.Max(0, importDepth - 1); if (importDepth == 0) { MultiStarSaveStore.Clear(); } } internal static void BeginGalaxy(GameDesc gameDesc) { generationDepth++; if (generationDepth > 1 || gameDesc == null) { return; } MultiStarGenerationPlan matchingPlan = MultiStarSaveStore.GetMatchingPlan(gameDesc.galaxySeed, gameDesc.starCount); if (matchingPlan != null) { activePlan = matchingPlan; ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("Restored multi-star plan for seed " + gameDesc.galaxySeed + " with " + matchingPlan.PhysicalStarCount + " physical stars.")); } } else if (IsImporting) { MultiStarGenerationPlan multiStarGenerationPlan = TryRecoverExpandedSavedPlan(gameDesc); if (multiStarGenerationPlan != null) { int starCount = gameDesc.starCount; gameDesc.starCount = multiStarGenerationPlan.PhysicalStarCount; activePlan = multiStarGenerationPlan; ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogWarning((object)("Recovered multi-star plan for seed " + gameDesc.galaxySeed + " after another generator restored starCount from " + starCount + " to its pre-expansion value. Using " + multiStarGenerationPlan.PhysicalStarCount + " physical stars.")); } } else { LogUnmatchedSavedPlan(gameDesc); activePlan = null; } } else { int count; bool flag = WanderingPlanetCompatibility.TryGetReservedSystemCount(gameDesc, out count); int num = gameDesc.starCount - (flag ? count : 0); if (num < 2) { num = gameDesc.starCount; flag = false; count = 0; } if (num <= 64) { activePlan = GenerationPlanner.CreateForGameplayStarCount(gameDesc.galaxySeed, num); } else { activePlan = GenerationPlanner.Create(gameDesc.galaxySeed, num); } if (flag) { activePlan.PhysicalStarCount += count; } gameDesc.starCount = activePlan.PhysicalStarCount; } } private static MultiStarGenerationPlan TryRecoverExpandedSavedPlan(GameDesc gameDesc) { MultiStarGenerationPlan pendingPlan = MultiStarSaveStore.PendingPlan; if (pendingPlan == null || pendingPlan.GalaxySeed != gameDesc.galaxySeed || pendingPlan.PhysicalStarCount <= gameDesc.starCount) { return null; } int gameplayStarCount = GenerationPlanner.GetGameplayStarCount(pendingPlan); if (gameDesc.starCount == gameplayStarCount) { return pendingPlan; } if (!WanderingPlanetCompatibility.TryGetReservedSystemCount(gameDesc, out var count) || gameDesc.starCount + count != gameplayStarCount) { return null; } return pendingPlan; } private static void LogUnmatchedSavedPlan(GameDesc gameDesc) { MultiStarGenerationPlan pendingPlan = MultiStarSaveStore.PendingPlan; if (pendingPlan == null) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("No multi-star plan was available while importing galaxy seed " + gameDesc.galaxySeed + ". The save may be missing its .moddsv sidecar.")); } return; } ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogError((object)("Refused to apply multi-star plan while importing galaxy: saved seed=" + pendingPlan.GalaxySeed + ", saved physical stars=" + pendingPlan.PhysicalStarCount + ", game seed=" + gameDesc.galaxySeed + ", game stars=" + gameDesc.starCount + ". The .dsv and .moddsv files do not describe the same galaxy.")); } } internal static void EndGalaxy() { generationDepth = Math.Max(0, generationDepth - 1); if (generationDepth == 0) { activePlan = null; } } internal static bool TryGetSystem(int starId, out MultiStarSystemPlan system) { system = null; if (activePlan != null) { return activePlan.TryGetSystem(starId, out system); } return false; } internal static void Clear() { importDepth = 0; generationDepth = 0; activePlan = null; } } internal static class ModConfig { internal const double DefaultOrbitSpeedMultiplier = 1800.0; private const double LegacyDefaultOrbitSpeedMultiplier = 20.0; private const double PreviousDefaultOrbitSpeedMultiplier = 3600.0; internal static ConfigEntry OrbitSpeedMultiplier { get; private set; } internal static void Initialize(ConfigFile config) { OrbitSpeedMultiplier = config.Bind("Motion", "OrbitSpeedMultiplier", 1800.0, "Internal stellar-orbit speed multiplier. The default makes binary motion clearly visible while outer hierarchy orbits remain slower."); if (Math.Abs(OrbitSpeedMultiplier.Value - 20.0) < 1E-06 || Math.Abs(OrbitSpeedMultiplier.Value - 3600.0) < 1E-06) { OrbitSpeedMultiplier.Value = 1800.0; } } } [HarmonyPatch(typeof(GalaxyData), "UpdatePoses", new Type[] { typeof(double) })] internal static class GalaxyPosePatch { [HarmonyPrefix] [HarmonyPriority(800)] private static void Prefix(GalaxyData __instance, double time) { if (!GenerationSession.IsGenerating && MultiStarRuntimeRegistry.TryGetRuntime(__instance, out var runtime)) { runtime.Apply(__instance, time); } } [HarmonyPostfix] [HarmonyPriority(0)] private static void Postfix(GalaxyData __instance) { if (!GenerationSession.IsGenerating && MultiStarRuntimeRegistry.TryGetRuntime(__instance, out var runtime)) { runtime.ApplyNextFramePlanetOffsets(__instance); } } } internal static class MultiStarRelationshipFormatter { internal static string Format(StarData star) { if (star == null || !MultiStarRuntimeRegistry.TryGetSystem(star, out var system)) { return null; } int memberIndex = system.GetMemberIndex(star.id); if (memberIndex < 0) { return null; } Func func = (int index) => GetMemberName(star.galaxy, system, index); switch (system.Topology) { case SystemTopology.Binary: return BinaryLine(func, (memberIndex == 0) ? 1 : 0); case SystemTopology.Triangle: return "与" + OtherNames(func, system.StarCount, memberIndex) + "共同组成正三角形三星"; case SystemTopology.BinaryWithMassiveOuter: if (memberIndex >= 2) { return "与" + func(0) + "、" + func(1) + "组成的双星组成三星"; } return BinaryLine(func, (memberIndex == 0) ? 1 : 0) + "\n并与" + func(2) + "恒星组成三星"; case SystemTopology.Square: return "与" + OtherNames(func, system.StarCount, memberIndex) + "共同组成正方形四星"; case SystemTopology.DoubleBinary: return FormatDoubleBinary(func, memberIndex); case SystemTopology.TripleWithMassiveOuter: if (system.InnerTopology != InnerTripleTopology.Triangle) { return FormatBinaryTripleWithOuter(func, memberIndex); } return FormatTriangleWithOuter(func, memberIndex); case SystemTopology.Pentagon: return "与" + OtherNames(func, system.StarCount, memberIndex) + "共同组成正五边形五星"; case SystemTopology.Hexagon: return "与" + OtherNames(func, system.StarCount, memberIndex) + "共同组成正六边形六星"; default: return null; } } private static string FormatDoubleBinary(Func name, int member) { int companion = (((member & 1) == 0) ? (member + 1) : (member - 1)); int num = ((member < 2) ? 2 : 0); return BinaryLine(name, companion) + "\n并与" + name(num) + "、" + name(num + 1) + "组成的双星组成四星"; } private static string FormatTriangleWithOuter(Func name, int member) { if (member == 3) { return "与" + name(0) + "、" + name(1) + "、" + name(2) + "组成的三星组成四星"; } return "与" + OtherNames(name, 3, member) + "共同组成正三角形三星\n并与" + name(3) + "恒星组成四星"; } private static string FormatBinaryTripleWithOuter(Func name, int member) { if (member < 2) { return BinaryLine(name, (member == 0) ? 1 : 0) + "\n并与" + name(2) + "恒星组成三星\n并与" + name(3) + "恒星组成四星"; } if (member == 2) { return "与" + name(0) + "、" + name(1) + "组成的双星组成三星\n并与" + name(3) + "恒星组成四星"; } return "与" + name(0) + "、" + name(1) + "、" + name(2) + "组成的三星组成四星"; } private static string BinaryLine(Func name, int companion) { return "与" + name(companion) + "恒星组成双星"; } private static string OtherNames(Func name, int count, int excluded) { List list = new List(); for (int i = 0; i < count; i++) { if (i != excluded) { list.Add(name(i)); } } return string.Join("、", list.ToArray()); } private static string GetMemberName(GalaxyData galaxy, MultiStarSystemPlan system, int member) { StarData obj = ((galaxy != null) ? galaxy.StarById(system.FirstStarId + member) : null); return ((obj != null) ? obj.displayName : null) ?? "未知"; } } internal static class MultiStarRuntimeRegistry { private static ConditionalWeakTable runtimes = new ConditionalWeakTable(); internal static void RegisterGalaxy(GalaxyData galaxy, MultiStarGenerationPlan plan) { if (galaxy != null && plan != null && galaxy.seed == plan.GalaxySeed && galaxy.starCount == plan.PhysicalStarCount) { GalaxyMultiStarRuntime galaxyMultiStarRuntime = new GalaxyMultiStarRuntime(galaxy, plan); runtimes.Remove(galaxy); runtimes.Add(galaxy, galaxyMultiStarRuntime); galaxyMultiStarRuntime.Apply(galaxy, 0.0, force: true); galaxyMultiStarRuntime.ApplyVirtualNames(); galaxyMultiStarRuntime.RefreshPlanetPoses(0.0); galaxyMultiStarRuntime.RebuildStarGraph(); ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("Generated " + plan.Systems.Count + " multi-star systems from " + plan.PhysicalStarCount + " physical stars.")); } } } internal static bool TryGetRuntime(GalaxyData galaxy, out GalaxyMultiStarRuntime runtime) { runtime = null; if (galaxy != null) { return runtimes.TryGetValue(galaxy, out runtime); } return false; } internal static bool TryGetSystem(StarData star, out MultiStarSystemPlan system) { system = null; if (star != null && TryGetRuntime(star.galaxy, out var runtime)) { return runtime.Plan.TryGetSystem(star.id, out system); } return false; } internal static StarData ResolveTravelStar(StarData star) { if (star == null || !TryGetSystem(star, out var system) || system.IsPlanetOwnerStarId(star.id)) { return star; } return star.galaxy.StarById(system.RealStarId) ?? star; } internal static StarData ResolveDysonStar(StarData star) { if (star == null || !TryGetSystem(star, out var system) || system.RealStarId == star.id) { return star; } return star.galaxy.StarById(system.RealStarId) ?? star; } internal static bool IsVirtualStar(StarData star) { if (star != null && TryGetSystem(star, out var system)) { return system.RealStarId != star.id; } return false; } internal static void SynchronizeForImmediateTravel(GalaxyData galaxy) { if (TryGetRuntime(galaxy, out var runtime)) { double time = (double)GameMain.gameTick / 60.0; runtime.Apply(galaxy, time, force: true); runtime.RefreshPlanetPoses(time); } } internal static MultiStarGenerationPlan GetActiveGamePlan() { if (!TryGetRuntime(GameMain.data?.galaxy, out var runtime)) { return null; } return runtime.Plan; } internal static void ClearActiveState() { runtimes = new ConditionalWeakTable(); } } internal sealed class GalaxyMultiStarRuntime { private readonly Dictionary systemsByRealStarId = new Dictionary(); private double lastAppliedTime = double.NaN; internal MultiStarGenerationPlan Plan { get; } internal GalaxyMultiStarRuntime(GalaxyData galaxy, MultiStarGenerationPlan plan) { Plan = plan; for (int i = 0; i < plan.Systems.Count; i++) { MultiStarSystemPlan multiStarSystemPlan = plan.Systems[i]; RuntimeSystem value = new RuntimeSystem(galaxy, multiStarSystemPlan, plan.SpacingProfile); systemsByRealStarId.Add(multiStarSystemPlan.RealStarId, value); } } internal void Apply(GalaxyData galaxy, double time, bool force = false) { //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) if (!force && time == lastAppliedTime) { return; } int num; object obj; if (GameMain.data != null) { num = ((GameMain.data.galaxy == galaxy) ? 1 : 0); if (num != 0) { obj = GameMain.data.localStar; goto IL_0034; } } else { num = 0; } obj = null; goto IL_0034; IL_0034: StarData val = (StarData)obj; Player val2 = ((num != 0) ? GameMain.mainPlayer : null); foreach (RuntimeSystem value in systemsByRealStarId.Values) { int num2; VectorLF3 val3; if (val2 != null) { num2 = (value.IsPlanetOwner(val) ? 1 : 0); if (num2 != 0) { val3 = val.uPosition; goto IL_0078; } } else { num2 = 0; } val3 = VectorLF3.zero; goto IL_0078; IL_0078: VectorLF3 val4 = val3; value.Apply(galaxy, time); if (num2 != 0) { val2.uPosition += val.uPosition - val4; } } lastAppliedTime = time; } internal void ApplyVirtualNames() { foreach (RuntimeSystem value in systemsByRealStarId.Values) { value.ApplyVirtualNames(); } } internal void RefreshPlanetPoses(double time) { foreach (RuntimeSystem value in systemsByRealStarId.Values) { value.RefreshPlanetPoses(time); value.ApplyNextFramePlanetOffset(value.RealStar.galaxy); } } internal void ApplyNextFramePlanetOffsets(GalaxyData galaxy) { foreach (RuntimeSystem value in systemsByRealStarId.Values) { value.ApplyNextFramePlanetOffset(galaxy); } } internal void RebuildStarGraph() { GalaxyData val = null; using (Dictionary.ValueCollection.Enumerator enumerator = systemsByRealStarId.Values.GetEnumerator()) { if (enumerator.MoveNext()) { val = enumerator.Current.RealStar.galaxy; } } if (val == null) { return; } if (val.graphNodes != null) { for (int i = 0; i < val.graphNodes.Length; i++) { StarGraphNode obj = val.graphNodes[i]; if (obj != null) { obj.Free(); } } } UniverseGen.CreateGalaxyStarGraph(val); foreach (MultiStarSystemPlan system in Plan.Systems) { for (int j = 0; j < system.StarCount; j++) { int num = system.FirstStarId + j; if (!system.IsPlanetOwnerStarId(num)) { IsolateGraphNode(val, num - 1); } } } } private static void IsolateGraphNode(GalaxyData galaxy, int starIndex) { if (galaxy.graphNodes == null || starIndex < 0 || starIndex >= galaxy.graphNodes.Length) { return; } StarGraphNode val = galaxy.graphNodes[starIndex]; if (val == null) { return; } for (int i = 0; i < galaxy.graphNodes.Length; i++) { StarGraphNode val2 = galaxy.graphNodes[i]; if (val2 != null && val2 != val) { val2.conns?.Remove(val); val2.lines?.Remove(val); } } val.conns?.Clear(); val.lines?.Clear(); } } internal sealed class RuntimeSystem { private const double LightYearsToUniverseUnits = 2400000.0; private const double AuToLightYears = 1.0 / 60.0; private readonly MultiStarSystemPlan plan; private readonly StarData[] members; private readonly double[] masses; private readonly VectorLF3 centerLy; private readonly MultiStarOrbitSolver orbitSolver; private readonly OrbitVector[] currentOffsets; private readonly OrbitVector[] nextOffsets; internal StarData RealStar { get; } internal RuntimeSystem(GalaxyData galaxy, MultiStarSystemPlan systemPlan, MultiStarSpacingProfile spacingProfile) { //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) plan = systemPlan; members = (StarData[])(object)new StarData[plan.StarCount]; masses = new double[plan.StarCount]; for (int i = 0; i < plan.StarCount; i++) { members[i] = galaxy.StarById(plan.FirstStarId + i); if (members[i] == null) { throw new InvalidOperationException("Missing multi-star member " + (plan.FirstStarId + i) + "."); } masses[i] = Math.Max(0.01, members[i].mass); } RealStar = members[plan.RealMemberIndex]; centerLy = RealStar.position; double firstOrbitDiameterAu = GetFirstOrbitDiameterAu(RealStar); double farthestPlanetDiameterAu = GetFarthestPlanetDiameterAu(RealStar, firstOrbitDiameterAu); MultiStarOrbitDimensions multiStarOrbitDimensions = MultiStarLayoutCalculator.Calculate(plan, masses, firstOrbitDiameterAu, farthestPlanetDiameterAu, spacingProfile); orbitSolver = new MultiStarOrbitSolver(plan, masses, multiStarOrbitDimensions.PrimaryInnerDiameterAu, multiStarOrbitDimensions.SecondaryInnerDiameterAu, multiStarOrbitDimensions.PrimaryOuterDistanceAu, multiStarOrbitDimensions.SecondaryOuterDistanceAu); currentOffsets = new OrbitVector[plan.StarCount]; nextOffsets = new OrbitVector[plan.StarCount]; } internal bool IsPlanetOwner(StarData star) { if (star != null) { return plan.IsPlanetOwnerStarId(star.id); } return false; } internal void ApplyVirtualNames() { string displayName = RealStar.displayName; for (int i = 0; i < members.Length; i++) { if (i != plan.RealMemberIndex) { members[i].overrideName = displayName + " " + (char)(65 + i); } } } internal void Apply(GalaxyData galaxy, double time) { //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_0156: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) double speedMultiplier = ModConfig.OrbitSpeedMultiplier?.Value ?? 1800.0; orbitSolver.CalculateOffsets(time, speedMultiplier, currentOffsets); orbitSolver.CalculateOffsets(time + 1.0 / 60.0, speedMultiplier, nextOffsets); for (int i = 0; i < members.Length; i++) { StarData val = members[i]; VectorLF3 val2 = centerLy + ToVectorLF3(currentOffsets[i]) * (1.0 / 60.0); VectorLF3 val3 = centerLy + ToVectorLF3(nextOffsets[i]) * (1.0 / 60.0); val.position = val2; val.uPosition = val2 * 2400000.0; if (galaxy.graphNodes != null && val.index >= 0 && val.index < galaxy.graphNodes.Length && galaxy.graphNodes[val.index] != null) { galaxy.graphNodes[val.index].pos = val2; } int astroId = val.astroId; if (galaxy.astrosData != null && astroId >= 0 && astroId < galaxy.astrosData.Length) { ref AstroData reference = ref galaxy.astrosData[astroId]; reference.id = astroId; reference.type = (EAstroType)1; reference.parentId = 0; reference.uPos = val.uPosition; reference.uPosNext = val3 * 2400000.0; reference.uRadius = val.physicsRadius; } } } internal void RefreshPlanetPoses(double time) { for (int i = 0; i < members.Length; i++) { if (!plan.IsPlanetOwnerMember(i)) { continue; } StarData val = members[i]; for (int j = 0; j < val.planetCount; j++) { PlanetData obj = val.planets[j]; if (obj != null) { obj.UpdateRuntimePose(time); } } } } internal void ApplyNextFramePlanetOffset(GalaxyData galaxy) { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) for (int i = 0; i < members.Length; i++) { if (!plan.IsPlanetOwnerMember(i)) { continue; } OrbitVector orbitVector = currentOffsets[i]; VectorLF3 val = ToVectorLF3(nextOffsets[i] - orbitVector) * 40000.0; StarData val2 = members[i]; for (int j = 0; j < val2.planetCount; j++) { PlanetData val3 = val2.planets[j]; if (val3 != null) { val3.uPositionNext += val; if (galaxy.astrosData != null && val3.id >= 0 && val3.id < galaxy.astrosData.Length) { galaxy.astrosData[val3.id].uPosNext = val3.uPositionNext; } } } } } private static VectorLF3 ToVectorLF3(OrbitVector value) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) return new VectorLF3(value.X, value.Y, value.Z); } private static double GetFirstOrbitDiameterAu(StarData star) { if (star.planets != null) { for (int i = 0; i < star.planetCount; i++) { PlanetData val = star.planets[i]; if (val != null && val.orbitAround == 0 && val.orbitIndex == 1) { return Math.Max(0.02, (double)val.orbitRadius * 2.0); } } } return Math.Max(0.02, (double)(StarGen.orbitRadius[1] * star.orbitScaler) * 2.0); } private static double GetFarthestPlanetDiameterAu(StarData star, double fallback) { double num = 0.0; if (star.planets != null) { for (int i = 0; i < star.planetCount; i++) { PlanetData val = star.planets[i]; if (val != null && val.orbitAround == 0) { num = Math.Max(num, val.orbitRadius); } } } if (!(num > 0.0)) { return fallback; } return num * 2.0; } } internal static class MultiStarSaveStore { private const uint Magic = 1297307987u; private static MultiStarGenerationPlan pendingPlan; internal static MultiStarGenerationPlan PendingPlan => pendingPlan; internal static void Export(BinaryWriter writer) { writer.Write(1297307987u); MultiStarGenerationPlan activeGamePlan = MultiStarRuntimeRegistry.GetActiveGamePlan(); writer.Write(activeGamePlan != null); activeGamePlan?.Write(writer); } internal static void Import(BinaryReader reader) { Clear(); if (reader.ReadUInt32() != 1297307987) { throw new InvalidDataException("Invalid multi-star save header."); } if (reader.ReadBoolean()) { pendingPlan = MultiStarGenerationPlan.Read(reader); } } internal static MultiStarGenerationPlan GetMatchingPlan(int seed, int starCount) { if (pendingPlan != null && pendingPlan.GalaxySeed == seed && pendingPlan.PhysicalStarCount == starCount) { return pendingPlan; } return null; } internal static void Clear() { pendingPlan = null; } } internal readonly struct OrbitVector { internal static readonly OrbitVector Zero = new OrbitVector(0.0, 0.0, 0.0); internal double X { get; } internal double Y { get; } internal double Z { get; } internal double Magnitude => Math.Sqrt(X * X + Y * Y + Z * Z); internal OrbitVector(double x, double y, double z) { X = x; Y = y; Z = z; } public static OrbitVector operator +(OrbitVector left, OrbitVector right) { return new OrbitVector(left.X + right.X, left.Y + right.Y, left.Z + right.Z); } public static OrbitVector operator -(OrbitVector left, OrbitVector right) { return new OrbitVector(left.X - right.X, left.Y - right.Y, left.Z - right.Z); } public static OrbitVector operator *(OrbitVector value, double scale) { return new OrbitVector(value.X * scale, value.Y * scale, value.Z * scale); } } internal readonly struct MultiStarOrbitDimensions { internal double PrimaryInnerDiameterAu { get; } internal double SecondaryInnerDiameterAu { get; } internal double PrimaryOuterDistanceAu { get; } internal double SecondaryOuterDistanceAu { get; } internal MultiStarOrbitDimensions(double primaryInnerDiameterAu, double secondaryInnerDiameterAu, double primaryOuterDistanceAu, double secondaryOuterDistanceAu) { PrimaryInnerDiameterAu = primaryInnerDiameterAu; SecondaryInnerDiameterAu = secondaryInnerDiameterAu; PrimaryOuterDistanceAu = primaryOuterDistanceAu; SecondaryOuterDistanceAu = secondaryOuterDistanceAu; } } internal static class MultiStarLayoutCalculator { internal static MultiStarOrbitDimensions Calculate(MultiStarSystemPlan plan, double[] masses, double firstOrbitDiameterAu, double farthestPlanetDiameterAu, MultiStarSpacingProfile spacingProfile) { if (spacingProfile == MultiStarSpacingProfile.Legacy) { return CalculateLegacy(plan, firstOrbitDiameterAu, farthestPlanetDiameterAu); } return CalculateExpanded(plan, masses, firstOrbitDiameterAu, farthestPlanetDiameterAu); } internal static MultiStarOrbitDimensions CalculateExpanded(MultiStarSystemPlan plan, double[] masses, double firstOrbitDiameterAu, double farthestPlanetDiameterAu) { if (plan == null || masses == null || masses.Length != plan.StarCount) { throw new ArgumentException("Layout inputs do not match the multi-star plan."); } double num = Math.Max(0.02, firstOrbitDiameterAu); double farthestPlanetDiameterAu2 = Math.Max(num, farthestPlanetDiameterAu); double num2 = num * plan.RealSystemDiameterFactor; switch (plan.Topology) { case SystemTopology.Binary: { double num3 = (IsExternalMassiveBinary(plan) ? CalculateExteriorSeparation(farthestPlanetDiameterAu2, num2, 0.0) : num2); return new MultiStarOrbitDimensions(num3, num3, num3, num3); } case SystemTopology.Triangle: case SystemTopology.Square: case SystemTopology.Pentagon: case SystemTopology.Hexagon: return new MultiStarOrbitDimensions(num2, num2, num2, num2); case SystemTopology.BinaryWithMassiveOuter: { double num7 = ConstrainEmbeddedDiameter(num, plan.VirtualSubsystemFactor, num2 * 0.5); double binaryMaximumOffset3 = GetBinaryMaximumOffset(num7, masses[0], masses[1]); return new MultiStarOrbitDimensions(num7, num7, CalculateExteriorSeparation(farthestPlanetDiameterAu2, num2, binaryMaximumOffset3), CalculateExteriorSeparation(farthestPlanetDiameterAu2, num2, binaryMaximumOffset3)); } case SystemTopology.DoubleBinary: { double num4 = ConstrainEmbeddedDiameter(num, plan.VirtualSubsystemFactor, num2 / 3.0); double num5 = ConstrainEmbeddedDiameter(firstOrbitDiameterAu, plan.SecondaryVirtualSubsystemFactor, num2 / 3.0); double binaryMaximumOffset = GetBinaryMaximumOffset(num4, masses[0], masses[1]); double binaryMaximumOffset2 = GetBinaryMaximumOffset(num5, masses[2], masses[3]); double num6 = CalculateExteriorSeparation(farthestPlanetDiameterAu2, num2, binaryMaximumOffset + binaryMaximumOffset2); return new MultiStarOrbitDimensions(num4, num5, num6, num6); } case SystemTopology.TripleWithMassiveOuter: if (plan.InnerTopology != InnerTripleTopology.Triangle) { return CalculateHierarchicalTriple(plan, masses, num, num2, farthestPlanetDiameterAu2); } return CalculateTriangleTriple(plan, num, num2, farthestPlanetDiameterAu2); default: throw new InvalidOperationException("Unsupported multi-star topology."); } } private static MultiStarOrbitDimensions CalculateLegacy(MultiStarSystemPlan plan, double firstOrbitDiameterAu, double farthestPlanetDiameterAu) { double num = firstOrbitDiameterAu * plan.RealSystemDiameterFactor; double num2 = farthestPlanetDiameterAu * plan.VirtualSubsystemFactor; double val = ((plan.InnerTopology == InnerTripleTopology.BinaryWithMassiveOuter) ? (num2 * 1.2) : num); double secondaryOuterDistanceAu = Math.Max(farthestPlanetDiameterAu, val) * plan.SecondaryVirtualSubsystemFactor; return new MultiStarOrbitDimensions(num, num, num2, secondaryOuterDistanceAu); } private static MultiStarOrbitDimensions CalculateTriangleTriple(MultiStarSystemPlan plan, double firstOrbitDiameterAu, double systemDiameterAu, double farthestPlanetDiameterAu) { double num = ConstrainEmbeddedDiameter(firstOrbitDiameterAu, plan.VirtualSubsystemFactor, systemDiameterAu * 0.5); return new MultiStarOrbitDimensions(num, num, num, CalculateExteriorSeparation(farthestPlanetDiameterAu, systemDiameterAu, num * 0.5)); } private static MultiStarOrbitDimensions CalculateHierarchicalTriple(MultiStarSystemPlan plan, double[] masses, double firstOrbitDiameterAu, double systemDiameterAu, double farthestPlanetDiameterAu) { double maximum = Math.Max(firstOrbitDiameterAu * 2.0, systemDiameterAu * 0.6); double num = Clamp(firstOrbitDiameterAu * plan.VirtualSubsystemFactor, firstOrbitDiameterAu * 2.0, maximum); double num2 = Clamp(firstOrbitDiameterAu * plan.SecondaryVirtualSubsystemFactor, firstOrbitDiameterAu, num * 0.5); double binaryMaximumOffset = GetBinaryMaximumOffset(num2, masses[0], masses[1]); return new MultiStarOrbitDimensions(num2, num2, Math.Max(firstOrbitDiameterAu, num - binaryMaximumOffset), CalculateExteriorSeparation(farthestPlanetDiameterAu, systemDiameterAu, num)); } private static double CalculateExteriorSeparation(double farthestPlanetDiameterAu, double systemDiameterAu, double innerExtentAu) { return Math.Max(systemDiameterAu, Math.Max(0.02, farthestPlanetDiameterAu) * 1.1 + innerExtentAu); } private static bool IsExternalMassiveBinary(MultiStarSystemPlan plan) { if (plan.Topology != SystemTopology.Binary || plan.StellarKinds == null) { return false; } int num = ((plan.RealMemberIndex == 0) ? 1 : 0); StellarKind stellarKind = plan.StellarKinds[num]; if (stellarKind != StellarKind.MainO) { return stellarKind == StellarKind.GiantBlue; } return true; } private static double ConstrainEmbeddedDiameter(double firstOrbitDiameterAu, double requestedFactor, double maximumDiameterAu) { return Clamp(Math.Max(0.02, firstOrbitDiameterAu) * requestedFactor, Math.Max(0.02, firstOrbitDiameterAu), Math.Max(firstOrbitDiameterAu, maximumDiameterAu)); } private static double GetBinaryMaximumOffset(double separationAu, double firstMass, double secondMass) { double num = Math.Max(0.02, firstMass + secondMass); return separationAu * Math.Max(firstMass, secondMass) / num; } private static double Clamp(double value, double minimum, double maximum) { return Math.Max(minimum, Math.Min(maximum, value)); } } internal sealed class MultiStarOrbitSolver { private const double TwoPi = Math.PI * 2.0; private readonly MultiStarSystemPlan plan; private readonly double[] masses; private readonly OrbitVector axisU; private readonly OrbitVector axisV; private readonly double primaryInnerDiameterAu; private readonly double secondaryInnerDiameterAu; private readonly double primaryOuterDistanceAu; private readonly double secondaryOuterDistanceAu; private readonly double direction; internal MultiStarOrbitSolver(MultiStarSystemPlan plan, double[] masses, double primaryInnerDiameterAu, double secondaryInnerDiameterAu, double primaryOuterDistanceAu, double secondaryOuterDistanceAu) { if (plan == null) { throw new ArgumentNullException("plan"); } if (masses == null || masses.Length != plan.StarCount) { throw new ArgumentException("Mass count must match the system plan.", "masses"); } this.plan = plan; this.masses = masses; this.primaryInnerDiameterAu = primaryInnerDiameterAu; this.secondaryInnerDiameterAu = secondaryInnerDiameterAu; this.primaryOuterDistanceAu = primaryOuterDistanceAu; this.secondaryOuterDistanceAu = secondaryOuterDistanceAu; direction = (((plan.FirstStarId & 1) == 0) ? (-1.0) : 1.0); double num = Math.Cos(plan.Longitude); double num2 = Math.Sin(plan.Longitude); double num3 = Math.Cos(plan.Inclination); double y = Math.Sin(plan.Inclination); axisU = new OrbitVector(num, 0.0, num2); axisV = new OrbitVector((0.0 - num2) * num3, y, num * num3); } internal void CalculateOffsets(double time, double speedMultiplier, OrbitVector[] result) { if (result == null || result.Length < plan.StarCount) { throw new ArgumentException("The output buffer is too small.", "result"); } switch (plan.Topology) { case SystemTopology.Binary: SetBinary(result, 0, 1, OrbitVector.Zero, primaryInnerDiameterAu, MovingAngle(plan.Phase, time, primaryInnerDiameterAu, masses[0] + masses[1], speedMultiplier)); break; case SystemTopology.Triangle: SetPolygon(result, 0, 3, OrbitVector.Zero, primaryInnerDiameterAu, MovingAngle(plan.Phase, time, primaryInnerDiameterAu, SumMass(0, 3), speedMultiplier)); break; case SystemTopology.BinaryWithMassiveOuter: SetHierarchicalTriple(result, OrbitVector.Zero, time, speedMultiplier, 0, 1, 2, plan.OuterPhase, plan.InnerPhase); break; case SystemTopology.Square: SetPolygon(result, 0, 4, OrbitVector.Zero, primaryInnerDiameterAu, MovingAngle(plan.Phase, time, primaryInnerDiameterAu, SumMass(0, 4), speedMultiplier)); break; case SystemTopology.DoubleBinary: SetDoubleBinary(result, time, speedMultiplier); break; case SystemTopology.TripleWithMassiveOuter: SetTripleWithMassiveOuter(result, time, speedMultiplier); break; case SystemTopology.Pentagon: SetPolygon(result, 0, 5, OrbitVector.Zero, primaryInnerDiameterAu, MovingAngle(plan.Phase, time, primaryInnerDiameterAu, SumMass(0, 5), speedMultiplier)); break; case SystemTopology.Hexagon: SetPolygon(result, 0, 6, OrbitVector.Zero, primaryInnerDiameterAu, MovingAngle(plan.Phase, time, primaryInnerDiameterAu, SumMass(0, 6), speedMultiplier)); break; default: throw new InvalidOperationException("Unsupported multi-star topology."); } } private void SetHierarchicalTriple(OrbitVector[] result, OrbitVector center, double time, double speedMultiplier, int first, int second, int outer, double hierarchyPhase, double binaryPhase) { double num = masses[first] + masses[second]; GetBinaryCenters(center, num, masses[outer], primaryOuterDistanceAu, MovingAngle(hierarchyPhase, time, primaryOuterDistanceAu, num + masses[outer], speedMultiplier), out var firstCenter, out var secondCenter); result[outer] = secondCenter; SetBinary(result, first, second, firstCenter, primaryInnerDiameterAu, MovingAngle(binaryPhase, time, primaryInnerDiameterAu, num, speedMultiplier)); } private void SetDoubleBinary(OrbitVector[] result, double time, double speedMultiplier) { double num = masses[0] + masses[1]; double num2 = masses[2] + masses[3]; GetBinaryCenters(OrbitVector.Zero, num, num2, primaryOuterDistanceAu, MovingAngle(plan.OuterPhase, time, primaryOuterDistanceAu, num + num2, speedMultiplier), out var firstCenter, out var secondCenter); SetBinary(result, 0, 1, firstCenter, primaryInnerDiameterAu, MovingAngle(plan.Phase, time, primaryInnerDiameterAu, num, speedMultiplier)); SetBinary(result, 2, 3, secondCenter, secondaryInnerDiameterAu, MovingAngle(plan.InnerPhase, time, secondaryInnerDiameterAu, num2, speedMultiplier)); } private void SetTripleWithMassiveOuter(OrbitVector[] result, double time, double speedMultiplier) { double num = masses[0] + masses[1] + masses[2]; GetBinaryCenters(OrbitVector.Zero, num, masses[3], secondaryOuterDistanceAu, MovingAngle(plan.OuterPhase, time, secondaryOuterDistanceAu, num + masses[3], speedMultiplier), out var firstCenter, out var secondCenter); result[3] = secondCenter; if (plan.InnerTopology == InnerTripleTopology.Triangle) { SetPolygon(result, 0, 3, firstCenter, primaryInnerDiameterAu, MovingAngle(plan.Phase, time, primaryInnerDiameterAu, num, speedMultiplier)); } else { SetHierarchicalTriple(result, firstCenter, time, speedMultiplier, 0, 1, 2, plan.Phase, plan.InnerPhase); } } private void SetBinary(OrbitVector[] result, int first, int second, OrbitVector center, double separation, double angle) { GetBinaryCenters(center, masses[first], masses[second], separation, angle, out var firstCenter, out var secondCenter); result[first] = firstCenter; result[second] = secondCenter; } private void GetBinaryCenters(OrbitVector center, double firstMass, double secondMass, double separation, double angle, out OrbitVector firstCenter, out OrbitVector secondCenter) { double num = Math.Max(0.02, firstMass + secondMass); OrbitVector orbitVector = Polar(1.0, angle); firstCenter = center - orbitVector * (separation * secondMass / num); secondCenter = center + orbitVector * (separation * firstMass / num); } private void SetPolygon(OrbitVector[] result, int firstMember, int memberCount, OrbitVector center, double maximumDiameter, double angle) { int num = memberCount / 2; double num2 = 2.0 * Math.Sin(Math.PI * (double)num / (double)memberCount); double radius = maximumDiameter / num2; double num3 = 0.0; OrbitVector zero = OrbitVector.Zero; for (int i = 0; i < memberCount; i++) { int num4 = firstMember + i; zero += (result[num4] = center + Polar(radius, angle + Math.PI * 2.0 * (double)i / (double)memberCount)) * masses[num4]; num3 += masses[num4]; } OrbitVector orbitVector = zero * (1.0 / Math.Max(0.01, num3)) - center; for (int j = 0; j < memberCount; j++) { int num5 = firstMember + j; result[num5] -= orbitVector; } } private OrbitVector Polar(double radius, double angle) { return axisU * (radius * Math.Cos(angle)) + axisV * (radius * Math.Sin(angle)); } private double MovingAngle(double phase, double time, double distanceAu, double totalMass, double speedMultiplier) { return phase + direction * time / CalculatePeriodSeconds(distanceAu, totalMass, speedMultiplier) * (Math.PI * 2.0); } internal static double CalculatePeriodSeconds(double distanceAu, double totalMass, double speedMultiplier) { double val = 24.0 * Math.Sqrt(Math.Pow(Math.Max(0.01, distanceAu), 3.0) / Math.Max(0.01, totalMass)); val = Math.Max(6.0, Math.Min(720.0, val)); double num = Math.Max(0.01, speedMultiplier); return Math.Max(60.0, val * 3600.0 / num); } private double SumMass(int firstMember, int memberCount) { double num = 0.0; for (int i = 0; i < memberCount; i++) { num += masses[firstMember + i]; } return num; } } internal static class PatchTargetValidator { internal static void Validate() { RequireMethod(typeof(UniverseGen), "CreateGalaxy", typeof(GameDesc)); RequireMethod(typeof(StarGen), "CreateStar", typeof(GalaxyData), typeof(VectorLF3), typeof(GameDesc), typeof(int), typeof(int), typeof(EStarType), typeof(ESpectrType)); RequireMethod(typeof(StarGen), "CreateStarPlanets", typeof(GalaxyData), typeof(StarData), typeof(GameDesc)); RequireMethod(typeof(GalaxyData), "UpdatePoses", typeof(double)); RequireMethod(typeof(GameData), "Import", typeof(BinaryReader)); RequireMethod(typeof(GameData), "ArriveStar", typeof(StarData)); RequireMethod(typeof(GameData), "ArrivePlanet", typeof(PlanetData)); RequireMethod(typeof(GameData), "CreateDysonSphere", typeof(int)); RequireMethod(typeof(SpaceSector), "TryCreateNewHive", typeof(StarData)); RequireMethod(typeof(UIStarmap), "SetViewStar", typeof(StarData), typeof(bool)); RequireMethod(typeof(UIStarmap), "OnStarClickInRouteSelectMode", typeof(StarData)); RequireMethod(typeof(DESelection), "SetViewStar", typeof(StarData)); RequireMethod(typeof(UIStarDetail), "OnStarDataSet"); RequireMethod(typeof(SunLightHandler), "LateUpdate"); MethodInfo methodInfo = AccessTools.PropertyGetter(typeof(StarData), "dysonLumino"); if (methodInfo == null || methodInfo.ReturnType != typeof(float)) { throw new MissingMethodException("StarData.dysonLumino getter has changed."); } } private static void RequireMethod(Type type, string name, params Type[] parameters) { if (AccessTools.Method(type, name, parameters, (Type[])null) == null) { throw new MissingMethodException(type.FullName + "." + name + " has changed."); } } } [BepInPlugin("Zincon.DSPMultiStarSystems", "Multi-Star Systems", "1.3.4")] [BepInProcess("DSPGAME.exe")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInIncompatibility("dsp.galactic-scale.2")] [BepInIncompatibility("Zincon.RealGalaxy")] [ModSaveSettings(/*Could not decode attribute arguments.*/)] public sealed class Plugin : BaseUnityPlugin, IModCanSave { public const string PluginGuid = "Zincon.DSPMultiStarSystems"; public const string PluginName = "Multi-Star Systems"; public const string PluginVersion = "1.3.4"; public const string CustomBirthStarLiteGuid = "Zincon.CustomCreateBirthStarLite"; public const string DspAddPlanetMoon2Guid = "Zincon.DSPAddPlanetMoon2Patch"; public const string DspAddPlanetOriginalGuid = "IndexOutOfRange.DSPAddPlanet"; public const string NestedMoonsGuid = "Zincon.DSPNestedMoons"; public const string GalacticScaleGuid = "dsp.galactic-scale.2"; public const string RealGalaxyGuid = "Zincon.RealGalaxy"; public const string WanderingPlanetsGuid = "Zincon.DSPWanderingPlanets"; private Harmony harmony; internal static ManualLogSource Log { get; private set; } private void Awake() { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; try { ModConfig.Initialize(((BaseUnityPlugin)this).Config); PatchTargetValidator.Validate(); harmony = new Harmony("Zincon.DSPMultiStarSystems"); harmony.PatchAll(typeof(Plugin).Assembly); WanderingPlanetCompatibility.Initialize(harmony); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Multi-Star Systems 1.3.4 initialized."); } catch (Exception ex) { Harmony obj = harmony; if (obj != null) { obj.UnpatchSelf(); } harmony = null; ((Behaviour)this).enabled = false; ((BaseUnityPlugin)this).Logger.LogError((object)("Multi-Star Systems failed to initialize. " + ex)); } } private void OnDestroy() { Harmony obj = harmony; if (obj != null) { obj.UnpatchSelf(); } harmony = null; GenerationSession.Clear(); MultiStarRuntimeRegistry.ClearActiveState(); MultiStarSaveStore.Clear(); CompanionLightController.Dispose(); } public void Export(BinaryWriter writer) { MultiStarSaveStore.Export(writer); } public void Import(BinaryReader reader) { MultiStarSaveStore.Import(reader); } public void IntoOtherSave() { MultiStarSaveStore.Clear(); } } [HarmonyPatch(typeof(UIStarDetail), "OnStarDataSet")] internal static class StarDetailRelationshipPatch { private const float RelationHeight = 64f; private static readonly FieldInfo ResourcesTabHeightField = AccessTools.Field(typeof(UIStarDetail), "resourcesTabHeight"); private static readonly ConditionalWeakTable relationTexts = new ConditionalWeakTable(); [HarmonyPostfix] private static void Postfix(UIStarDetail __instance) { if (!((Object)(object)__instance == (Object)null) && !((Object)(object)__instance.typeText == (Object)null)) { Text orCreateRelationText = GetOrCreateRelationText(__instance); string text = MultiStarRelationshipFormatter.Format(__instance.star); ((Component)orCreateRelationText).gameObject.SetActive(!string.IsNullOrEmpty(text)); orCreateRelationText.text = text ?? string.Empty; if (!string.IsNullOrEmpty(text)) { ReserveRelationSpace(__instance, orCreateRelationText); } } } private static Text GetOrCreateRelationText(UIStarDetail detail) { //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) if (relationTexts.TryGetValue(detail, out var value) && (Object)(object)value != (Object)null) { return value; } relationTexts.Remove(detail); Text val = Object.Instantiate(detail.typeText); ((Object)val).name = "DSPMultiStarRelationship"; ((Component)val).transform.SetParent(((Component)detail.typeText).transform.parent, false); ((Graphic)val).raycastTarget = false; val.alignment = (TextAnchor)0; val.horizontalOverflow = (HorizontalWrapMode)0; val.verticalOverflow = (VerticalWrapMode)1; val.lineSpacing = 1.05f; RectTransform rectTransform = ((Graphic)detail.typeText).rectTransform; RectTransform rectTransform2 = ((Graphic)val).rectTransform; rectTransform2.anchorMin = rectTransform.anchorMin; rectTransform2.anchorMax = rectTransform.anchorMax; rectTransform2.pivot = rectTransform.pivot; rectTransform2.anchoredPosition = rectTransform.anchoredPosition + new Vector2(0f, -24f); Rect rect = rectTransform.rect; rectTransform2.sizeDelta = new Vector2(Mathf.Max(220f, ((Rect)(ref rect)).width), 64f); ((Component)val).transform.SetAsLastSibling(); relationTexts.Add(detail, val); return val; } private static void ReserveRelationSpace(UIStarDetail detail, Text relation) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) RectTransform rectTransform = ((Graphic)detail.typeText).rectTransform; ((Graphic)relation).rectTransform.anchoredPosition = rectTransform.anchoredPosition + new Vector2(0f, -24f); for (int i = 0; i < detail.entries.Count; i++) { UIResAmountEntry val = detail.entries[i]; if ((Object)(object)val != (Object)null) { RectTransform rectTrans = val.rectTrans; rectTrans.anchoredPosition += new Vector2(0f, -64f); } } RectTransform paramGroup = detail.paramGroup; paramGroup.anchoredPosition += new Vector2(0f, -64f); int num = (int)ResourcesTabHeightField.GetValue(detail); ResourcesTabHeightField.SetValue(detail, num + 64); } } internal static class StellarKindMapper { internal static void Apply(StellarKind kind, ref EStarType starType, ref ESpectrType spectrType) { switch (kind) { case StellarKind.MainM: case StellarKind.MainK: case StellarKind.MainG: case StellarKind.MainF: case StellarKind.MainA: case StellarKind.MainB: case StellarKind.MainO: starType = (EStarType)0; spectrType = (ESpectrType)kind; break; case StellarKind.GiantRed: starType = (EStarType)1; spectrType = (ESpectrType)0; break; case StellarKind.GiantYellow: starType = (EStarType)1; spectrType = (ESpectrType)2; break; case StellarKind.GiantWhite: starType = (EStarType)1; spectrType = (ESpectrType)4; break; case StellarKind.GiantBlue: starType = (EStarType)1; spectrType = (ESpectrType)5; break; case StellarKind.WhiteDwarf: starType = (EStarType)2; spectrType = (ESpectrType)7; break; case StellarKind.NeutronStar: starType = (EStarType)3; spectrType = (ESpectrType)7; break; case StellarKind.BlackHole: starType = (EStarType)4; spectrType = (ESpectrType)7; break; } } } internal static class WanderingPlanetCompatibility { private const int MarkerBase = 20590000; private const int MaximumEncodedSystems = 99; private const string FactoryTypeName = "DSPWanderingPlanets.WanderingSystemFactory"; internal static bool TryGetReservedSystemCount(GameDesc gameDesc, out int count) { count = 0; if (gameDesc == null) { return false; } long num = (long)gameDesc.galaxyAlgo - 20590000L; if (num <= 0 || num > 99) { return false; } count = (int)num; return true; } internal static void Initialize(Harmony harmony) { //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Expected O, but got Unknown if (harmony == null) { return; } Type type = AccessTools.TypeByName("DSPWanderingPlanets.WanderingSystemFactory"); if (type == null) { return; } MethodInfo methodInfo = AccessTools.Method(type, "SelectSystemIndexes", new Type[2] { typeof(GalaxyData), typeof(int) }, (Type[])null); MethodInfo methodInfo2 = AccessTools.Method(typeof(WanderingPlanetCompatibility), "SelectSystemIndexesPrefix", (Type[])null, (Type[])null); if (methodInfo == null || methodInfo2 == null) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)"wandering planet III was detected, but its system-selection method could not be patched. Multi-star members may be selected as wandering anchors."); } return; } harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)"Enabled wandering planet III compatibility: wandering anchors skip multi-star members."); } } private static bool SelectSystemIndexesPrefix(GalaxyData __0, int __1, ref int[] __result) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) if (__0 == null || GenerationSession.ActivePlan == null) { return true; } int num = Math.Max(0, __1); List list = new List(num); int num2 = __0.starCount - 1; while (num2 >= 1 && list.Count < num) { StarData val = __0.stars[num2]; if (val != null && (int)val.type == 0 && !GenerationSession.TryGetSystem(val.id, out var _)) { list.Add(num2); } num2--; } list.Sort(); __result = list.ToArray(); return false; } }