Decompiled source of WanderingPlanetIII v1.1.10

DSPWanderingPlanets.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using CommonAPI;
using CommonAPI.Systems;
using CommonAPI.Systems.ModLocalization;
using HarmonyLib;
using UnityEngine;
using crecheng.DSPModSave;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("DSPWanderingPlanets")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.1.10.0")]
[assembly: AssemblyInformationalVersion("1.1.10")]
[assembly: AssemblyProduct("DSPWanderingPlanets")]
[assembly: AssemblyTitle("DSPWanderingPlanets")]
[assembly: AssemblyVersion("1.1.10.0")]
namespace DSPWanderingPlanets;

internal sealed class DeterministicRandom
{
	private uint state;

	internal uint State
	{
		get
		{
			return state;
		}
		set
		{
			state = ((value == 0) ? 1831565813u : value);
		}
	}

	internal DeterministicRandom(uint seed)
	{
		state = ((seed == 0) ? 1831565813u : seed);
	}

	private DeterministicRandom(uint state, bool clone)
	{
		this.state = state;
	}

	internal DeterministicRandom Clone()
	{
		return new DeterministicRandom(state, clone: true);
	}

	internal uint NextUInt()
	{
		uint num = state;
		num ^= num << 13;
		num ^= num >> 17;
		return state = num ^ (num << 5);
	}

	internal double NextDouble()
	{
		return (double)NextUInt() / 4294967296.0;
	}

	internal int NextInt(int exclusiveMaximum)
	{
		if (exclusiveMaximum <= 0)
		{
			throw new ArgumentOutOfRangeException("exclusiveMaximum");
		}
		return (int)(NextUInt() % (uint)exclusiveMaximum);
	}

	internal int NextInt(int minimum, int exclusiveMaximum)
	{
		if (exclusiveMaximum <= minimum)
		{
			throw new ArgumentOutOfRangeException("exclusiveMaximum");
		}
		return minimum + NextInt(exclusiveMaximum - minimum);
	}
}
internal static class GenerationMarker
{
	private const int MarkerBase = 20590000;

	private const int MaximumEncodedSystems = 99;

	private const int MaximumStarCount = 128;

	internal static bool TryGetSystemCount(GameDesc gameDesc, out int count)
	{
		count = ((gameDesc != null) ? (gameDesc.galaxyAlgo - 20590000) : 0);
		if (count > 0)
		{
			return count <= 99;
		}
		return false;
	}

	internal static int MarkNewGame(GameDesc gameDesc)
	{
		if (gameDesc == null)
		{
			return 0;
		}
		if (TryGetSystemCount(gameDesc, out var count))
		{
			return count;
		}
		int systemCount = ModConfig.GetSystemCount(gameDesc.galaxySeed);
		int val = Math.Max(0, 128 - gameDesc.starCount);
		int num = Math.Min(systemCount, val);
		if (num <= 0)
		{
			return 0;
		}
		gameDesc.starCount += num;
		gameDesc.galaxyAlgo = 20590000 + num;
		return num;
	}
}
[HarmonyPatch]
internal static class GalaxyGenerationPatches
{
	internal static void ValidateTargets()
	{
		MethodInfo methodInfo = AccessTools.Method(typeof(GameData), "NewGame", new Type[1] { typeof(GameDesc) }, (Type[])null);
		MethodInfo methodInfo2 = AccessTools.Method(typeof(UniverseGen), "CreateGalaxy", new Type[1] { typeof(GameDesc) }, (Type[])null);
		if (methodInfo == null || methodInfo.ReturnType != typeof(bool))
		{
			throw new MissingMethodException("GameData.NewGame(GameDesc) has changed.");
		}
		if (methodInfo2 == null || methodInfo2.ReturnType != typeof(GalaxyData))
		{
			throw new MissingMethodException("UniverseGen.CreateGalaxy(GameDesc) has changed.");
		}
	}

	[HarmonyPrefix]
	[HarmonyPriority(800)]
	[HarmonyPatch(typeof(GameData), "NewGame")]
	private static void GameData_NewGame_Prefix(GameDesc _gameDesc)
	{
		int num = GenerationMarker.MarkNewGame(_gameDesc);
		if (num > 0)
		{
			Plugin.Log.LogInfo((object)("Reserved " + num + " wandering-system star IDs for the new universe."));
		}
	}

	[HarmonyPostfix]
	[HarmonyPriority(0)]
	[HarmonyAfter(new string[] { "Zincon.DSPAddPlanetMoon2Patch", "Zincon.CustomCreateBirthStarLite" })]
	[HarmonyPatch(typeof(UniverseGen), "CreateGalaxy")]
	private static void UniverseGen_CreateGalaxy_Postfix(GameDesc gameDesc, GalaxyData __result)
	{
		if (__result != null && GenerationMarker.TryGetSystemCount(gameDesc, out var count))
		{
			int num = Math.Min(count, Math.Max(0, __result.starCount - 1));
			if (num > 0)
			{
				WanderingSystemFactory.TransformGalaxy(__result, gameDesc, num);
			}
		}
	}
}
internal static class ModConfig
{
	private const int MaximumSupportedSystems = 32;

	internal static ConfigEntry<double> SpeedMetersPerSecond { get; private set; }

	internal static ConfigEntry<int> MinimumSystemCount { get; private set; }

	internal static ConfigEntry<int> MaximumSystemCount { get; private set; }

	internal static ConfigEntry<bool> StartInWanderingSystem { get; private set; }

	internal static ConfigEntry<float> UnipolarMagnetChance { get; private set; }

	internal static ConfigEntry<double> MinimumWormholeHours { get; private set; }

	internal static ConfigEntry<double> MaximumWormholeHours { get; private set; }

	internal static double LegacyReplaySpeedMetersPerSecond { get; private set; }

