Decompiled source of MultiStarSystems v1.3.4

DSPMultiStarSystems.dll

Decompiled 4 days ago
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<Light>() : 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<Light>();
			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<int, MultiStarSystemPlan> byStarId = new Dictionary<int, MultiStarSystemPlan>();

	internal int GalaxySeed;

	internal int PhysicalStarCount;

	internal MultiStarSpacingProfile SpacingProfile = MultiStarSpacingProfile.Expanded;

	internal bool AllowOuterPlanetOwners = true;

	internal List<MultiStarSystemPlan> Systems = new List<MultiStarSystemPlan>();

	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<PlanetData> list = new List<PlanetData>();
		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<int> list = new List<int>();
		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<int> hashSet = new HashSet<int>();
		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<MultiStarSystemPlan> 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<MultiStarSystemPlan> 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<MultiStarSystemPlan> 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<MultiStarSystemPlan> 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<MultiStarSystemPlan> 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<MultiStarSystemPlan> 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<MultiStarSystemPlan> 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<MultiStarSystemPlan> 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<int[]> 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<int> hashSet = new HashSet<int>();
		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<double> OrbitSpeedMultiplier { get; private set; }

	internal static void Initialize(ConfigFile config)
	{
		OrbitSpeedMultiplier = config.Bind<double>("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<int, string> 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<int, string> 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<int, string> 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<int, string> 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<int, string> name, int companion)
	{
		return "与" + name(companion) + "恒星组成双星";
	}

	private static string OtherNames(Func<int, string> name, int count, int excluded)
	{
		List<string> list = new List<string>();
		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<GalaxyData, GalaxyMultiStarRuntime> runtimes = new ConditionalWeakTable<GalaxyData, GalaxyMultiStarRuntime>();

	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<GalaxyData, GalaxyMultiStarRuntime>();
	}
}
internal sealed class GalaxyMultiStarRuntime
{
	private readonly Dictionary<int, RuntimeSystem> systemsByRealStarId = new Dictionary<int, RuntimeSystem>();

	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<int, RuntimeSystem>.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<UIStarDetail, Text> relationTexts = new ConditionalWeakTable<UIStarDetail, Text>();

	[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<Text>(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;
			s