	internal static void Initialize(ConfigFile config)
	{
		//IL_0035: Unknown result type (might be due to invalid IL or missing references)
		//IL_003f: Expected O, but got Unknown
		//IL_007c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0086: Expected O, but got Unknown
		//IL_0102: Unknown result type (might be due to invalid IL or missing references)
		//IL_010c: Expected O, but got Unknown
		//IL_0146: Unknown result type (might be due to invalid IL or missing references)
		//IL_0150: Expected O, but got Unknown
		//IL_0173: Unknown result type (might be due to invalid IL or missing references)
		//IL_017d: Expected O, but got Unknown
		//IL_01a0: Unknown result type (might be due to invalid IL or missing references)
		//IL_01aa: Expected O, but got Unknown
		//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
		//IL_01fd: Expected O, but got Unknown
		SpeedMetersPerSecond = config.Bind<double>("Movement", "SpeedMetersPerSecond", 600.0, new ConfigDescription("Wandering-system travel speed in DSP universe metres per second.", (AcceptableValueBase)(object)new AcceptableValueRange<double>(1.0, 1000000.0), Array.Empty<object>()));
		double value = SpeedMetersPerSecond.Value;
		LegacyReplaySpeedMetersPerSecond = config.Bind<double>("Migration", "LegacyReplaySpeedMetersPerSecond", value, new ConfigDescription("Recorded 1.0.x speed used only to preserve old-save positions during migration.", (AcceptableValueBase)(object)new AcceptableValueRange<double>(1.0, 1000000.0), Array.Empty<object>())).Value;
		if (Math.Abs(SpeedMetersPerSecond.Value - 1200.0) < 0.001)
		{
			SpeedMetersPerSecond.Value = 600.0;
			config.Save();
		}
		MinimumWormholeHours = config.Bind<double>("Movement", "MinimumWormholeHours", 2.0, new ConfigDescription("Minimum in-game hours between random wormholes for each wandering system.", (AcceptableValueBase)(object)new AcceptableValueRange<double>(0.05, 1000.0), Array.Empty<object>()));
		MaximumWormholeHours = config.Bind<double>("Movement", "MaximumWormholeHours", 6.0, new ConfigDescription("Maximum in-game hours between random wormholes for each wandering system.", (AcceptableValueBase)(object)new AcceptableValueRange<double>(0.05, 1000.0), Array.Empty<object>()));
		MinimumSystemCount = config.Bind<int>("Generation", "MinimumSystemCount", 3, new ConfigDescription("Minimum wandering systems in a new save. This is stored in the save's galaxy marker.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 32), Array.Empty<object>()));
		MaximumSystemCount = config.Bind<int>("Generation", "MaximumSystemCount", 8, new ConfigDescription("Maximum wandering systems in a new save. This is stored in the save's galaxy marker.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 32), Array.Empty<object>()));
		StartInWanderingSystem = config.Bind<bool>("Generation", "StartInWanderingSystem", true, "Start new saves on the main planet of a wandering system. Disable to preserve the vanilla birth system.");
		UnipolarMagnetChance = config.Bind<float>("Resources", "UnipolarMagnetChance", 0.25f, new ConfigDescription("Chance for each solid body in a wandering system to receive one unipolar-magnet cluster.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
	}

	internal static int GetSystemCount(int galaxySeed)
	{
		int num = MinimumSystemCount.Value;
		int num2 = MaximumSystemCount.Value;
		if (num > num2)
		{
			int num3 = num;
			num = num2;
			num2 = num3;
		}
		if (num == num2)
		{
			return num;
		}
		DeterministicRandom deterministicRandom = new DeterministicRandom((uint)(galaxySeed ^ 0x57414E44));
		return num + deterministicRandom.NextInt(num2 - num + 1);
	}

	internal static void GetWormholeIntervalSeconds(out double minimum, out double maximum)
	{
		minimum = MinimumWormholeHours.Value * 3600.0;
		maximum = MaximumWormholeHours.Value * 3600.0;
		if (minimum > maximum)
		{
			double num = minimum;
			minimum = maximum;
			maximum = num;
		}
	}
}
internal static class MotionController
{
	private sealed class RuntimeGalaxy
	{
		internal GalaxyData Galaxy { get; }

		internal int[] SystemIndexes { get; }

		internal bool[] IsSystemIndex { get; }

		internal Point3d[] Targets { get; }

		internal MotionTrack[] Tracks { get; }

		internal Point3d[] NextFrameOffsets { get; }

		internal Dictionary<int, int> TrackByStarIndex { get; }

		internal double Speed { get; set; }

		internal RuntimeGalaxy(GalaxyData galaxy, int[] systemIndexes, bool[] isSystemIndex, Point3d[] targets, MotionTrack[] tracks, double speed)
		{
			Galaxy = galaxy;
			SystemIndexes = systemIndexes;
			IsSystemIndex = isSystemIndex;
			Targets = targets;
			Tracks = tracks;
			NextFrameOffsets = new Point3d[tracks.Length];
			Speed = speed;
			TrackByStarIndex = new Dictionary<int, int>();
			for (int i = 0; i < systemIndexes.Length; i++)
			{
				TrackByStarIndex[systemIndexes[i]] = i;
			}
		}
	}

	private const int SaveVersion = 1;

	private const double SystemWarpLightYearsPerSecond = 0.25;

	private const double WarpSteeringRadiansPerSecond = Math.PI / 4.0;

	private static readonly object SyncRoot = new object();

	private static readonly Dictionary<GalaxyData, RuntimeGalaxy> Galaxies = new Dictionary<GalaxyData, RuntimeGalaxy>();

	private static readonly Dictionary<int, MotionTrackState> PendingStates = new Dictionary<int, MotionTrackState>();

	private static StarData activePlayerWarpStar;

	private static MotionTrack activePlayerWarpTrack;

	internal static void Register(GalaxyData galaxy, int[] systemIndexes)
	{
		//IL_007a: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
		if (galaxy == null || systemIndexes == null || systemIndexes.Length == 0)
		{
			return;
		}
		bool[] array = new bool[galaxy.starCount];
		foreach (int num in systemIndexes)
		{
			if (num <= 0 || num >= galaxy.starCount)
			{
				throw new ArgumentOutOfRangeException("systemIndexes");
			}
			array[num] = true;
		}
		Point3d[] array2 = new Point3d[galaxy.starCount - systemIndexes.Length];
		int num2 = 0;
		for (int j = 0; j < galaxy.starCount; j++)
		{
			if (!array[j])
			{
				array2[num2++] = ToPoint(galaxy.stars[j].uPosition);
			}
		}
		MotionTrack[] array3 = new MotionTrack[systemIndexes.Length];
		double configuredSpeed = GetConfiguredSpeed();
		double metersPerSecond = Math.Max(1.0, ModConfig.LegacyReplaySpeedMetersPerSecond);
		for (int k = 0; k < array3.Length; k++)
		{
			StarData val = galaxy.stars[systemIndexes[k]];
			array3[k] = new MotionTrack(ToPoint(val.uPosition), (uint)(val.seed ^ galaxy.seed ^ 0x54524156));
			array3[k].ResetLegacy(array2, metersPerSecond, 2400000.0);
		}
		RuntimeGalaxy runtimeGalaxy = new RuntimeGalaxy(galaxy, (int[])systemIndexes.Clone(), array, array2, array3, configuredSpeed);
		lock (SyncRoot)
		{
			Galaxies.Clear();
			Galaxies.Add(galaxy, runtimeGalaxy);
			activePlayerWarpStar = null;
			activePlayerWarpTrack = null;
			ApplyPendingStates(runtimeGalaxy);
		}
	}

	internal static void BeforePoseUpdate(GalaxyData galaxy, double time)
	{
		//IL_014b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0150: Unknown result type (might be due to invalid IL or missing references)
		//IL_0167: 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_0192: Unknown result type (might be due to invalid IL or missing references)
		//IL_019a: Unknown result type (might be due to invalid IL or missing references)
		//IL_019f: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
		//IL_01fa: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ff: Unknown result type (might be due to invalid IL or missing references)
		RuntimeGalaxy value;
		lock (SyncRoot)
		{
			if (!Galaxies.TryGetValue(galaxy, out value))
			{
				return;
			}
		}
		double configuredSpeed = GetConfiguredSpeed();
		if (Math.Abs(configuredSpeed - value.Speed) > 0.001)
		{
			value.Speed = configuredSpeed;
			for (int i = 0; i < value.Tracks.Length; i++)
			{
				value.Tracks[i].SetCruiseSpeed(configuredSpeed);
			}
		}
		ModConfig.GetWormholeIntervalSeconds(out var minimum, out var maximum);
		int num = ((GameMain.localStar == null) ? (-1) : GameMain.localStar.index);
		for (int j = 0; j < value.Tracks.Length; j++)
		{
			MotionTrack motionTrack = value.Tracks[j];
			motionTrack.SetWormholeIntervalRange(minimum, maximum);
			if (motionTrack.IsWarping)
			{
				motionTrack.SetWarpSpeed(GetSystemWarpSpeed());
			}
			bool holdWormhole = num == value.SystemIndexes[j];
			motionTrack.AdvanceTo(Math.Max(0.0, time), value.Targets, holdWormhole);
			Point3d position = motionTrack.Position;
			Point3d point3d = motionTrack.Direction * (motionTrack.ActiveSpeed / 60.0);
			value.NextFrameOffsets[j] = point3d;
			StarData val = galaxy.stars[value.SystemIndexes[j]];
			val.uPosition = ToVector(position);
			val.position = ToVector(position / 2400000.0);
			ref AstroData reference = ref galaxy.astrosData[val.astroId];
			reference.id = val.astroId;
			reference.type = (EAstroType)1;
			reference.uPos = val.uPosition;
			reference.uPosNext = ToVector(position + point3d);
			if (galaxy.graphNodes != null && val.index >= 0 && val.index < galaxy.graphNodes.Length && galaxy.graphNodes[val.index] != null)
			{
				galaxy.graphNodes[val.index].pos = val.position;
			}
		}
	}

	internal static void AfterPoseUpdate(GalaxyData galaxy)
	{
		//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
		RuntimeGalaxy value;
		lock (SyncRoot)
		{
			if (!Galaxies.TryGetValue(galaxy, out value))
			{
				return;
			}
		}
		for (int i = 0; i < value.Tracks.Length; i++)
		{
			Point3d point3d = value.NextFrameOffsets[i];
			StarData val = galaxy.stars[value.SystemIndexes[i]];
			for (int j = 0; j < val.planetCount; j++)
			{
				PlanetData val2 = val.planets[j];
				if (val2 != null)
				{
					val2.uPositionNext.x += point3d.X;
					val2.uPositionNext.y += point3d.Y;
					val2.uPositionNext.z += point3d.Z;
					galaxy.astrosData[val2.id].uPosNext = val2.uPositionNext;
				}
			}
		}
	}

	internal static bool TryToggleLocalSystemWarp(Player player)
	{
		//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
		if (player == null)
		{
			return false;
		}
		StarData localPlayerStar = GetLocalPlayerStar(player);
		if (localPlayerStar?.galaxy == null)
		{
			return false;
		}
		MotionTrack motionTrack;
		lock (SyncRoot)
		{
			if (!Galaxies.TryGetValue(localPlayerStar.galaxy, out var value) || !value.TrackByStarIndex.TryGetValue(localPlayerStar.index, out var value2))
			{
				return false;
			}
			motionTrack = value.Tracks[value2];
		}
		if (motionTrack.IsWarping)
		{
			motionTrack.StopWarp();
			activePlayerWarpStar = null;
			activePlayerWarpTrack = null;
			Plugin.Log.LogInfo((object)"Planetary warp disengaged.");
			return true;
		}
		if (player.planetData?.star != localPlayerStar || (int)player.movementState != 0)
		{
			return false;
		}
		if (GameMain.history == null || !PrototypeRegistry.IsPlanetaryWarpTechUnlocked(GameMain.history) || player.mecha == null || !PrototypeRegistry.TryConsumePlanetaryWarper(player))
		{
			return false;
		}
		double systemWarpSpeed = GetSystemWarpSpeed();
		if (!motionTrack.StartWarp(systemWarpSpeed))
		{
			return false;
		}
		activePlayerWarpStar = localPlayerStar;
		activePlayerWarpTrack = motionTrack;
		Plugin.Log.LogInfo((object)("Planetary warp engaged at 0.25 ly/s (" + systemWarpSpeed + " m/s)."));
		return true;
	}

	internal static bool TrySteerLocalSystemWarp(Player player, Point3d screenRight, Point3d screenUp, double horizontal, double vertical, double deltaTime)
	{
		if (player == null || deltaTime <= 0.0 || (Math.Abs(horizontal) < 0.001 && Math.Abs(vertical) < 0.001))
		{
			return false;
		}
		StarData localPlayerStar = GetLocalPlayerStar(player);
		if (localPlayerStar?.galaxy == null)
		{
			return false;
		}
		lock (SyncRoot)
		{
			if (!Galaxies.TryGetValue(localPlayerStar.galaxy, out var value) || !value.TrackByStarIndex.TryGetValue(localPlayerStar.index, out var value2))
			{
				return false;
			}
			return TrySteerTrack(value.Tracks[value2], screenRight, screenUp, horizontal, vertical, deltaTime);
		}
	}

	internal static bool TrySteerActivePlayerWarp(Point3d screenRight, Point3d screenUp, double horizontal, double vertical, double deltaTime)
	{
		if (deltaTime <= 0.0 || (Math.Abs(horizontal) < 0.001 && Math.Abs(vertical) < 0.001))
		{
			return false;
		}
		lock (SyncRoot)
		{
			if (activePlayerWarpTrack == null || !activePlayerWarpTrack.IsWarping)
			{
				return false;
			}
			return TrySteerTrack(activePlayerWarpTrack, screenRight, screenUp, horizontal, vertical, deltaTime);
		}
	}

	internal static bool IsPlayerSystemWarping()
	{
		lock (SyncRoot)
		{
			return activePlayerWarpTrack != null && activePlayerWarpTrack.IsWarping;
		}
	}

	internal static bool TryGetActivePlayerWarpDirection(out Point3d direction)
	{
		direction = new Point3d(1.0, 0.0, 0.0);
		lock (SyncRoot)
		{
			if (activePlayerWarpTrack == null || !activePlayerWarpTrack.IsWarping)
			{
				return false;
			}
			direction = activePlayerWarpTrack.Direction;
			return direction.Magnitude > 1E-06;
		}
	}

	internal static void RefreshActivePlayerWarp(Player player)
	{
		if (player == null)
		{
			return;
		}
		lock (SyncRoot)
		{
			if (activePlayerWarpTrack == null || !activePlayerWarpTrack.IsWarping)
			{
				activePlayerWarpStar = null;
				activePlayerWarpTrack = null;
				StarData val = player.planetData?.star;
				if (val == null && player == GameMain.mainPlayer)
				{
					val = GameMain.localStar;
				}
				if (val?.galaxy != null && Galaxies.TryGetValue(val.galaxy, out var value) && value.TrackByStarIndex.TryGetValue(val.index, out var value2) && value.Tracks[value2].IsWarping)
				{
					activePlayerWarpStar = val;
					activePlayerWarpTrack = value.Tracks[value2];
				}
			}
		}
	}

	internal static bool TryGetLocalWarp(Player player, out Point3d direction, out double speed)
	{
		direction = new Point3d(1.0, 0.0, 0.0);
		speed = 0.0;
		StarData localPlayerStar = GetLocalPlayerStar(player);
		if (localPlayerStar?.galaxy == null)
		{
			return false;
		}
		lock (SyncRoot)
		{
			if (!Galaxies.TryGetValue(localPlayerStar.galaxy, out var value) || !value.TrackByStarIndex.TryGetValue(localPlayerStar.index, out var value2))
			{
				return false;
			}
			MotionTrack motionTrack = value.Tracks[value2];
			if (!motionTrack.IsWarping)
			{
				return false;
			}
			direction = motionTrack.Direction;
			speed = motionTrack.ActiveSpeed;
			return true;
		}
	}

	internal static bool IsLocalSystemWarping(Player player)
	{
		StarData localPlayerStar = GetLocalPlayerStar(player);
		if (localPlayerStar?.galaxy == null)
		{
			return false;
		}
		lock (SyncRoot)
		{
			RuntimeGalaxy value;
			int value2;
			return Galaxies.TryGetValue(localPlayerStar.galaxy, out value) && value.TrackByStarIndex.TryGetValue(localPlayerStar.index, out value2) && value.Tracks[value2].IsWarping;
		}
	}

	internal static bool IsAnySystemWarping()
	{
		lock (SyncRoot)
		{
			foreach (RuntimeGalaxy value in Galaxies.Values)
			{
				for (int i = 0; i < value.Tracks.Length; i++)
				{
					if (value.Tracks[i].IsWarping)
					{
						return true;
					}
				}
			}
			return false;
		}
	}

	internal static bool IsWanderingPlanet(PlanetData planet)
	{
		return IsWanderingStar(planet?.star);
	}

	internal static bool IsWanderingStar(StarData star)
	{
		if (star?.galaxy == null)
		{
			return false;
		}
		lock (SyncRoot)
		{
			RuntimeGalaxy value;
			return Galaxies.TryGetValue(star.galaxy, out value) && star.index >= 0 && star.index < value.IsSystemIndex.Length && value.IsSystemIndex[star.index];
		}
	}

	private static double GetSystemWarpSpeed()
	{
		return 600000.0;
	}

	private static bool TrySteerTrack(MotionTrack track, Point3d screenRight, Point3d screenUp, double horizontal, double vertical, double deltaTime)
	{
		double num = Math.Min(1.0, Math.Sqrt(horizontal * horizontal + vertical * vertical));
		Point3d steeringDirection = screenRight * horizontal + screenUp * vertical;
		double radians = Math.PI / 4.0 * Math.Min(deltaTime, 0.1) * num;
		return track.SteerWarp(steeringDirection, radians);
	}

	private static StarData GetLocalPlayerStar(Player player)
	{
		if (player == GameMain.mainPlayer && activePlayerWarpStar != null)
		{
			if (activePlayerWarpTrack != null && activePlayerWarpTrack.IsWarping)
			{
				return activePlayerWarpStar;
			}
			activePlayerWarpStar = null;
			activePlayerWarpTrack = null;
		}
		StarData val = ((player == null) ? null : player.planetData?.star);
		if (val == null && player == GameMain.mainPlayer)
		{
			val = GameMain.localStar;
		}
		return val;
	}

	internal static void Export(BinaryWriter writer)
	{
		writer.Write(1);
		lock (SyncRoot)
		{
			RuntimeGalaxy currentRuntime = GetCurrentRuntime();
			if (currentRuntime == null)
			{
				writer.Write(0);
				return;
			}
			writer.Write(currentRuntime.Tracks.Length);
			for (int i = 0; i < currentRuntime.Tracks.Length; i++)
			{
				writer.Write(currentRuntime.SystemIndexes[i]);
				WriteState(writer, currentRuntime.Tracks[i].CaptureState());
			}
		}
	}

	internal static void Import(BinaryReader reader)
	{
		int num = reader.ReadInt32();
		if (num != 1)
		{
			throw new InvalidDataException("Unsupported wandering-planet motion save version " + num + ".");
		}
		int num2 = reader.ReadInt32();
		if (num2 < 0 || num2 > 99)
		{
			throw new InvalidDataException("Invalid wandering-system motion count.");
		}
		lock (SyncRoot)
		{
			PendingStates.Clear();
			for (int i = 0; i < num2; i++)
			{
				int key = reader.ReadInt32();
				PendingStates[key] = ReadState(reader);
			}
			RuntimeGalaxy currentRuntime = GetCurrentRuntime();
			if (currentRuntime != null)
			{
				ApplyPendingStates(currentRuntime);
			}
		}
	}

	internal static void IntoOtherSave()
	{
		lock (SyncRoot)
		{
			PendingStates.Clear();
			activePlayerWarpStar = null;
			activePlayerWarpTrack = null;
			RuntimeGalaxy currentRuntime = GetCurrentRuntime();
			if (currentRuntime == null)
			{
				return;
			}
			double configuredSpeed = GetConfiguredSpeed();
			double num = Math.Max(0.0, GameMain.gameTime);
			ModConfig.GetWormholeIntervalSeconds(out var minimum, out var maximum);
			for (int i = 0; i < currentRuntime.Tracks.Length; i++)
			{
				MotionTrack motionTrack = currentRuntime.Tracks[i];
				if (num <= 0.001)
				{
					motionTrack.Reset(currentRuntime.Targets, configuredSpeed, 2400000.0, minimum, maximum);
					continue;
				}
				motionTrack.ResetLegacy(currentRuntime.Targets, Math.Max(1.0, ModConfig.LegacyReplaySpeedMetersPerSecond), 2400000.0);
				motionTrack.AdvanceTo(num, currentRuntime.Targets, holdWormhole: false);
				motionTrack.EnableWormholes(configuredSpeed, minimum, maximum);
			}
			currentRuntime.Speed = configuredSpeed;
		}
	}

	internal static void Clear()
	{
		lock (SyncRoot)
		{
			Galaxies.Clear();
			PendingStates.Clear();
			activePlayerWarpStar = null;
			activePlayerWarpTrack = null;
		}
	}

	private static RuntimeGalaxy GetCurrentRuntime()
	{
		GalaxyData galaxy = GameMain.galaxy;
		if (galaxy != null && Galaxies.TryGetValue(galaxy, out var value))
		{
			return value;
		}
		using (Dictionary<GalaxyData, RuntimeGalaxy>.ValueCollection.Enumerator enumerator = Galaxies.Values.GetEnumerator())
		{
			if (enumerator.MoveNext())
			{
				return enumerator.Current;
			}
		}
		return null;
	}

	private static void ApplyPendingStates(RuntimeGalaxy runtime)
	{
		if (PendingStates.Count == 0)
		{
			return;
		}
		ModConfig.GetWormholeIntervalSeconds(out var minimum, out var maximum);
		double configuredSpeed = GetConfiguredSpeed();
		for (int i = 0; i < runtime.Tracks.Length; i++)
		{
			if (PendingStates.TryGetValue(runtime.SystemIndexes[i], out var value))
			{
				runtime.Tracks[i].RestoreState(value, runtime.Targets, 2400000.0, minimum, maximum);
				runtime.Tracks[i].SetCruiseSpeed(configuredSpeed);
				PendingStates.Remove(runtime.SystemIndexes[i]);
			}
		}
		runtime.Speed = configuredSpeed;
	}

	private static void WriteState(BinaryWriter writer, MotionTrackState state)
	{
		WritePoint(writer, state.Position);
		WritePoint(writer, state.Direction);
		writer.Write(state.TargetIndex);
		writer.Write(state.NextRandomRetargetTime);
		writer.Write(state.NextWormholeTime);
		writer.Write(state.CurrentTime);
		writer.Write(state.CruiseSpeed);
		writer.Write(state.IsWarping);
		writer.Write(state.WarpSpeed);
		writer.Write(state.RandomState);
	}

	private static MotionTrackState ReadState(BinaryReader reader)
	{
		return new MotionTrackState
		{
			Position = ReadPoint(reader),
			Direction = ReadPoint(reader),
			TargetIndex = reader.ReadInt32(),
			NextRandomRetargetTime = reader.ReadDouble(),
			NextWormholeTime = reader.ReadDouble(),
			CurrentTime = reader.ReadDouble(),
			CruiseSpeed = reader.ReadDouble(),
			IsWarping = reader.ReadBoolean(),
			WarpSpeed = reader.ReadDouble(),
			RandomState = reader.ReadUInt32()
		};
	}

	private static void WritePoint(BinaryWriter writer, Point3d point)
	{
		writer.Write(point.X);
		writer.Write(point.Y);
		writer.Write(point.Z);
	}

	private static Point3d ReadPoint(BinaryReader reader)
	{
		return new Point3d(reader.ReadDouble(), reader.ReadDouble(), reader.ReadDouble());
	}

	private static double GetConfiguredSpeed()
	{
		return Math.Max(1.0, ModConfig.SpeedMetersPerSecond.Value);
	}

	private static Point3d ToPoint(VectorLF3 value)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_000c: Unknown result type (might be due to invalid IL or missing references)
		return new Point3d(value.x, value.y, value.z);
	}

	private static VectorLF3 ToVector(Point3d value)
	{
		//IL_0012: Unknown result type (might be due to invalid IL or missing references)
		return new VectorLF3(value.X, value.Y, value.Z);
	}
}
[HarmonyPatch(typeof(GalaxyData), "UpdatePoses")]
internal static class MotionPatches
{
	internal static void ValidateTargets()
	{
		MethodInfo methodInfo = AccessTools.Method(typeof(GalaxyData), "UpdatePoses", new Type[1] { typeof(double) }, (Type[])null);
		if (methodInfo == null || methodInfo.ReturnType != typeof(void))
		{
			throw new MissingMethodException("GalaxyData.UpdatePoses(double) has changed.");
		}
	}

	[HarmonyPrefix]
	[HarmonyPriority(800)]
	[HarmonyBefore(new string[] { "Zincon.DSPAddPlanetMoon2Patch" })]
	private static void Prefix(GalaxyData __instance, double time)
	{
		MotionController.BeforePoseUpdate(__instance, time);
	}

	[HarmonyPostfix]
	[HarmonyPriority(0)]
	private static void Postfix(GalaxyData __instance)
	{
		MotionController.AfterPoseUpdate(__instance);
	}
}
internal struct Point3d
{
	internal double X;

	internal double Y;

	internal double Z;

	internal double SqrMagnitude => X * X + Y * Y + Z * Z;

	internal double Magnitude => Math.Sqrt(SqrMagnitude);

	internal Point3d Normalized
	{
		get
		{
			double magnitude = Magnitude;
			if (!(magnitude <= 1E-12))
			{
				return this / magnitude;
			}
			return default(Point3d);
		}
	}

	internal Point3d(double x, double y, double z)
	{
		X = x;
		Y = y;
		Z = z;
	}

	internal static double Dot(Point3d left, Point3d right)
	{
		return left.X * right.X + left.Y * right.Y + left.Z * right.Z;
	}

	public static Point3d operator +(Point3d left, Point3d right)
	{
		return new Point3d(left.X + right.X, left.Y + right.Y, left.Z + right.Z);
	}

	public static Point3d operator -(Point3d left, Point3d right)
	{
		return new Point3d(left.X - right.X, left.Y - right.Y, left.Z - right.Z);
	}

	public static Point3d operator *(Point3d value, double scale)
	{
		return new Point3d(value.X * scale, value.Y * scale, value.Z * scale);
	}

	public static Point3d operator /(Point3d value, double scale)
	{
		return new Point3d(value.X / scale, value.Y / scale, value.Z / scale);
	}
}
internal sealed class MotionTrackState
{
	internal Point3d Position;

	internal Point3d Direction;

	internal int TargetIndex;

	internal double NextRandomRetargetTime;

	internal double NextWormholeTime;

	internal double CurrentTime;

	internal double CruiseSpeed;

	internal bool IsWarping;

	internal double WarpSpeed;

	internal uint RandomState;
}
internal sealed class MotionTrack
{
	internal const double MinimumRandomRetargetSeconds = 1800.0;

	private const double ForwardConeCosine = 0.5;

	private const double Epsilon = 1E-07;

	private const int WormholeDirectionSamples = 12;

	private readonly Point3d initialPosition;

	private readonly uint seed;

	private DeterministicRandom random;

	private double cruiseSpeed;

	private double warpSpeed;

	private double lightYear;

	private double currentTime;

	private double minimumWormholeSeconds;

	private double maximumWormholeSeconds;

	internal Point3d Position { get; private set; }

	internal Point3d Direction { get; private set; }

	internal int TargetIndex { get; private set; }

	internal double NextRandomRetargetTime { get; private set; }

	internal double NextWormholeTime { get; private set; }

	internal double CurrentTime => currentTime;

	internal bool IsWarping { get; private set; }

	internal double ActiveSpeed
	{
		get
		{
			if (!IsWarping)
			{
				return cruiseSpeed;
			}
			return warpSpeed;
		}
	}

	internal MotionTrack(Point3d initialPosition, uint seed)
	{
		this.initialPosition = initialPosition;
		this.seed = seed;
		Position = initialPosition;
		Direction = new Point3d(1.0, 0.0, 0.0);
		TargetIndex = -1;
	}

	internal void Reset(IReadOnlyList<Point3d> targets, double metersPerSecond, double lightYearInMeters)
	{
		Reset(targets, metersPerSecond, lightYearInMeters, 7200.0, 21600.0);
	}

	internal void Reset(IReadOnlyList<Point3d> targets, double metersPerSecond, double lightYearInMeters, double minimumWormholeIntervalSeconds, double maximumWormholeIntervalSeconds)
	{
		ResetLegacy(targets, metersPerSecond, lightYearInMeters);
		SetWormholeIntervalRange(minimumWormholeIntervalSeconds, maximumWormholeIntervalSeconds);
		ScheduleWormhole();
	}

	internal void ResetLegacy(IReadOnlyList<Point3d> targets, double metersPerSecond, double lightYearInMeters)
	{
		ValidateParameters(targets, metersPerSecond, lightYearInMeters);
		cruiseSpeed = metersPerSecond;
		warpSpeed = 0.0;
		lightYear = lightYearInMeters;
		currentTime = 0.0;
		Position = initialPosition;
		Direction = new Point3d(1.0, 0.0, 0.0);
		TargetIndex = -1;
		IsWarping = false;
		random = new DeterministicRandom(seed);
		SelectTarget(targets, respectHeading: false, -1);
		ScheduleRandomRetarget();
		NextWormholeTime = double.PositiveInfinity;
	}

	internal void EnableWormholes(double metersPerSecond, double minimumWormholeIntervalSeconds, double maximumWormholeIntervalSeconds)
	{
		SetCruiseSpeed(metersPerSecond);
		SetWormholeIntervalRange(minimumWormholeIntervalSeconds, maximumWormholeIntervalSeconds);
		ScheduleWormhole();
	}

	internal void SetCruiseSpeed(double metersPerSecond)
	{
		if (metersPerSecond <= 0.0)
		{
			throw new ArgumentOutOfRangeException("metersPerSecond");
		}
		cruiseSpeed = metersPerSecond;
	}

	internal void SetWormholeIntervalRange(double minimum, double maximum)
	{
		if (minimum <= 0.0 || maximum <= 0.0)
		{
			throw new ArgumentOutOfRangeException("minimum");
		}
		minimumWormholeSeconds = Math.Min(minimum, maximum);
		maximumWormholeSeconds = Math.Max(minimum, maximum);
	}

	internal bool StartWarp(double metersPerSecond)
	{
		if (IsWarping || metersPerSecond <= 0.0)
		{
			return false;
		}
		warpSpeed = metersPerSecond;
		IsWarping = true;
		return true;
	}

	internal bool StopWarp()
	{
		if (!IsWarping)
		{
			return false;
		}
		IsWarping = false;
		warpSpeed = 0.0;
		return true;
	}

	internal bool SetWarpSpeed(double metersPerSecond)
	{
		if (!IsWarping || metersPerSecond <= 0.0)
		{
			return false;
		}
		warpSpeed = metersPerSecond;
		return true;
	}

	internal bool SteerWarp(Point3d steeringDirection, double radians)
	{
		if (!IsWarping || radians <= 1E-07)
		{
			return false;
		}
		Point3d point3d = steeringDirection - Direction * Point3d.Dot(steeringDirection, Direction);
		if (point3d.SqrMagnitude <= 1E-07)
		{
			return false;
		}
		double num = Math.Min(Math.PI / 2.0, radians);
		Direction = (Direction * Math.Cos(num) + point3d.Normalized * Math.Sin(num)).Normalized;
		return true;
	}

	internal void AdvanceTo(double time, IReadOnlyList<Point3d> targets)
	{
		AdvanceTo(time, targets, holdWormhole: false);
	}

	internal void AdvanceTo(double time, IReadOnlyList<Point3d> targets, bool holdWormhole)
	{
		if (time < currentTime - 1E-07)
		{
			double num = time - currentTime;
			NextRandomRetargetTime += num;
			if (!double.IsInfinity(NextWormholeTime))
			{
				NextWormholeTime += num;
			}
			currentTime = Math.Max(0.0, time);
			return;
		}
		int num2 = 0;
		while (currentTime + 1E-07 < time)
		{
			if (++num2 > 100000)
			{
				throw new InvalidOperationException("Wandering motion exceeded its event safety limit.");
			}
			double num3 = time - currentTime;
			Point3d targetOffset = targets[TargetIndex] - Position;
			double activeSpeed = ActiveSpeed;
			double arrivalSeconds = GetArrivalSeconds(targetOffset, activeSpeed);
			if (IsWarping)
			{
				double seconds = Math.Min(arrivalSeconds, num3);
				Move(seconds, activeSpeed);
				FreezeTimers(seconds, freezeRandomRetarget: true, freezeWormhole: true);
				if (arrivalSeconds <= num3 + 1E-07)
				{
					IsWarping = false;
					warpSpeed = 0.0;
					SelectTarget(targets, respectHeading: true, -1);
					ScheduleRandomRetarget();
					ScheduleWormhole();
				}
				continue;
			}
			double val = Math.Max(0.0, NextRandomRetargetTime - currentTime);
			double num4 = (holdWormhole ? double.PositiveInfinity : Math.Max(0.0, NextWormholeTime - currentTime));
			double num5 = Math.Min(arrivalSeconds, Math.Min(val, num4));
			if (num5 > num3 || double.IsInfinity(num5))
			{
				Move(num3, cruiseSpeed);
				if (holdWormhole)
				{
					FreezeTimers(num3, freezeRandomRetarget: false, freezeWormhole: true);
				}
				break;
			}
			Move(num5, cruiseSpeed);
			if (holdWormhole)
			{
				FreezeTimers(num5, freezeRandomRetarget: false, freezeWormhole: true);
			}
			if (num4 <= num5 + 1E-07)
			{
				ExecuteWormhole(targets);
				ScheduleRandomRetarget();
				ScheduleWormhole();
			}
			else
			{
				SelectTarget(targets, respectHeading: true, -1);
				ScheduleRandomRetarget();
			}
		}
	}

	internal double GetMinimumIntervalSeconds()
	{
		return Math.Min(1800.0, 20.0 * lightYear / cruiseSpeed);
	}

	internal double GetMaximumIntervalSeconds()
	{
		return Math.Max(1800.0, 20.0 * lightYear / cruiseSpeed);
	}

	internal MotionTrackState CaptureState()
	{
		return new MotionTrackState
		{
			Position = Position,
			Direction = Direction,
			TargetIndex = TargetIndex,
			NextRandomRetargetTime = NextRandomRetargetTime,
			NextWormholeTime = NextWormholeTime,
			CurrentTime = currentTime,
			CruiseSpeed = cruiseSpeed,
			IsWarping = IsWarping,
			WarpSpeed = warpSpeed,
			RandomState = random.State
		};
	}

	internal void RestoreState(MotionTrackState state, IReadOnlyList<Point3d> targets, double lightYearInMeters, double minimumWormholeIntervalSeconds, double maximumWormholeIntervalSeconds)
	{
		if (state == null || state.TargetIndex < 0 || state.TargetIndex >= targets.Count)
		{
			throw new ArgumentException("Invalid wandering motion state.", "state");
		}
		ValidateParameters(targets, Math.Max(1.0, state.CruiseSpeed), lightYearInMeters);
		Position = state.Position;
		Direction = state.Direction.Normalized;
		if (Direction.SqrMagnitude <= 1E-07)
		{
			Direction = (targets[state.TargetIndex] - Position).Normalized;
		}
		TargetIndex = state.TargetIndex;
		NextRandomRetargetTime = state.NextRandomRetargetTime;
		NextWormholeTime = state.NextWormholeTime;
		currentTime = Math.Max(0.0, state.CurrentTime);
		cruiseSpeed = Math.Max(1.0, state.CruiseSpeed);
		IsWarping = state.IsWarping && state.WarpSpeed > 0.0;
		warpSpeed = (IsWarping ? state.WarpSpeed : 0.0);
		lightYear = lightYearInMeters;
		SetWormholeIntervalRange(minimumWormholeIntervalSeconds, maximumWormholeIntervalSeconds);
		random = new DeterministicRandom(state.RandomState);
	}

	private void Move(double seconds, double metersPerSecond)
	{
		if (!(seconds <= 1E-07))
		{
			Position += Direction * (metersPerSecond * seconds);
			currentTime += seconds;
		}
	}

	private double GetArrivalSeconds(Point3d targetOffset, double metersPerSecond)
	{
		double sqrMagnitude = targetOffset.SqrMagnitude;
		double num = lightYear * lightYear;
		if (sqrMagnitude <= num)
		{
			return 0.0;
		}
		double num2 = Point3d.Dot(targetOffset, Direction);
		if (num2 <= 0.0)
		{
			return double.PositiveInfinity;
		}
		double num3 = Math.Max(0.0, sqrMagnitude - num2 * num2);
		if (num3 > num)
		{
			return double.PositiveInfinity;
		}
		double val = num2 - Math.Sqrt(Math.Max(0.0, num - num3));
		return Math.Max(0.0, val) / metersPerSecond;
	}

	private void FreezeTimers(double seconds, bool freezeRandomRetarget, bool freezeWormhole)
	{
		if (!(seconds <= 1E-07))
		{
			if (freezeRandomRetarget)
			{
				NextRandomRetargetTime += seconds;
			}
			if (freezeWormhole && !double.IsInfinity(NextWormholeTime))
			{
				NextWormholeTime += seconds;
			}
		}
	}

	private void ExecuteWormhole(IReadOnlyList<Point3d> targets)
	{
		int num = random.NextInt(targets.Count);
		Point3d point3d = targets[num];
		Point3d position = point3d + RandomUnitVector() * lightYear;
		double num2 = GetNearestOtherTargetDistanceSquared(position, targets, num);
		for (int i = 1; i < 12; i++)
		{
			Point3d point3d2 = point3d + RandomUnitVector() * lightYear;
			double nearestOtherTargetDistanceSquared = GetNearestOtherTargetDistanceSquared(point3d2, targets, num);
			if (nearestOtherTargetDistanceSquared > num2)
			{
				num2 = nearestOtherTargetDistanceSquared;
				position = point3d2;
			}
		}
		Position = position;
		SelectTarget(targets, respectHeading: false, num);
	}

	private Point3d RandomUnitVector()
	{
		double num = random.NextDouble() * 2.0 - 1.0;
		double num2 = random.NextDouble() * Math.PI * 2.0;
		double num3 = Math.Sqrt(Math.Max(0.0, 1.0 - num * num));
		return new Point3d(num3 * Math.Cos(num2), num, num3 * Math.Sin(num2));
	}

	private static double GetNearestOtherTargetDistanceSquared(Point3d position, IReadOnlyList<Point3d> targets, int excludedIndex)
	{
		double num = double.PositiveInfinity;
		for (int i = 0; i < targets.Count; i++)
		{
			if (i != excludedIndex)
			{
				num = Math.Min(num, (targets[i] - position).SqrMagnitude);
			}
		}
		return num;
	}

	private void SelectTarget(IReadOnlyList<Point3d> targets, bool respectHeading, int additionallyExcludedIndex)
	{
		List<int> list = new List<int>();
		int num = -1;
		double num2 = double.NegativeInfinity;
		int targetIndex = TargetIndex;
		for (int i = 0; i < targets.Count; i++)
		{
			if (i == additionallyExcludedIndex || (respectHeading && i == targetIndex))
			{
				continue;
			}
			Point3d point3d = targets[i] - Position;
			double magnitude = point3d.Magnitude;
			if (!(magnitude <= lightYear + 1E-07))
			{
				Point3d right = point3d / magnitude;
				double num3 = (respectHeading ? Point3d.Dot(Direction, right) : 1.0);
				if (!respectHeading || num3 > 0.5)
				{
					list.Add(i);
				}
				if (num3 > num2)
				{
					num2 = num3;
					num = i;
				}
			}
		}
		if (list.Count > 0)
		{
			TargetIndex = list[random.NextInt(list.Count)];
		}
		else if (num >= 0)
		{
			TargetIndex = num;
		}
		else
		{
			int excludedIndex = ((additionallyExcludedIndex >= 0) ? additionallyExcludedIndex : (respectHeading ? targetIndex : (-1)));
			TargetIndex = FindFarthestTarget(targets, excludedIndex);
		}
		Direction = (targets[TargetIndex] - Position).Normalized;
		if (Direction.SqrMagnitude <= 1E-07)
		{
			Direction = new Point3d(1.0, 0.0, 0.0);
		}
	}

	private int FindFarthestTarget(IReadOnlyList<Point3d> targets, int excludedIndex)
	{
		int num = -1;
		double num2 = double.NegativeInfinity;
		for (int i = 0; i < targets.Count; i++)
		{
			if (i != excludedIndex || targets.Count <= 1)
			{
				double sqrMagnitude = (targets[i] - Position).SqrMagnitude;
				if (sqrMagnitude > num2)
				{
					num2 = sqrMagnitude;
					num = i;
				}
			}
		}
		if (num < 0)
		{
			return 0;
		}
		return num;
	}

	private void ScheduleRandomRetarget()
	{
		double minimumIntervalSeconds = GetMinimumIntervalSeconds();
		double maximumIntervalSeconds = GetMaximumIntervalSeconds();
		NextRandomRetargetTime = currentTime + minimumIntervalSeconds + random.NextDouble() * (maximumIntervalSeconds - minimumIntervalSeconds);
	}

	private void ScheduleWormhole()
	{
		NextWormholeTime = currentTime + minimumWormholeSeconds + random.NextDouble() * (maximumWormholeSeconds - minimumWormholeSeconds);
	}

	private static void ValidateParameters(IReadOnlyList<Point3d> targets, double metersPerSecond, double lightYearInMeters)
	{
		if (targets == null || targets.Count == 0)
		{
			throw new ArgumentException("At least one target star is required.", "targets");
		}
		if (metersPerSecond <= 0.0 || lightYearInMeters <= 0.0)
		{
			throw new ArgumentOutOfRangeException("metersPerSecond");
		}
	}
}
[BepInPlugin("Zincon.DSPWanderingPlanets", "wandering planet III", "1.1.10")]
[BepInProcess("DSPGAME.exe")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInIncompatibility("dsp.galactic-scale.2")]
[CommonAPISubmoduleDependency(new string[] { "ProtoRegistry" })]
public sealed class Plugin : BaseUnityPlugin, IModCanSave
{
	public const string PluginGuid = "Zincon.DSPWanderingPlanets";

	public const string PluginName = "wandering planet III";

	public const string PluginVersion = "1.1.10";

	public const string NestedMoonsGuid = "Zincon.DSPNestedMoons";

	public const string DspAddPlanetGuid = "Zincon.DSPAddPlanetMoon2Patch";

	public const string GalacticScaleGuid = "dsp.galactic-scale.2";

	public const string CommonApiGuid = "dsp.common-api.CommonAPI";

	private Harmony harmony;

	internal static ManualLogSource Log { get; private set; }

	private void Awake()
	{
		//IL_0035: Unknown result type (might be due to invalid IL or missing references)
		//IL_003f: Expected O, but got Unknown
		Log = ((BaseUnityPlugin)this).Logger;
		try
		{
			ModConfig.Initialize(((BaseUnityPlugin)this).Config);
			PrototypeRegistry.Register();
			GalaxyGenerationPatches.ValidateTargets();
			MotionPatches.ValidateTargets();
			VisualPatches.ValidateTargets();
			WarpPatches.ValidateTargets();
			harmony = new Harmony("Zincon.DSPWanderingPlanets");
			harmony.PatchAll(typeof(Plugin).Assembly);
			((BaseUnityPlugin)this).Logger.LogInfo((object)"wandering planet III 1.1.10 loaded. New universes will include deterministic wandering systems.");
		}
		catch (Exception ex)
		{
			Harmony obj = harmony;
			if (obj != null)
			{
				obj.UnpatchSelf();
			}
			harmony = null;
			((Behaviour)this).enabled = false;
			((BaseUnityPlugin)this).Logger.LogError((object)("Failed to initialize wandering planet III:\n" + ex));
		}
	}

	private void OnDestroy()
	{
		VisualPatches.RestoreRuntimeVisuals();
		WarpPatches.ClearRuntimeState();
		MotionController.Clear();
		PrototypeRegistry.UnregisterRuntimeHandlers();
		Harmony obj = harmony;
		if (obj != null)
		{
			obj.UnpatchSelf();
		}
		harmony = null;
	}

	private void LateUpdate()
	{
		if (harmony != null)
		{
			VisualPatches.RefreshRuntimeVisuals();
		}
	}

	private void Update()
	{
		if (harmony != null)
		{
			Player mainPlayer = GameMain.mainPlayer;
			PrototypeRegistry.MigrateLegacyTechnology(GameMain.history);
			if (VFInput._warpKey && MotionController.TryToggleLocalSystemWarp(mainPlayer))
			{
				WarpPatches.NotifySystemWarpToggleHandled();
			}
			MotionController.RefreshActivePlayerWarp(mainPlayer);
			WarpPatches.UpdateSteeringInput();
		}
	}

	public void Export(BinaryWriter writer)
	{
		MotionController.Export(writer);
	}

	public void Import(BinaryReader reader)
	{
		MotionController.Import(reader);
	}

	public void IntoOtherSave()
	{
		PrototypeRegistry.ResetSaveMigration();
		MotionController.IntoOtherSave();
	}
}
internal static class PrototypeRegistry
{
	internal const int PlanetaryWarperItemId = 11991;

	internal const int PlanetaryWarperRecipeId = 490;

	internal const int PlanetaryWarpTechId = 1991;

	private const int LegacyPlanetaryWarpTechId = 11991;

	private const int VanillaWarperItemId = 1210;

	private const int GravityLensItemId = 1209;

	private const int QuantumChipItemId = 1305;

	private const int StrangeAnnihilationFuelRodItemId = 1804;

	private const int DarkFogMatterRecombinatorItemId = 5203;

	private const int DarkFogNegentropySingularityItemId = 5204;

	private const int GravityMatrixTechId = 1705;

	private const float TechnologyColumnSpacing = 4f;

	private const float TechnologyRowSpacing = 4f;

	private const float TechnologyNodeClearance = 3.5f;

	private const int GreenMatrixItemId = 6006;

	private const string VanillaWarperIconPath = "Icons/ItemRecipe/space-warper";

	private const string ItemNameKey = "WanderingPlanetaryWarperName";

	private const string ItemDescriptionKey = "WanderingPlanetaryWarperDescription";

	private const string RecipeDescriptionKey = "WanderingPlanetaryWarperRecipeDescription";

	private const string TechNameKey = "WanderingPlanetaryWarpTechNameV2";

	private const string TechDescriptionKey = "WanderingPlanetaryWarpTechDescription";

	private const string TechConclusionKey = "WanderingPlanetaryWarpTechConclusion";

	internal const string WanderingSystemTypeNameKey = "WanderingSystemTypeName";

	private static readonly FieldInfo ItemIconField = AccessTools.Field(typeof(ItemProto), "_iconSprite");

	private static readonly FieldInfo RecipeIconField = AccessTools.Field(typeof(RecipeProto), "_iconSprite");

	private static readonly FieldInfo TechIconField = AccessTools.Field(typeof(TechProto), "_iconSprite");

	private static ItemProto itemProto;

	private static RecipeProto recipeProto;

	private static TechProto techProto;

	private static Texture2D iconTexture;

	private static Sprite iconSprite;

	private static GameHistoryData migratedHistory;

	internal static void Register()
	{
		//IL_012e: Unknown result type (might be due to invalid IL or missing references)
		if (ItemIconField == null || RecipeIconField == null || TechIconField == null)
		{
			throw new MissingFieldException("DSP prototype icon fields have changed.");
		}
		RegisterTranslations();
		using (ProtoRegistry.StartModLoad("Zincon.DSPWanderingPlanets"))
		{
			itemProto = ProtoRegistry.RegisterItem(11991, "WanderingPlanetaryWarperName", "WanderingPlanetaryWarperDescription", "Icons/ItemRecipe/space-warper", 1707, 10, (EItemType)3);
			itemProto.Productive = true;
			recipeProto = ProtoRegistry.RegisterRecipe(490, (ERecipeType)4, 3600, new int[6] { 1210, 1804, 1209, 1305, 5203, 5204 }, new int[6] { 50, 20, 20, 20, 10, 10 }, new int[1] { 11991 }, new int[1] { 1 }, "WanderingPlanetaryWarperRecipeDescription", 1991, 1707, "WanderingPlanetaryWarperName", "Icons/ItemRecipe/space-warper");
			techProto = ProtoRegistry.RegisterTech(1991, "WanderingPlanetaryWarpTechNameV2", "WanderingPlanetaryWarpTechDescription", "WanderingPlanetaryWarpTechConclusion", "Icons/ItemRecipe/space-warper", new int[1] { 1705 }, new int[1] { 6006 }, new int[1] { 1 }, 21600000L, new int[1] { 490 }, FindTechnologyPosition());
			if (((Proto)techProto).ID != 1991)
			{
				Plugin.Log.LogWarning((object)("LDBTool remapped the planetary-warp technology from " + 1991 + " to " + ((Proto)techProto).ID + "; restoring the main-tree ID."));
				((Proto)techProto).ID = 1991;
			}
		}
		ProtoRegistry.onLoadingFinished += ApplyCustomIcon;
	}

	internal static void UnregisterRuntimeHandlers()
	{
		migratedHistory = null;
		ProtoRegistry.onLoadingFinished -= ApplyCustomIcon;
		if ((Object)(object)iconSprite != (Object)null)
		{
			Object.Destroy((Object)(object)iconSprite);
			iconSprite = null;
		}
		if ((Object)(object)iconTexture != (Object)null)
		{
			Object.Destroy((Object)(object)iconTexture);
			iconTexture = null;
		}
	}

	internal static bool TryConsumePlanetaryWarper(Player player)
	{
		StorageComponent val = ((player == null) ? null : player.mecha?.warpStorage);
		if (val?.grids == null || val.grids.Length == 0 || val.grids[0].itemId != 11991 || val.grids[0].count <= 0)
		{
			return false;
		}
		int num = 11991;
		int num2 = 1;
		int num3 = default(int);
		val.TakeTailItems(ref num, ref num2, ref num3, false);
		if (num != 11991 || num2 != 1)
		{
			return false;
		}
		player.mecha.AddConsumptionStat(num, num2, player.nearestFactory);
		return true;
	}

	internal static bool IsPlanetaryWarpTechUnlocked(GameHistoryData history)
	{
		if (history != null)
		{
			if (!history.TechUnlocked(1991))
			{
				return history.TechUnlocked(11991);
			}
			return true;
		}
		return false;
	}

	internal static void MigrateLegacyTechnology(GameHistoryData history)
	{
		if (history != null && history != migratedHistory)
		{
			if (history.TechUnlocked(11991) && !history.TechUnlocked(1991))
			{
				history.UnlockTechUnlimited(1991, true);
				Plugin.Log.LogInfo((object)"Migrated the legacy planetary-warp technology to the visible tech tree.");
			}
			migratedHistory = history;
		}
	}

	internal static void ResetSaveMigration()
	{
		migratedHistory = null;
	}

	internal static bool IsSupportedWarper(int itemId)
	{
		if (itemId != 1210)
		{
			return itemId == 11991;
		}
		return true;
	}

	internal static int GetWarpSlotStackSize(int itemId)
	{
		if (itemId != 11991)
		{
			return 20;
		}
		return 10;
	}

	private static Vector2 FindTechnologyPosition()
	{
		//IL_001d: 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_006c: 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)
		TechProto val = ((ProtoSet<TechProto>)(object)LDB.techs).Select(1705);
		if (val == null)
		{
			return new Vector2(53f, -35f);
		}
		float num = val.Position.x + 4f;
		Vector2 val2 = default(Vector2);
		for (int i = 0; i < 64; i++)
		{
			int num2 = ((i != 0) ? ((i + 1) / 2 * ((i % 2 != 1) ? 1 : (-1))) : 0);
			((Vector2)(ref val2))..ctor(num, val.Position.y + (float)num2 * 4f);
			if (IsTechnologyPositionFree(val2))
			{
				return val2;
			}
		}
		return new Vector2(num, val.Position.y - 256f);
	}

	private static bool IsTechnologyPositionFree(Vector2 candidate)
	{
		//IL_0033: Unknown result type (might be due to invalid IL or missing references)
		//IL_0051: Unknown result type (might be due to invalid IL or missing references)
		TechProto[] dataArray = ((ProtoSet<TechProto>)(object)LDB.techs).dataArray;
		if (dataArray == null)
		{
			return true;
		}
		foreach (TechProto val in dataArray)
		{
			if (val != null && ((Proto)val).ID < 2000 && Math.Abs(val.Position.x - candidate.x) < 3.5f && Math.Abs(val.Position.y - candidate.y) < 3.5f)
			{
				return false;
			}
		}
		return true;
	}

	private static void RegisterTranslations()
	{
		LocalizationModule.RegisterTranslation("WanderingPlanetaryWarperName", "Planetary Space Warper", "行星空间翘曲器", "Planetary Space Warper");
		LocalizationModule.RegisterTranslation("WanderingPlanetaryWarperDescription", "A Dark-Fog-derived curvature core that encloses nearby space and drives an entire wandering system through a jump.", "源自黑雾空间技术的曲率核心,可包裹附近空间并驱动整个流浪星系跳跃。", "A Dark-Fog-derived curvature core that encloses nearby space and drives an entire wandering system through a jump.");
		LocalizationModule.RegisterTranslation("WanderingPlanetaryWarperRecipeDescription", "Combine warpers, strange annihilation fuel, gravitational components, and Dark Fog matter-control materials into a stellar-scale jump core.", "将翘曲器、奇异湮灭燃料、引力组件与黑雾物质控制材料封装为星系尺度的跳跃核心。", "Combine warpers, strange annihilation fuel, gravitational components, and Dark Fog matter-control materials into a stellar-scale jump core.");
		LocalizationModule.RegisterTranslation("WanderingPlanetaryWarpTechNameV2", "Planetary Spacetime Folding", "行星级空间折叠", "Planetary Spacetime Folding");
		LocalizationModule.RegisterTranslation("WanderingPlanetaryWarpTechDescription", "Reverse-engineer the Dark Fog's matter-recombination and negentropy-confinement technologies to construct a closed curvature field around an entire star system. Powered by core-element-antimatter annihilation, the field reconstructs local spacetime topology, removes the wandering system from its conventional geodesic, and reinserts it at the target coordinates.", "通过逆向解析黑雾的物质重组与负熵约束技术,构建覆盖整个恒星系统的闭合曲率场。核心素-反物质奇异湮灭反应为局部时空拓扑重构提供能量,使流浪星系整体脱离常规测地线,并在目标坐标重新嵌入现实空间。", "Reverse-engineer the Dark Fog's matter-recombination and negentropy-confinement technologies to construct a closed curvature field around an entire star system. Powered by core-element-antimatter annihilation, the field reconstructs local spacetime topology, removes the wandering system from its conventional geodesic, and reinserts it at the target coordinates.");
		LocalizationModule.RegisterTranslation("WanderingPlanetaryWarpTechConclusion", "System-scale curvature navigation protocol established. Controlled spatial jumps are now available to wandering systems.", "系统级曲率航行协议已完成。流浪星系现可执行受控空间跃迁。", "System-scale curvature navigation protocol established. Controlled spatial jumps are now available to wandering systems.");
		LocalizationModule.RegisterTranslation("WanderingSystemTypeName", "Wandering System", "流浪星系", "Wandering System");
	}

	private static void ApplyCustomIcon()
	{
		//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
		//IL_01cd: Expected O, but got Unknown
		//IL_021b: Unknown result type (might be due to invalid IL or missing references)
		//IL_022a: Unknown result type (might be due to invalid IL or missing references)
		TechProto val = ((ProtoSet<TechProto>)(object)LDB.techs).Select(1991);
		RecipeProto val2 = ((ProtoSet<RecipeProto>)(object)LDB.recipes).Select(490);
		if (val != techProto || val2 != recipeProto || val.PreTechs == null || Array.IndexOf(val.PreTechs, 1705) < 0)
		{
			Plugin.Log.LogError((object)("Planetary-warp prototype self-check failed: tech=" + ((val == null) ? "missing" : ((Proto)val).ID.ToString()) + ", recipe=" + ((val2 == null) ? "missing" : ((Proto)val2).ID.ToString()) + "."));
		}
		else
		{
			Plugin.Log.LogInfo((object)("Planetary-warp prototypes loaded at main-tree tech ID " + ((Proto)val).ID + " after gravity-matrix tech " + 1705 + " at (" + val.Position.x + ", " + val.Position.y + ") with " + val2.Items.Length + " recipe ingredients."));
		}
		try
		{
			using (Stream stream = typeof(PrototypeRegistry).Assembly.GetManifestResourceStream("DSPWanderingPlanets.assets.planetary-space-warper.png"))
			{
				if (stream == null)
				{
					throw new FileNotFoundException("Embedded planetary-warper icon was not found.", "DSPWanderingPlanets.assets.planetary-space-warper.png");
				}
				byte[] array = new byte[stream.Length];
				int num;
				for (int i = 0; i < array.Length; i += num)
				{
					num = stream.Read(array, i, array.Length - i);
					if (num <= 0)
					{
						throw new EndOfStreamException("Could not read the embedded icon.");
					}
				}
				iconTexture = new Texture2D(2, 2, (TextureFormat)5, false);
				((Object)iconTexture).name = "planetary-space-warper";
				if (!ImageConversion.LoadImage(iconTexture, array, false))
				{
					throw new InvalidDataException("The embedded icon is not a valid PNG.");
				}
				iconSprite = Sprite.Create(iconTexture, new Rect(0f, 0f, (float)((Texture)iconTexture).width, (float)((Texture)iconTexture).height), new Vector2(0.5f, 0.5f), 100f);
				((Object)iconSprite).name = "planetary-space-warper";
			}
			ItemIconField.SetValue(itemProto, iconSprite);
			RecipeIconField.SetValue(recipeProto, iconSprite);
			TechIconField.SetValue(techProto, iconSprite);
		}
		catch (Exception ex)
		{
			Plugin.Log.LogError((object)("Failed to apply the planetary-warper icon: " + ex));
		}
	}
}
[HarmonyPatch]
internal static class VeinGenerationPatches
{
	private const int UnipolarTypeIndex = 14;

	[HarmonyPostfix]
	[HarmonyPriority(0)]
	[HarmonyPatch(typeof(PlanetAlgorithm), "GenerateVeins")]
	private static void PlanetAlgorithm_Postfix(PlanetData ___planet)
	{
		TryInjectUnipolarCluster(___planet);
	}

	[HarmonyPostfix]
	[HarmonyPriority(0)]
	[HarmonyPatch(typeof(PlanetAlgorithm0), "GenerateVeins")]
	private static void PlanetAlgorithm0_Postfix(PlanetData ___planet)
	{
		TryInjectUnipolarCluster(___planet);
	}

	[HarmonyPostfix]
	[HarmonyPriority(0)]
	[HarmonyPatch(typeof(PlanetAlgorithm7), "GenerateVeins")]
	private static void PlanetAlgorithm7_Postfix(PlanetData ___planet)
	{
		TryInjectUnipolarCluster(___planet);
	}

	[HarmonyPostfix]
	[HarmonyPriority(0)]
	[HarmonyPatch(typeof(PlanetAlgorithm11), "GenerateVeins")]
	private static void PlanetAlgorithm11_Postfix(PlanetData ___planet)
	{
		TryInjectUnipolarCluster(___planet);
	}

	[HarmonyPostfix]
	[HarmonyPriority(0)]
	[HarmonyPatch(typeof(PlanetAlgorithm12), "GenerateVeins")]
	private static void PlanetAlgorithm12_Postfix(PlanetData ___planet)
	{
		TryInjectUnipolarCluster(___planet);
	}

	[HarmonyPostfix]
	[HarmonyPriority(0)]
	[HarmonyPatch(typeof(PlanetAlgorithm13), "GenerateVeins")]
	private static void PlanetAlgorithm13_Postfix(PlanetData ___planet)
	{
		TryInjectUnipolarCluster(___planet);
	}

	private static void TryInjectUnipolarCluster(PlanetData planet)
	{
		//IL_0009: Unknown result type (might be due to invalid IL or missing references)
		//IL_000f: Invalid comparison between Unknown and I4
		//IL_0012: Unknown result type (might be due to invalid IL or missing references)
		if (!MotionController.IsWanderingPlanet(planet) || (int)planet.type == 5 || (int)planet.type == 0 || planet.data == null)
		{
			return;
		}
		DeterministicRandom deterministicRandom = new DeterministicRandom((uint)(planet.seed ^ 0x4D41474E));
		if (deterministicRandom.NextDouble() >= (double)ModConfig.UnipolarMagnetChance.Value)
		{
			return;
		}
		lock (planet)
		{
			if (!ContainsUnipolarVein(planet.data))
			{
				AddUnipolarCluster(planet, deterministicRandom);
			}
		}
	}

	private static bool ContainsUnipolarVein(PlanetRawData data)
	{
		//IL_002e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0035: Invalid comparison between Unknown and I4
		if (data.veinPool == null)
		{
			return false;
		}
		for (int i = 1; i < data.veinCursor && i < data.veinPool.Length; i++)
		{
			if (data.veinPool[i].id == i && (int)data.veinPool[i].type == 14)
			{
				return true;
			}
		}
		return false;
	}

	private static void AddUnipolarCluster(PlanetData planet, DeterministicRandom random)
	{
		//IL_0054: Unknown result type (might be due to invalid IL or missing references)
		//IL_0059: Unknown result type (might be due to invalid IL or missing references)
		//IL_005b: 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_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)
		//IL_006b: Unknown result type (might be due to invalid IL or missing references)
		//IL_006d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0072: Unknown result type (might be due to invalid IL or missing references)
		//IL_0077: 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)
		//IL_0115: Unknown result type (might be due to invalid IL or missing references)
		//IL_011a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0124: Unknown result type (might be due to invalid IL or missing references)
		//IL_0129: Unknown result type (might be due to invalid IL or missing references)
		//IL_0133: Unknown result type (might be due to invalid IL or missing references)
		//IL_0138: Unknown result type (might be due to invalid IL or missing references)
		//IL_013a: Unknown result type (might be due to invalid IL or missing references)
		//IL_013c: Unknown result type (might be due to invalid IL or missing references)
		//IL_013e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0143: Unknown result type (might be due to invalid IL or missing references)
		//IL_0147: Unknown result type (might be due to invalid IL or missing references)
		//IL_014c: Unknown result type (might be due to invalid IL or missing references)
		//IL_014f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0167: Unknown result type (might be due to invalid IL or missing references)
		//IL_0177: Unknown result type (might be due to invalid IL or missing references)
		//IL_0181: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c7: Unknown result type (might be due to invalid IL or missing references)
		//IL_01cc: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
		//IL_01db: Unknown result type (might be due to invalid IL or missing references)
		//IL_01fa: Unknown result type (might be due to invalid IL or missing references)
		//IL_021d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0225: Unknown result type (might be due to invalid IL or missing references)
		//IL_022f: Unknown result type (might be due to invalid IL or missing references)
		int[] veinModelIndexs = PlanetModelingManager.veinModelIndexs;
		int[] veinModelCounts = PlanetModelingManager.veinModelCounts;
		int[] veinProducts = PlanetModelingManager.veinProducts;
		if (veinModelIndexs == null || veinModelCounts == null || veinProducts == null || veinModelIndexs.Length <= 14 || veinModelCounts.Length <= 14 || veinProducts.Length <= 14 || veinModelCounts[14] <= 0)
		{
			return;
		}
		PlanetRawData data = planet.data;
		if (!TryChooseClusterCenter(planet, data, random, out var center))
		{
			return;
		}
		int num = FindNextGroupIndex(data);
		Quaternion val = Quaternion.FromToRotation(Vector3.up, center);
		Vector3 val2 = val * Vector3.right;
		Vector3 val3 = val * Vector3.forward;
		float num2 = 2.1f / planet.radius;
		int num3 = random.NextInt(12, 19);
		int amountBase = Mathf.Max(20, Mathf.RoundToInt(30000f * Math.Max(0.1f, planet.star.resourceCoef)));
		List<Vector3> list = new List<Vector3>(num3);
		int num4 = 0;
		for (int i = 0; i < num3 * 20; i++)
		{
			if (num4 >= num3)
			{
				break;
			}
			double num5 = random.NextDouble() * Math.PI * 2.0;
			float num6 = ((num4 == 0) ? 0f : ((float)Math.Sqrt(random.NextDouble()) * 4.2f));
			Vector3 val4 = (val2 * (float)Math.Cos(num5) + val3 * (float)Math.Sin(num5)) * (num6 * num2);
			Vector3 val5 = center + val4;
			Vector3 normalized = ((Vector3)(ref val5)).normalized;
			float num7 = data.QueryHeight(normalized);
			if (!(num7 < planet.radius) && !IsTooCloseToClusterNode(list, normalized, num2))
			{
				VeinData val6 = new VeinData
				{
					type = (EVeinType)14,
					groupIndex = (short)num,
					modelIndex = (short)(veinModelIndexs[14] + random.NextInt(veinModelCounts[14])),
					amount = CalculateAmount(amountBase, random),
					productId = veinProducts[14],
					pos = normalized * num7,
					minerCount = 0
				};
				if (DSPGame.GameDesc.isInfiniteResource)
				{
					val6.amount = 1000000000;
				}
				else
				{
					val6.amount = Mathf.Max(1, Mathf.RoundToInt((float)val6.amount * DSPGame.GameDesc.resourceMultiplier));
				}
				data.EraseVegetableAtPoint(normalized);
				data.AddVeinData(val6);
				list.Add(normalized);
				num4++;
			}
		}
	}

	private static bool IsTooCloseToClusterNode(List<Vector3> placedDirections, Vector3 direction, float spacing)
	{
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		//IL_0015: Unknown result type (might be due to invalid IL or missing references)
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		float num = spacing * spacing * 0.65f;
		for (int i = 0; i < placedDirections.Count; i++)
		{
			Vector3 val = placedDirections[i] - direction;
			if (((Vector3)(ref val)).sqrMagnitude < num)
			{
				return true;
			}
		}
		return false;
	}

	private static bool TryChooseClusterCenter(PlanetData planet, PlanetRawData data, DeterministicRandom random, out Vector3 center)
	{
		//IL_0059: Unknown result type (might be due to invalid IL or missing references)
		//IL_005e: 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_0078: 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)
		for (int i = 0; i < 512; i++)
		{
			center = new Vector3((float)(random.NextDouble() * 2.0 - 1.0), (float)(random.NextDouble() * 2.0 - 1.0), (float)(random.NextDouble() * 2.0 - 1.0));
			if (!(((Vector3)(ref center)).sqrMagnitude < 0.01f))
			{
				((Vector3)(ref center)).Normalize();
				if (!(data.QueryHeight(center) < planet.radius) && !IsNearExistingVein(data, center))
				{
					return true;
				}
			}
		}
		center = Vector3.zero;
		return false;
	}

	private static bool IsNearExistingVein(PlanetRawData data, Vector3 center)
	{
		//IL_0015: Unknown result type (might be due to invalid IL or missing references)
		//IL_001a: Unknown result type (might be due to invalid IL or missing references)
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		//IL_003e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0043: Unknown result type (might be due to invalid IL or missing references)
		if (data.veinPool == null)
		{
			return false;
		}
		for (int i = 1; i < data.veinCursor && i < data.veinPool.Length; i++)
		{
			VeinData val = data.veinPool[i];
			if (val.id == i && ((Vector3)(ref val.pos)).sqrMagnitude > 0.01f && Vector3.Dot(((Vector3)(ref val.pos)).normalized, center) > 0.985f)
			{
				return true;
			}
		}
		return false;
	}

	private static int FindNextGroupIndex(PlanetRawData data)
	{
		int num = 0;
		if (data.veinPool != null)
		{
			for (int i = 1; i < data.veinCursor && i < data.veinPool.Length; i++)
			{
				if (data.veinPool[i].id == i)
				{
					num = Math.Max(num, data.veinPool[i].groupIndex);
				}
			}
		}
		return Math.Min(32767, num + 1);
	}

	private static int CalculateAmount(int amountBase, DeterministicRandom random)
	{
		return Mathf.RoundToInt((float)amountBase * (float)(0.5 + random.NextDouble()));
	}
}
internal static class VisualPatches
{
	private sealed class HiddenOrbitState
	{
		internal PlanetData Planet;

		internal GameObject RelatedObject;

		internal Renderer PlanetRenderer;

		internal Renderer[] Renderers;

		internal bool[] EnabledStates;

		internal void Hide()
		{
			for (int i = 0; i < Renderers.Length; i++)
			{
				Renderer val = Renderers[i];
				if ((Object)(object)val != (Object)null && val != PlanetRenderer)
				{
					val.enabled = false;
				}
			}
		}

		internal void Restore()
		{
			for (int i = 0; i < Renderers.Length; i++)
			{
				Renderer val = Renderers[i];
				if ((Object)(object)val != (Object)null)
				{
					val.enabled = EnabledStates[i];
				}
			}
		}
	}

	[HarmonyPatch(typeof(UIStarmapPlanet), "_OnLateUpdate")]
	private static class StarmapPlanetLightingPatch
	{
		[HarmonyPostfix]
		private static void Postfix(UIStarmapPlanet __instance)
		{
			RemoveStarmapDaylight(__instance);
		}
	}

	[HarmonyPatch(typeof(UIStarmap), "_OnLateUpdate")]
	private static class StarmapPlayerTrackDirectionPatch
	{
		[HarmonyPostfix]
		private static void Postfix(UIStarmap __instance)
		{
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)__instance?.playerTrack == (Object)null) && MotionController.TryGetActivePlayerWarpDirection(out var direction))
			{
				Vector3 val = default(Vector3);
				((Vector3)(ref val))..ctor((float)direction.X, (float)direction.Y, (float)direction.Z);
				if (((Vector3)(ref val)).sqrMagnitude > 1E-06f)
				{
					__instance.playerTrack.rotation = Quaternion.LookRotation(((Vector3)(ref val)).normalized);
				}
			}
		}
	}

	[HarmonyPatch(typeof(UIStarmapPlanet), "_OnFree")]
	private static class StarmapPlanetFreePatch
	{
		[HarmonyPrefix]
		private static void Prefix(UIStarmapPlanet __instance)
		{
			RestoreOrbitVisibility(__instance);
		}
	}

	[HarmonyPatch(/*Could not decode attribute arguments.*/)]
	private static class WanderingSystemTypeNamePatch
	{
		[HarmonyPostfix]
		private static void Postfix(StarData __instance, ref string __result)
		{
			if (MotionController.IsWanderingStar(__instance))
			{
				__result = Localization.Translate("WanderingSystemTypeName");
			}
		}
	}

	[HarmonyPatch(typeof(UIStarDetail), "OnStarDataSet")]
	private static class WanderingSystemSpectrumPatch
	{
		[HarmonyPostfix]
		private static void Postfix(UIStarDetail __instance)
		{
			if (MotionController.IsWanderingStar((__instance != null) ? __instance.star : null))
			{
				if ((Object)(object)__instance.typeText != (Object)null)
				{
					__instance.typeText.text = Localization.Translate("WanderingSystemTypeName");
				}
				if ((Object)(object)__instance.spectrValueText != (Object)null)
				{
					__instance.spectrValueText.text = "-";
				}
			}
		}
	}

	private static readonly Color StarmapGray = new Color(0.56f, 0.59f, 0.61f, 1f);

	private static readonly Dictionary<UIStarmapPlanet, HiddenOrbitState> HiddenOrbits = new Dictionary<UIStarmapPlanet, HiddenOrbitState>();

	private static FieldInfo spotMaterialField;

	private static FieldInfo massMaterialField;

	private static FieldInfo planetMaterialField;

	internal static void ValidateTargets()
	{
		spotMaterialField = AccessTools.Field(typeof(UIStarmapStarObject), "spotMat");
		massMaterialField = AccessTools.Field(typeof(UIStarmapStarObject), "massMat");
		planetMaterialField = AccessTools.Field(typeof(UIStarmapPlanet), "planetMat");
		if (spotMaterialField == null || massMaterialField == null || planetMaterialField == null || AccessTools.Method(typeof(UIStarmap), "_OnLateUpdate", (Type[])null, (Type[])null) == null || AccessTools.Method(typeof(UIStarmapPlanet), "_OnLateUpdate", (Type[])null, (Type[])null) == null || AccessTools.Method(typeof(UIStarmapPlanet), "_OnFree", (Type[])null, (Type[])null) == null || AccessTools.PropertyGetter(typeof(StarData), "typeString") == null || AccessTools.Method(typeof(UIStarDetail), "OnStarDataSet", (Type[])null, (Type[])null) == null)
		{
			throw new MissingFieldException("DSP starmap visual fields have changed.");
		}
	}

	internal static void RefreshRuntimeVisuals()
	{
		HidePhysicalStars(((Object)(object)GameMain.instance == (Object)null) ? null : GameMain.universeSimulator);
		UpdateStarmap(UIRoot.instance?.uiGame?.starmap);
	}

	internal static void RestoreRuntimeVisuals()
	{
		foreach (HiddenOrbitState value in HiddenOrbits.Values)
		{
			value.Restore();
		}
		HiddenOrbits.Clear();
	}

	private static void HidePhysicalStars(UniverseSimulator universe)
	{
		if (universe?.starSimulators == null)
		{
			return;
		}
		for (int i = 0; i < universe.starSimulators.Length; i++)
		{
			StarSimulator val = universe.starSimulators[i];
			if ((Object)(object)val != (Object)null && MotionController.IsWanderingStar(val.starData) && ((Component)val).gameObject.activeSelf)
			{
				((Component)val).gameObject.SetActive(false);
			}
		}
	}

	private static void UpdateStarmap(UIStarmap starmap)
	{
		if ((Object)(object)starmap == (Object)null)
		{
			RestoreRuntimeVisuals();
			return;
		}
		if (starmap.planetUIs != null)
		{
			for (int i = 0; i < starmap.planetUIs.Length; i++)
			{
				UIStarmapPlanet val = starmap.planetUIs[i];
				if (!((Object)(object)val == (Object)null))
				{
					bool hiddenMainOrbit = MotionController.IsWanderingPlanet(val.planet) && val.planet?.orbitAroundPlanet == null && (Object)(object)val.relatedObject != (Object)null;
					UpdateOrbitVisibility(val, hiddenMainOrbit);
					RemoveStarmapDaylight(val);
				}
			}
		}
		if (starmap.starUIs == null)
		{
			return;
		}
		for (int j = 0; j < starmap.starUIs.Length; j++)
		{
			UIStarmapStarObject val2 = starmap.starUIs[j]?.starObject;
			if (!((Object)(object)val2 == (Object)null) && MotionController.IsWanderingStar(val2.star))
			{
				object? value = spotMaterialField.GetValue(val2);
				ApplyGray((Material)((value is Material) ? value : null), val2.spotBlender);
				object? value2 = massMaterialField.GetValue(val2);
				ApplyGray((Material)((value2 is Material) ? value2 : null), val2.massBlender);
			}
		}
	}

	private static void UpdateOrbitVisibility(UIStarmapPlanet planetUi, bool hiddenMainOrbit)
	{
		if (HiddenOrbits.TryGetValue(planetUi, out var value) && (!hiddenMainOrbit || value.Planet != planetUi.planet || value.RelatedObject != planetUi.relatedObject))
		{
			value.Restore();
			HiddenOrbits.Remove(planetUi);
			value = null;
		}
		if (!hiddenMainOrbit)
		{
			return;
		}
		if (value == null)
		{
			Renderer[] componentsInChildren = planetUi.relatedObject.GetComponentsInChildren<Renderer>(true);
			bool[] array = new bool[componentsInChildren.Length];
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				array[i] = (Object)(object)componentsInChildren[i] != (Object)null && componentsInChildren[i].enabled;
			}
			value = new HiddenOrbitState
			{
				Planet = planetUi.planet,
				RelatedObject = planetUi.relatedObject,
				PlanetRenderer = planetUi.planetRenderer,
				Renderers = componentsInChildren,
				EnabledStates = array
			};
			HiddenOrbits.Add(planetUi, value);
		}
		value.Hide();
	}

	private static void RemoveStarmapDaylight(UIStarmapPlanet planetUi)
	{
		//IL_003b: Unknown result type (might be due to invalid IL or missing references)
		if (MotionController.IsWanderingPlanet(planetUi.planet))
		{
			object? value = planetMaterialField.GetValue(planetUi);
			Material val = (Material)((value is Material) ? value : null);
			if ((Object)(object)val != (Object)null && val.HasProperty("_SunDir"))
			{
				val.SetVector("_SunDir", Vector4.zero);
			}
		}
	}

	private static void RestoreOrbitVisibility(UIStarmapPlanet planetUi)
	{
		if ((Object)(object)planetUi != (Object)null && HiddenOrbits.TryGetValue(planetUi, out var value))
		{
			value.Restore();
			HiddenOrbits.Remove(planetUi);
		}
	}

	private static void ApplyGray(Material material, StarMaterialBlender blender)
	{
		if ((Object)(object)material == (Object)null)
		{
			return;
		}
		if (blender?.colorPropNames != null)
		{
			for (int i = 0; i < blender.colorPropNames.Length; i++)
			{
				SetGrayIfPresent(material, blender.colorPropNames[i]);
			}
		}
		SetGrayIfPresent(material, "_Color");
		SetGrayIfPresent(material, "_TintColor");
		SetGrayIfPresent(material, "_SunCenterColor");
		SetGrayIfPresent(material, "_SunGlowColor");
	}

	private static void SetGrayIfPresent(Material material, string propertyName)
	{
		//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_0039: 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)
		if (!string.IsNullOrEmpty(propertyName) && material.HasProperty(propertyName))
		{
			Color color = material.GetColor(propertyName);
			material.SetColor(propertyName, new Color(StarmapGray.r, StarmapGray.g, StarmapGray.b, color.a));
		}
	}
}
internal static class WanderingSystemFactory
{
	private const double SatelliteGravity = 1.0830842106853677E-08;

	private const double FourPiSquared = 39.47841760435743;

	private const float MainPlanetOffsetAu = 1f;

	private const int MediterraneanThemeId = 1;

	internal static void TransformGalaxy(GalaxyData galaxy, GameDesc gameDesc, int systemCount)
	{
		int[] array = SelectSystemIndexes(galaxy, systemCount);
		if (array.Length == 0)
		{
			Plugin.Log.LogWarning((object)"No non-birth main-sequence stars were available for wandering systems.");
			return;
		}
		for (int i = 0; i < array.Length; i++)
		{
			BuildSystem(galaxy, galaxy.stars[array[i]], gameDesc, i + 1);
		}
		if (ModConfig.StartInWanderingSystem.Value && ConfigureBirthSystem(galaxy, array))
		{
			Plugin.Log.LogInfo((object)"Configured the first wandering system as the new-save birth system.");
		}
		IsolateMovingGraphNodes(galaxy, array);
		RecalculateHabitableCount(galaxy);
		MotionController.Register(galaxy, array);
		MotionController.BeforePoseUpdate(galaxy, 0.0);
		for (int j = 0; j < array.Length; j++)
		{
			StarData val = galaxy.stars[array[j]];
			for (int k = 0; k < val.planetCount; k++)
			{
				val.planets[k].UpdateRuntimePose(0.0);
			}
		}
		MotionController.AfterPoseUpdate(galaxy);
		Plugin.Log.LogInfo((object)("Generated " + array.Length + " wandering systems with the built-in route planner enabled."));
		if (array.Length < systemCount)
		{
			Plugin.Log.LogWarning((object)("Requested " + systemCount + " wandering systems, but only " + array.Length + " non-birth main-sequence stars were available. Compact and giant stars were preserved."));
		}
	}

	private static int[] SelectSystemIndexes(GalaxyData galaxy, int requestedCount)
	{
		//IL_001f: Unknown result type (might be due to invalid IL or missing references)
		List<int> list = new List<int>(requestedCount);
		int num = galaxy.starCount - 1;
		while (num >= 1 && list.Count < requestedCount)
		{
			StarData val = galaxy.stars[num];
			if (val != null && (int)val.type == 0)
			{
				list.Add(num);
			}
			num--;
		}
		list.Sort();
		return list.ToArray();
	}

	private static bool ConfigureBirthSystem(GalaxyData galaxy, int[] systemIndexes)
	{
		if (galaxy == null || systemIndexes == null)
		{
			return false;
		}
		foreach (int num in systemIndexes)
		{
			if (num < 0 || num >= galaxy.starCount)
			{
				continue;
			}
			StarData val = galaxy.stars[num];
			if (val?.planets != null)
			{
				PlanetData val2 = SelectBirthPlanet(val, galaxy.seed);
				if (val2 != null && ApplyMediterraneanBirthTheme(val2))
				{
					galaxy.birthStarId = val.id;
					galaxy.birthPlanetId = val2.id;
					return true;
				}
			}
		}
		return false;
	}

	private static PlanetData SelectBirthPlanet(StarData star, int galaxySeed)
	{
		//IL_0017: Unknown result type (might be due to invalid IL or missing references)
		//IL_001d: Invalid comparison between Unknown and I4
		List<PlanetData> list = new List<PlanetData>();
		for (int i = 0; i < star.planetCount; i++)
		{
			PlanetData val = star.planets[i];
			if (val != null && (int)val.type != 5 && (val.orbitAroundPlanet == null || val.orbitAroundPlanet.orbitAroundPlanet == null))
			{
				list.Add(val);
			}
		}
		if (list.Count == 0)
		{
			return null;
		}
		DeterministicRandom deterministicRandom = new DeterministicRandom((uint)(galaxySeed ^ star.seed ^ 0x42495254));
		return list[deterministicRandom.NextInt(list.Count)];
	}

	private static bool ApplyMediterraneanBirthTheme(PlanetData planet)
	{
		//IL_000a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0010: Invalid comparison between Unknown and I4
		//IL_002b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0031: Invalid comparison between Unknown and I4
		//IL_0034: Unknown result type (might be due to invalid IL or missing references)
		//IL_003a: Invalid comparison between Unknown and I4
		//IL_0059: Unknown result type (might be due to invalid IL or missing references)
		//IL_005e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0065: 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_0073: 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_00d3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d9: Invalid comparison between Unknown and I4
		if (planet.theme == 1 && (int)planet.type == 2)
		{
			return true;
		}
		ThemeProto val = ((ProtoSet<ThemeProto>)(object)LDB.themes)?.Select(1);
		if (val == null || (int)val.Distribute != 1 || (int)val.PlanetType != 2)
		{
			Plugin.Log.LogError((object)"Vanilla Mediterranean birth theme 1 is unavailable; wandering-system birth was not enabled.");
			return false;
		}
		DotNet35Random val2 = new DotNet35Random(planet.infoSeed ^ 0x4D454449);
		double num = val2.NextDouble();
		double num2 = val2.NextDouble();
		double num3 = val2.NextDouble();
		double num4 = val2.NextDouble();
		int num5 = val2.Next();
		int index = planet.star.index;
		try
		{
			planet.type = (EPlanetType)2;
			planet.star.index = 0;
			PlanetGen.SetPlanetTheme(planet, new int[1] { 1 }, num, num2, num3, num4, num5);
		}
		finally
		{
			planet.star.index = index;
		}
		if (planet.theme == 1)
		{
			return (int)planet.type == 2;
		}
		return false;
	}

	private static void BuildSystem(GalaxyData galaxy, StarData star, GameDesc gameDesc, int ordinal)
	{
		ClearOldPlanetAstros(galaxy, star);
		PrepareGenerationAnchor(star, ordinal);
		BodyLayout[] array = WanderingSystemLayout.Generate((star.seed * 397) ^ (galaxy.seed * 7919) ^ ordinal);
		star.planets = (PlanetData[])(object)new PlanetData[array.Length];
		star.planetCount = array.Length;
		for (int i = 0; i < array.Length; i++)
		{
			int num = star.seed * 486187739 + i * 16777619 + 31;
			int num2 = (num * 397) ^ 0x57414E44;
			PlanetData val = PlanetGen.CreatePlanet(galaxy, star, gameDesc.savedThemeIds, i, 0, Math.Min(16, Math.Max(1, array[i].OrbitIndex)), i + 1, array[i].IsGas, num, num2);
			star.planets[i] = val;
		}
		ConfigureHierarchy(galaxy, star, array);
		SuppressAnchorStar(galaxy, star);
	}

	private static void PrepareGenerationAnchor(StarData star, int ordinal)
	{
		//IL_0024: Unknown result type (might be due to invalid IL or missing references)
		star.name = "Wandering Planet " + ordinal;
		star.overrideName = string.Empty;
		star.type = (EStarType)0;
		star.mass = 1f;
		star.radius = 1f;
		star.luminosity = 1f;
		star.temperature = 5778f;
		star.habitableRadius = 1f;
		star.lightBalanceRadius = 1f;
		star.orbitScaler = 1f;
		star.asterBelt1OrbitIndex = 0f;
		star.asterBelt2OrbitIndex = 0f;
		star.asterBelt1Radius = 0f;
		star.asterBelt2Radius = 0f;
	}

	private static void ConfigureHierarchy(GalaxyData galaxy, StarData star, BodyLayout[] layout)
	{
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		//IL_001d: Unknown result type (might be due to invalid IL or missing references)
		//IL_001e: Unknown result type (might be due to invalid IL or missing references)
		//IL_013a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0140: Invalid comparison between Unknown and I4
		//IL_01ea: 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_01f2: Unknown result type (might be due to invalid IL or missing references)
		for (int i = 0; i < layout.Length; i++)
		{
			BodyLayout bodyLayout = layout[i];
			PlanetData val = star.planets[i];
			val.singularity = (EPlanetSingularity)(val.singularity & -33);
			if (bodyLayout.ParentIndex < 0)
			{
				val.orbitAroundPlanet = null;
				val.orbitAround = 0;
				val.orbitIndex = 1;
				val.number = 1;
				val.orbitRadius = 1f;
				val.sunDistance = 1f;
				val.orbitalPeriod = 1E+30;
				val.orbitPhase = 0f;
			}
			else
			{
				PlanetData val2 = (val.orbitAroundPlanet = star.planets[bodyLayout.ParentIndex]);
				val.orbitAround = val2.number;
				val.orbitIndex = bodyLayout.OrbitIndex;
				val.number = bodyLayout.SiblingNumber;
				val.orbitRadius = CalculateSatelliteOrbitRadius(star, val2, val);
				val.sunDistance = 1f;
				val.orbitalPeriod = Math.Sqrt(39.47841760435743 * (double)val.orbitRadius * (double)val.orbitRadius * (double)val.orbitRadius / 1.0830842106853677E-08);
			}
			float radiusForDepth = WanderingSystemLayout.GetRadiusForDepth(bodyLayout.Depth, val.radius);
			if (Math.Abs(radiusForDepth - val.radius) > 0.01f)
			{
				val.radius = radiusForDepth;
				if ((int)val.type != 5)
				{
					val.scale = 1f;
					val.precision = 200;
					val.segment = 5;
				}
			}
			UpdateRuntimeRotations(val);
			val.luminosity = CalculateSolarEfficiency(val.infoSeed);
			galaxy.astrosData[val.id].uRadius = val.realRadius;
		}
		float sunDistance = CalculateSystemRadius(star);
		for (int j = 0; j < star.planetCount; j++)
		{
			star.planets[j].sunDistance = sunDistance;
		}
		for (int k = 0; k < layout.Length; k++)
		{
			if (layout[k].Children.Count > 0)
			{
				PlanetData obj = star.planets[k];
				obj.singularity = (EPlanetSingularity)(obj.singularity | 0x20);
			}
		}
	}

	private static float CalculateSystemRadius(StarData star)
	{
		float num = 1f;
		for (int i = 0; i < star.planetCount; i++)
		{
			PlanetData obj = star.planets[i];
			float num2 = obj.realRadius / 40000f;
			for (PlanetData val = obj; val != null; val = val.orbitAroundPlanet)
			{
				num2 += val.orbitRadius;
			}
			num = Math.Max(num, num2);
		}
		return num;
	}

	private static float CalculateSatelliteOrbitRadius(StarData star, PlanetData parent, PlanetData satellite)
	{
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_000b: Unknown result type (might be due to invalid IL or missing references)
		DotNet35Random val = new DotNet35Random(satellite.infoSeed);
		double num = val.NextDouble();
		double num2 = val.NextDouble();
		float num3 = Mathf.Pow(1.2f, (float)(num * (num2 - 0.5) * 0.5));
		return ((1600f * (float)satellite.orbitIndex + 200f) * Mathf.Pow(star.orbitScaler, 0.3f) * Mathf.Lerp(num3, 1f, 0.5f) + parent.realRadius) / 40000f;
	}

	private static void UpdateRuntimeRotations(PlanetData body)
	{
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_000b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0020: Unknown result type (might be due to invalid IL or missing references)
		//IL_0025: Unknown result type (might be due to invalid IL or missing references)
		//IL_0042: Unknown result type (might be due to invalid IL or missing references)
		//IL_0035: Unknown result type (might be due to invalid IL or missing references)
		//IL_003a: Unknown result type (might be due to invalid IL or missing references)
		//IL_003b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0043: 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_0055: Unknown result type (might be due to invalid IL or missing references)
		//IL_005a: Unknown result type (might be due to invalid IL or missing references)
		//IL_005f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0064: Unknown result type (might be due to invalid IL or missing references)
		Quaternion val = Quaternion.AngleAxis(body.orbitLongitude, Vector3.up) * Quaternion.AngleAxis(body.orbitInclination, Vector3.forward);
		body.runtimeOrbitRotation = ((body.orbitAroundPlanet == null) ? val : (body.orbitAroundPlanet.runtimeOrbitRotation * val));
		body.runtimeSystemRotation = body.runtimeOrbitRotation * Quaternion.AngleAxis(body.obliquity, Vector3.forward);
	}

	private static float CalculateSolarEfficiency(int seed)
	{
		DeterministicRandom deterministicRandom = new DeterministicRandom((uint)(seed ^ 0x534F4C52));
		return (float)(0.001 + deterministicRandom.NextDouble() * 0.009);
	}

	private static void SuppressAnchorStar(GalaxyData galaxy, StarData star)
	{
		//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d1: 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)
		star.mass = 0.01f;
		star.radius = 1f;
		star.luminosity = 0f;
		star.temperature = 1f;
		star.classFactor = -2f;
		star.color = 0.3f;
		star.habitableRadius = 0f;
		star.lightBalanceRadius = 0f;
		star.dysonRadius = 0.2f;
		star.acdiskRadius = 0f;
		star.asterBelt1OrbitIndex = 0f;
		star.asterBelt2OrbitIndex = 0f;
		star.asterBelt1Radius = 0f;
		star.asterBelt2Radius = 0f;
		star.initialHiveCount = 0;
		star.maxHiveCount = 0;
		star.hivePatternLevel = 0;
		AstroData val = galaxy.astrosData[star.astroId];
		val.id = star.astroId;
		val.type = (EAstroType)1;
		val.parentId = 0;
		val.uRadius = 0f;
		galaxy.astrosData[star.astroId] = val;
	}

	private static void ClearOldPlanetAstros(GalaxyData galaxy, StarData star)
	{
		for (int i = 1; i < 100; i++)
		{
			((AstroData)(ref galaxy.astrosData[star.astroId + i])).SetEmpty();
			galaxy.astrosFactory[star.astroId + i] = null;
		}
	}

	private static void IsolateMovingGraphNodes(GalaxyData galaxy, int[] systemIndexes)
	{
		if (galaxy.graphNodes == null)
		{
			return;
		}
		foreach (int num in systemIndexes)
		{
			StarGraphNode val = galaxy.graphNodes[num];
			if (val == null)
			{
				continue;
			}
			for (int j = 0; j < galaxy.graphNodes.Length; j++)
			{
				StarGraphNode val2 = galaxy.graphNodes[j];
				if (val2 != null && val2 != val)
				{
					val2.conns?.Remove(val);
					val2.lines?.Remove(val);
				}
			}
			val.conns?.Clear();
			val.lines?.Clear();
		}
	}

	private static void RecalculateHabitableCount(GalaxyData galaxy)
	{
		//IL_0020: Unknown result type (might be due to invalid IL or missing references)
		//IL_0026: Invalid comparison between Unknown and I4
		int num = 0;
		for (int i = 0; i < galaxy.starCount; i++)
		{
			PlanetData[] planets = galaxy.stars[i].planets;
			for (int j = 0; j < planets.Length; j++)
			{
				if (planets[j] != null && (int)planets[j].type == 2)
				{
					num++;
				}
			}
		}
		galaxy.habitableCount = num;
	}
}
internal sealed class BodyLayout
{
	internal int Index { get; }

	internal int ParentIndex { get; }

	internal int Depth { get; }

	internal bool IsGas { get; }

	internal int OrbitIndex { get; set; }

	internal int SiblingNumber { get; set; }

	internal List<int> Children { get; }

	internal BodyLayout(int index, int parentIndex, int depth, bool isGas)
	{
		Index = index;
		ParentIndex = parentIndex;
		Depth = depth;
		IsGas = isGas;
		Children = new List<int>();
	}
}
internal static class WanderingSystemLayout
{
	internal const int MinimumPrimaryMoons = 2;

	internal const int MaximumPrimaryMoons = 5;

	internal const int MaximumBodies = 6;

	internal const int MaximumDepth = 5;

	internal const double BaseMoonChance = 0.6;

	internal static BodyLayout[] Generate(int seed)
	{
		DeterministicRandom deterministicRandom = new DeterministicRandom((uint)(seed ^ 0x4D4F4F4E));
		List<BodyLayout> list = new List<BodyLayout>(6);
		BodyLayout bodyLayout = AddBody(list, -1, 0, isGas: false);
		int num = 2 + deterministicRandom.NextInt(4);
		for (int i = 0; i < num; i++)
		{
			if (list.Count >= 6)
			{
				break;
			}
			AddBody(list, bodyLayout.Index, 1, RollGas(deterministicRandom));
		}
		for (int j = 0; j < bodyLayout.Children.Count; j++)
		{
			if (list.Count >= 6)
			{
				break;
			}
			AddNestedMoons(list, list[bodyLayout.Children[j]], deterministicRandom);
		}
		AssignSatelliteOrbits(bodyLayout, list);
		return list.ToArray();
	}

	internal static double GetHostChance(int hostDepth)
	{
		if (hostDepth < 0)
		{
			throw new ArgumentOutOfRangeException("hostDepth");
		}
		return Math.Pow(0.6, hostDepth + 1);
	}

	internal static float GetRadiusForDepth(int depth, float originalRadius)
	{
		if (depth == 3)
		{
			return 160f;
		}
		if (depth >= 4)
		{
			return 80f;
		}
		return originalRadius;
	}

	private static BodyLayout AddBody(List<BodyLayout> bodies, int parentIndex, int depth, bool isGas)
	{
		BodyLayout bodyLayout = new BodyLayout(bodies.Count, parentIndex, depth, isGas);
		bodies.Add(bodyLayout);
		if (parentIndex >= 0)
		{
			bodies[parentIndex].Children.Add(bodyLayout.Index);
		}
		return bodyLayout;
	}

	private static void AddNestedMoons(List<BodyLayout> bodies, BodyLayout parent, DeterministicRandom random)
	{
		if (parent.Depth < 5)
		{
			double hostChance = GetHostChance(parent.Depth);
			while (bodies.Count < 6 && random.NextDouble() < hostChance)
			{
				BodyLayout parent2 = AddBody(bodies, parent.Index, parent.Depth + 1, RollGas(random));
				AddNestedMoons(bodies, parent2, random);
			}
		}
	}

	private static bool RollGas(DeterministicRandom random)
	{
		return random.NextDouble() < 0.2;
	}

	private static void AssignSatelliteOrbits(BodyLayout host, IReadOnlyList<BodyLayout> bodies)
	{
		int num = 0;
		for (int i = 0; i < host.Children.Count; i++)
		{
			BodyLayout bodyLayout = bodies[host.Children[i]];
			int num2 = (bodyLayout.IsGas ? 3 : ((bodyLayout.Children.Count > 0) ? 1 : 0));
			bodyLayout.SiblingNumber = i + 1;
			bodyLayout.OrbitIndex = i + 1 + num + num2;
			num += num2 * 2;
			AssignSatelliteOrbits(bodyLayout, bodies);
		}
	}
}
internal static class WarpPatches
{
	[HarmonyPatch]
	private static class WarperStorageAddPatches
	{
		internal static IEnumerable<MethodBase> GetTargetMethods()
		{
			Type byRefInt = typeof(int).MakeByRefType();
			yield return AccessTools.Method(typeof(StorageComponent), "AddItem", new Type[5]
			{
				typeof(int),
				typeof(int),
				typeof(int),
				byRefInt,
				typeof(bool)
			}, (Type[])null);
			yield return AccessTools.Method(typeof(StorageComponent), "AddItemStacked", new Type[4]
			{
				typeof(int),
				typeof(int),
				typeof(int),
				byRefInt
			}, (Type[])null);
			yield return AccessTools.Method(typeof(StorageComponent), "AddItemFiltered", new Type[5]
			{
				typeof(int),
				typeof(int),
				typeof(int),
				byRefInt,
				typeof(bool)
			}, (Type[])null);
			yield return AccessTools.Method(typeof(StorageComponent), "AddItemFilteredBanOnly", new Type[4]
			{
				typeof(int),
				typeof(int),
				typeof(int),
				byRefInt
			}, (Type[])null);
			yield return AccessTools.Method(typeof(StorageComponent), "AddItem", new Type[6]
			{
				typeof(int),
				typeof(int),
				typeof(int),
				typeof(int),
				typeof(int),
				byRefInt
			}, (Type[])null);
			yield return AccessTools.Method(typeof(StorageComponent), "AddItemBanGridFirst", new Type[4]
			{
				typeof(int),
				typeof(int),
				typeof(int),
				byRefInt
			}, (Type[])null);
		}

		private static IEnumerable<MethodBase> TargetMethods()
		{
			return GetTargetMethods();
		}

		[HarmonyPrefix]
		private static void Prefix(StorageComponent __instance, [HarmonyArgument(0)] int itemId)
		{
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: 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)
			Player mainPlayer = GameMain.mainPlayer;
			StorageComponent val = ((mainPlayer == null) ? null : mainPlayer.mecha?.warpStorage);
			if (__instance == val && PrototypeRegistry.IsSupportedWarper(itemId) && __instance.grids != null && __instance.grids.Length != 0)
			{
				GRID val2 = __instance.grids[0];
				if (val2.count <= 0 || val2.itemId == itemId)
				{
					__instance.SetFilterDirect(0, itemId, PrototypeRegistry.GetWarpSlotStackSize(itemId));
				}
			}
		}
	}

	[HarmonyPatch]
	private static class PreventVanillaWarperUseDuringSystemWarpPatch
	{
		private static IEnumerable<MethodBase> TargetMethods()
		{
			yield return AccessTools.Method(typeof(Mecha), "UseWarper", Type.EmptyTypes, (Type[])null);
			yield return AccessTools.Method(typeof(Mecha), "AutoReplenishWarper", Type.EmptyTypes, (Type[])null);
		}

		[HarmonyPrefix]
		private static bool Prefix(Mecha __instance, ref bool __result)
		{
			Player mainPlayer = GameMain.mainPlayer;
			if (__instance != ((mainPlayer != null) ? mainPlayer.mecha : null) || (!IsPlanetaryWarperSlot(__instance.warpStorage) && !MotionController.IsAnySystemWarping() && Time.frameCount > suppressVanillaWarperThroughFrame))
			{
				return true;
			}
			__result = false;
			return false;
		}
	}

	[HarmonyPatch(typeof(PlayerController), "GetInput")]
	private static class CaptureMovementInputForWarpSteeringPatch
	{
		[HarmonyPostfix]
		private static void Postfix(PlayerController __instance)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: 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_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: 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_007a: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)__instance == (Object)null) && ShouldCaptureSteeringInput())
			{
				Vector4 input = __instance.input0;
				input.x = 0f;
				input.y = 0f;
				__instance.input0 = input;
				if (__instance.actionWalk != null)
				{
					__instance.actionWalk.moveVelocity = Vector3.zero;
				}
				if (__instance.actionDrift != null)
				{
					__instance.actionDrift.moveVelocity = Vector3.zero;
				}
				if (__instance.actionFly != null)
				{
					__instance.actionFly.moveVelocity = Vector3.zero;
				}
			}
		}
	}

	[HarmonyPatch(typeof(VFWarpEffect), "Update")]
	private static class WarpVisualPatch
	{
		private struct VisualState
		{
			internal bool Applied;

			internal VFWarpEffect Effect;

			internal Player OriginalPlayer;
		}

		[HarmonyPrefix]
		private static void Prefix(VFWarpEffect __instance, ref VisualState __state)
		{
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Expected O, but got Unknown
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: 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