using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using BetterSolarSystem.Balance;
using GalacticScale;
using GalacticScale.Generators;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using PCGSharp;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyFileVersion("3.2.0.0")]
[assembly: AssemblyVersion("3.2.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Embedded]
[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
internal sealed class RefSafetyRulesAttribute : Attribute
{
public readonly int Version;
public RefSafetyRulesAttribute(int P_0)
{
Version = P_0;
}
}
}
namespace BetterSolarSystem
{
public static class BalancedGeneration
{
public const string SaveMarker = "GS2Tweaks.Balanced.v2";
public const string ResourceMarker = "GS2Tweaks.Resources.v2.2";
public const string LayoutMarker = "GS2Tweaks.Layout.v2.3";
public const float OrbitScale = 1.5f;
public const string JupiterName = "木星";
public const string IoName = "木卫一";
public const string HomeName = "木卫二";
public const string GanymedeName = "木卫三";
public const string CallistoName = "木卫四";
public const string SunMarker = "GS2Tweaks.Sun.v2.1";
public static bool Enabled = true;
public static readonly float[] SolarOrbits = new float[8] { 0.387f, 0.723f, 1f, 1.524f, 5.203f, 9.537f, 19.191f, 30.069f };
public static readonly string[] Profiles = new string[7] { "温带多行星", "紧凑岩质", "外侧巨行星", "热木星", "海洋群岛", "巨星远轨", "遗迹资源" };
private static readonly string[] StarLetters = new string[14]
{
"K", "M", "G", "F", "A", "B", "O", "WD", "RG", "YG",
"WG", "BG", "NS", "BH"
};
private static readonly int[] Frequencies = new int[14]
{
16, 16, 14, 12, 9, 7, 5, 5, 3, 2,
2, 3, 3, 3
};
private static readonly float[][] Layouts = new float[7][]
{
new float[7] { 0.4f, 0.75f, 1f, 1.3f, 1.7f, 3.1f, 6f },
new float[7] { 0.28f, 0.48f, 0.73f, 1f, 1.32f, 1.8f, 3f },
new float[7] { 0.42f, 0.8f, 1.15f, 2.5f, 4.5f, 8f, 13f },
new float[6] { 0.3f, 0.8f, 1.1f, 1.55f, 3f, 6.5f },
new float[7] { 0.45f, 0.83f, 1.08f, 1.35f, 2f, 4.8f, 9f },
new float[6] { 1f, 1.8f, 3f, 5.3f, 9f, 15f },
new float[6] { 0.4f, 0.7f, 1.2f, 2.1f, 4f, 7.5f }
};
public static bool IsManagedGalaxy
{
get
{
if (GSSettings.ThemeLibrary != null)
{
return ((Dictionary<string, GSTheme>)(object)GSSettings.ThemeLibrary).ContainsKey("GS2Tweaks.Balanced.v2");
}
return false;
}
}
public static void Configure(GS2Generator2 gen, int starCount)
{
//IL_0011: Unknown result type (might be due to invalid IL or missing references)
//IL_001b: Expected O, but got Unknown
//IL_0022: Unknown result type (might be due to invalid IL or missing references)
//IL_002c: Expected O, but got Unknown
//IL_0033: Unknown result type (might be due to invalid IL or missing references)
//IL_003d: Expected O, but got Unknown
GSVeinType.random = new Random(GSSettings.Seed);
GSSettings.BirthIron = new GSVein(18, 0.1f);
GSSettings.BirthCopper = new GSVein(18, 0.1f);
Action<string, object> action = delegate(string key, object value)
{
//IL_0008: Unknown result type (might be due to invalid IL or missing references)
//IL_0012: Expected O, but got Unknown
gen.OnUpdate(key, new Val(value));
};
action("birthStar", 3);
action("birthPlanetSize", 300);
action("birthPlanetMoon", true);
action("birthPlanetGasMoon", true);
action("birthPlanetUnlock", true);
action("birthPlanetSiTi", false);
action("birthRareDisable", false);
action("noRaresStartingSystem", true);
action("starSizeMulti", 2f);
action("galaxyDensity", 11);
action("luminosityBoost", 1f);
action("binaryChance", 0);
action("secondarySatellites", false);
action("hugeGasGiants", true);
action("cometsEnabled", false);
int[] array = new int[7] { 20, 50, 100, 200, 300, 400, 500 };
for (int num = 0; num < array.Length; num++)
{
int num2 = array[num];
action("limitPlanetSize" + num2, num2 == 50 || num2 == 200 || num2 == 300);
}
for (int num3 = 0; num3 < StarLetters.Length; num3++)
{
string text = StarLetters[num3];
action("freq" + text, Frequencies[num3]);
int num4 = ((starCount >= 32) ? Math.Max(1, starCount / 64) : 0);
if (starCount >= 64 && (text == "BH" || text == "NS"))
{
num4 *= 2;
}
if (starCount >= 64 && text == "O")
{
num4 *= 3;
}
action(text + "minStars", num4);
action(text + "luminosityBoost", 1f);
}
}
public static void PrepareStars(GSStar birthStar)
{
//IL_0018: Unknown result type (might be due to invalid IL or missing references)
//IL_001e: Expected O, but got Unknown
//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
//IL_00d6: Invalid comparison between Unknown and I4
//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
Random val = new Random(GSSettings.Seed ^ 0x53656374);
List<GSStar> list = ((IEnumerable<GSStar>)GSSettings.Stars).Where((GSStar s) => !s.Decorative && s != birthStar && (int)s.Type == 0).ToList();
for (int num = list.Count - 1; num > 0; num--)
{
int index = ((Pcg)val).Next(num + 1);
GSStar value = list[num];
list[num] = list[index];
list[index] = value;
}
for (int num2 = 0; num2 < list.Count; num2++)
{
list[num2].genData.Set("balancedProfile", Val.op_Implicit(num2 % 5));
}
foreach (GSStar item in (List<GSStar>)(object)GSSettings.Stars)
{
if ((int)item.Type == 1)
{
item.genData.Set("balancedProfile", Val.op_Implicit(5));
}
else if ((int)item.Type != 0)
{
item.genData.Set("balancedProfile", Val.op_Implicit(6));
}
}
birthStar.Name = "太阳 · Sol";
birthStar.radius = 6f;
birthStar.physicsRadius = 7200f;
birthStar.mass = 1f;
birthStar.luminosity = 1f;
birthStar.temperature = 5772f;
birthStar.age = 0.46f;
birthStar.dysonRadius = 1f;
birthStar.genData.Set("balancedProfile", Val.op_Implicit(-1));
HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal);
foreach (GSStar item2 in (List<GSStar>)(object)GSSettings.Stars)
{
string name = item2.Name;
int num3 = 2;
while (!hashSet.Add(item2.Name))
{
item2.Name = name + " · " + num3++;
}
}
}
public static bool BuildSystem(GSStar star, bool birth, ref GSPlanet birthPlanet, Dictionary<GSStar, List<Orbit>> orbitCache)
{
//IL_002c: Unknown result type (might be due to invalid IL or missing references)
//IL_0032: Expected O, but got Unknown
//IL_0033: Unknown result type (might be due to invalid IL or missing references)
//IL_003d: Expected O, but got Unknown
//IL_012a: Unknown result type (might be due to invalid IL or missing references)
//IL_0131: Expected O, but got Unknown
if (!Enabled)
{
return false;
}
if (GSSettings.Instance.imported)
{
throw new InvalidOperationException("Balanced generation cannot rebuild an imported save.");
}
Random rng = new Random(star.Seed ^ 0x506C616E);
star.Planets = new GSPlanets();
if (birth)
{
BuildSolar(star, rng, ref birthPlanet);
}
else
{
BuildVaried(star, rng);
}
foreach (GSPlanet item in (List<GSPlanet>)(object)star.Planets)
{
ExpandOrbits(item);
}
string[] array = new string[4] { "minOrbit", "maxOrbit", "minHZ", "maxHZ" };
foreach (string text in array)
{
star.genData.Set(text, Val.op_Implicit(star.genData.Get(text, (Val)null).Float(-1f) * 1.5f));
}
star.MaxOrbit *= 1.5f;
List<Orbit> list = new List<Orbit>();
foreach (GSPlanet item2 in (List<GSPlanet>)(object)star.Planets)
{
Orbit val = new Orbit(item2.OrbitRadius);
val.planets.Add(item2);
list.Add(val);
}
orbitCache[star] = list;
star.genData.Set("balancedBuilt", Val.op_Implicit(true));
return true;
}
private static void ExpandOrbits(GSPlanet body)
{
bool num = (double)Math.Abs(body.RotationPeriod - body.OrbitalPeriod) < 0.001;
body.OrbitRadius *= 1.5f;
body.OrbitalPeriod = Utils.CalculateOrbitPeriod(body.OrbitRadius, 0.0005f);
if (num)
{
body.RotationPeriod = body.OrbitalPeriod;
}
foreach (GSPlanet item in (List<GSPlanet>)(object)body.Moons)
{
ExpandOrbits(item);
}
}
private static GSPlanet Body(string name, string theme, int radius, bool gas, Random rng)
{
//IL_003c: Unknown result type (might be due to invalid IL or missing references)
//IL_0041: Unknown result type (might be due to invalid IL or missing references)
//IL_0056: Unknown result type (might be due to invalid IL or missing references)
//IL_0063: Unknown result type (might be due to invalid IL or missing references)
//IL_0076: Unknown result type (might be due to invalid IL or missing references)
//IL_008d: Unknown result type (might be due to invalid IL or missing references)
//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
//IL_00ee: Expected O, but got Unknown
return new GSPlanet(name, theme, radius, 0f, 0f, 1f, (float)((Pcg)rng).Next(360), 0f, 600f, (float)((Pcg)rng).Next(360), 1f, (GSPlanets)null)
{
Scale = (gas ? 10f : 1f),
Seed = ((Pcg)rng).Next(),
OrbitLongitude = ((Pcg)rng).Next(360),
Obliquity = rng.NextFloat(0f, 28f),
OrbitInclination = rng.NextFloat(0f, 4f),
RotationPeriod = (gas ? rng.Next(240, 720) : rng.Next(420, 1800)),
veinSettings = ((Dictionary<string, GSTheme>)(object)GSSettings.ThemeLibrary)[theme].VeinSettings.Clone()
};
}
private static void Place(GSPlanet body, float orbit, float solar)
{
body.OrbitRadius = orbit;
body.OrbitalPeriod = Utils.CalculateOrbitPeriod(orbit, 0.0005f);
body.Luminosity = Mathf.Clamp(solar, 0.06f, 4f);
}
private static void AddMoon(GSPlanet host, string name, string theme, int radius, float orbit, Random rng)
{
GSPlanet val = Body(name, theme, radius, gas: false, rng);
Place(val, orbit, 1f);
val.genData.Set("hosttype", Val.op_Implicit("planet"));
val.genData.Set("hostname", Val.op_Implicit(host.Name));
val.OrbitInclination = rng.NextFloat(0f, 8f);
val.RotationPeriod = val.OrbitalPeriod;
host.Moons.Add(val);
}
private static void BuildSolar(GSStar star, Random rng, ref GSPlanet birthPlanet)
{
string[] array = new string[8] { "水星", "金星", "地球", "火星", "木星", "土星", "天王星", "海王星" };
string[] array2 = new string[8] { "Barren", "VolcanicAsh", "Mediterranean", "Gobi", "GasGiant", "GasGiant2", "IceGiant", "IceGiant2" };
int[] array3 = new int[8] { 200, 300, 300, 200, 330, 280, 120, 120 };
float[] array4 = new float[8] { 7f, 3.4f, 0f, 1.85f, 1.3f, 2.49f, 0.77f, 1.77f };
float[] array5 = new float[8] { 0.034f, 177.4f, 23.44f, 25.19f, 3.13f, 26.73f, 97.77f, 28.32f };
for (int i = 0; i < 8; i++)
{
GSPlanet val = Body(array[i], array2[i], array3[i], i >= 4, rng);
val.OrbitInclination = array4[i];
val.Obliquity = array5[i];
Place(val, SolarOrbits[i], 1f / (SolarOrbits[i] * SolarOrbits[i]));
val.genData.Set("hosttype", Val.op_Implicit("star"));
val.genData.Set("hostname", Val.op_Implicit(star.Name));
star.Planets.Add(val);
}
AddMoon(((List<GSPlanet>)(object)star.Planets)[2], "月球", "Barren", 200, 0.04f, rng);
GSPlanet val2 = ((List<GSPlanet>)(object)star.Planets)[4];
AddMoon(val2, "木卫一", "Lava", 200, 0.115f, rng);
AddMoon(val2, "木卫二", "Prairie", 300, 0.175f, rng);
AddMoon(val2, "木卫三", "IceGelisol", 200, 0.245f, rng);
AddMoon(val2, "木卫四", "IceGelisol2", 200, 0.325f, rng);
AddMoon(val2, "木卫五", "Barren", 50, 0.395f, rng);
birthPlanet = ((List<GSPlanet>)(object)val2.Moons)[1];
birthPlanet.genData.Set("birthPlanet", Val.op_Implicit(true));
birthPlanet.RotationPeriod = 600f;
birthPlanet.Obliquity = 8f;
AddMoon(((List<GSPlanet>)(object)star.Planets)[5], "土卫二", "IceLake", 200, 0.11f, rng);
AddMoon(((List<GSPlanet>)(object)star.Planets)[5], "土卫六", "AshenGelisol", 200, 0.19f, rng);
AddMoon(((List<GSPlanet>)(object)star.Planets)[5], "土卫八", "IceGelisol2", 200, 0.28f, rng);
AddMoon(((List<GSPlanet>)(object)star.Planets)[6], "天卫三", "IceGelisol3", 200, 0.07f, rng);
AddMoon(((List<GSPlanet>)(object)star.Planets)[6], "天卫四", "CrystalDesert", 200, 0.13f, rng);
AddMoon(((List<GSPlanet>)(object)star.Planets)[7], "海卫一", "IceGelisol", 200, 0.08f, rng);
GSPlanet val3 = Body("谷神星", "Barren", 50, gas: false, rng);
Place(val3, 2.77f, 0.13f);
star.Planets.Add(val3);
GSPlanet val4 = Body("冥王星", "IceGelisol", 50, gas: false, rng);
Place(val4, 39.482f, 0.06f);
val4.OrbitInclination = 17.16f;
AddMoon(val4, "卡戎", "IceGelisol2", 50, 0.025f, rng);
star.Planets.Add(val4);
((List<GSPlanet>)(object)star.Planets).Sort((Comparison<GSPlanet>)((GSPlanet a, GSPlanet b) => a.OrbitRadius.CompareTo(b.OrbitRadius)));
star.genData.Set("minOrbit", Val.op_Implicit(0.3f));
star.genData.Set("maxOrbit", Val.op_Implicit(42f));
star.genData.Set("minHZ", Val.op_Implicit(0.95f));
star.genData.Set("maxHZ", Val.op_Implicit(1.67f));
foreach (GSPlanet item in (List<GSPlanet>)(object)star.Planets)
{
foreach (GSPlanet item2 in (List<GSPlanet>)(object)item.Moons)
{
item2.Luminosity = ((item2 == birthPlanet) ? 1f : item.Luminosity);
}
}
}
private static bool GasSlot(int profile, int i, int length)
{
switch (profile)
{
case 2:
return i >= 3;
case 3:
if (i != 0)
{
return i == length - 1;
}
return true;
case 1:
case 6:
return i == length - 1;
default:
return i >= length - 2;
}
}
private static EThemeHeat Heat(float distance)
{
if (!(distance < 0.5f))
{
if (!(distance < 0.82f))
{
if (!(distance <= 1.7f))
{
if (!(distance < 5f))
{
return (EThemeHeat)4;
}
return (EThemeHeat)3;
}
return (EThemeHeat)2;
}
return (EThemeHeat)1;
}
return (EThemeHeat)0;
}
private unsafe static string Theme(Random rng, EThemeHeat heat, int radius, bool moon, bool habitable, HashSet<string> used)
{
//IL_0036: Unknown result type (might be due to invalid IL or missing references)
//IL_0038: Expected I4, but got Unknown
float[] array = new float[6] { 3f, 1f, 0f, -3f, -6f, 6f };
int num = (int)heat;
float low = array[num];
float high = ((num == 0) ? 6f : array[num - 1]);
List<string> list = (from t in ((Dictionary<string, GSTheme>)(object)GSSettings.ThemeLibrary).Values
where ((int)t.ThemeType == 5 || (int)t.ThemeType == (moon ? 3 : 2)) && (int)t.PlanetType != 5 && t.MinRadius <= radius && t.MaxRadius >= radius && t.Temperature >= low && t.Temperature < high && (!habitable || t.Habitable)
select t.Name).Distinct().OrderBy<string, string>((string n) => n, StringComparer.Ordinal).ToList();
if (list.Count == 0)
{
throw new InvalidOperationException("No supported theme for " + ((object)(*(EThemeHeat*)(&heat))/*cast due to .constrained prefix*/).ToString() + "/" + radius);
}
List<string> list2 = list.Where((string n) => !used.Contains(n)).ToList();
if (list2.Count > 0)
{
list = list2;
}
string text = list[((Pcg)rng).Next(list.Count)];
used.Add(text);
return text;
}
private static void BuildVaried(GSStar star, Random rng)
{
//IL_0024: Unknown result type (might be due to invalid IL or missing references)
//IL_002a: Expected O, but got Unknown
//IL_04f8: Unknown result type (might be due to invalid IL or missing references)
//IL_04ff: Expected O, but got Unknown
//IL_01ee: Unknown result type (might be due to invalid IL or missing references)
//IL_01fe: Unknown result type (might be due to invalid IL or missing references)
//IL_0205: Unknown result type (might be due to invalid IL or missing references)
//IL_020e: Unknown result type (might be due to invalid IL or missing references)
//IL_0211: Invalid comparison between Unknown and I4
//IL_02c7: Unknown result type (might be due to invalid IL or missing references)
int num = star.genData.Get("balancedProfile", (Val)null).Int(0);
Random val = new Random(star.Seed ^ 0x436F756E);
int num2 = ((Pcg)val).Next(100);
int num3 = ((num2 < 12) ? 1 : ((num2 < 32) ? 2 : ((num2 < 54) ? 3 : ((num2 < 72) ? 4 : ((num2 < 84) ? 5 : ((num2 < 92) ? 6 : ((num2 < 97) ? 7 : 8)))))));
star.genData.Set("primaryCount", Val.op_Implicit(num3));
float[] array = Layouts[num];
float[] array2 = new float[num3];
for (int i = 0; i < num3; i++)
{
float num4 = ((num3 == 1) ? ((num == 6) ? 0.55f : 0.3f) : ((float)i / (float)(num3 - 1))) * (float)(array.Length - 1);
int num5 = (int)num4;
int num6 = Math.Min(num5 + 1, array.Length - 1);
array2[i] = array[num5] + (array[num6] - array[num5]) * (num4 - (float)num5);
}
float num7 = Mathf.Clamp((float)Math.Pow(Math.Max(0.05f, star.luminosity), 0.25), 0.7f, 2.2f);
float num8 = star.RadiusAU * 1.3f;
HashSet<string> used = new HashSet<string>();
float num9 = star.RadiusAU + 0.05f;
for (int j = 0; j < array2.Length; j++)
{
bool flag = num3 > 1 && GasSlot(num, j, array2.Length) && (j > 0 || num == 3);
bool flag2 = array2[j] >= 4f;
if (num == 3 && num3 == 2 && j == 1)
{
flag = false;
}
int num10 = ((!flag) ? ((((Pcg)rng).NextDouble() < 0.55) ? 300 : 200) : (flag2 ? (rng.Next(12, 19) * 10) : (rng.Next(22, 41) * 10)));
EThemeHeat val2 = (EThemeHeat)((num != 6) ? ((int)Heat(array2[j])) : ((j < 3) ? 3 : 4));
string theme = ((!flag) ? Theme(rng, val2, num10, moon: false, num == 4 && (int)val2 == 2, used) : ((!flag2) ? ((j % 2 == 0) ? "GasGiant" : "GasGiant2") : ((j % 2 == 0) ? "IceGiant" : "IceGiant2")));
GSPlanet val3 = Body(star.Name + " " + (j + 1), theme, num10, flag, rng);
int num11 = ((!flag) ? ((num10 == 300 && ((Pcg)rng).NextDouble() < 0.15) ? 1 : 0) : ((num == 2) ? rng.Next(1, 4) : rng.Next(0, 3)));
float num12 = val3.RadiusAU + 0.035f;
for (int k = 0; k < num11; k++)
{
string theme2 = Theme(rng, val2, 200, moon: true, habitable: false, used);
AddMoon(val3, val3.Name + "-" + (k + 1), theme2, 200, num12, rng);
num12 += 0.035f + rng.NextFloat(0f, 0.025f);
}
float num13 = Math.Max(num8 + array2[j] * num7 * rng.NextFloat(0.97f, 1.03f), num9 + Envelope(val3) + 0.06f);
Place(val3, num13, 1f / (array2[j] * array2[j]));
foreach (GSPlanet item in (List<GSPlanet>)(object)val3.Moons)
{
item.Luminosity = val3.Luminosity;
}
val3.genData.Set("hosttype", Val.op_Implicit("star"));
val3.genData.Set("hostname", Val.op_Implicit(star.Name));
star.Planets.Add(val3);
num9 = num13 + Envelope(val3);
}
int num14 = ((((Pcg)val).NextDouble() < ((num == 6) ? 0.65 : 0.25)) ? 1 : 0);
for (int l = 0; l < num14; l++)
{
string theme3 = Theme(rng, (EThemeHeat)((l == 0) ? 4 : 3), 50, moon: false, habitable: false, used);
GSPlanet val4 = Body(star.Name + " · " + ((l == 0) ? "外带" : "碎片"), theme3, 50, gas: false, rng);
Place(val4, num9 + 0.35f + 0.3f * (float)l, 0.06f);
val4.OrbitInclination = rng.NextFloat(8f, 24f);
star.Planets.Add(val4);
num9 = val4.OrbitRadius + val4.RadiusAU;
}
Random rng2 = new Random(star.Seed ^ 0x536D616C);
List<GSPlanet> list = ((IEnumerable<GSPlanet>)star.Planets).Where((GSPlanet p) => p.Scale == 10f && ((List<GSPlanet>)(object)p.Moons).Count >= 2).ToList();
int num15 = ((IEnumerable<GSPlanet>)star.Planets).Sum((GSPlanet p) => ((List<GSPlanet>)(object)p.Moons).Count);
int num16 = Math.Min(list.Count, num15 / 3);
for (int num17 = 0; num17 < num16; num17++)
{
GSPlanet val5 = list[num17];
float num18 = ((List<GSPlanet>)(object)val5.Moons)[0].OrbitRadius - ((List<GSPlanet>)(object)val5.Moons)[0].RadiusAU;
float orbit = val5.RadiusAU + (num18 - val5.RadiusAU) * 0.5f;
AddMoon(val5, val5.Name + " · 星砂", val5.Theme.StartsWith("IceGiant") ? "IceGelisol2" : "Barren", 50, orbit, rng2);
((List<GSPlanet>)(object)val5.Moons).Sort((Comparison<GSPlanet>)((GSPlanet a, GSPlanet b) => a.OrbitRadius.CompareTo(b.OrbitRadius)));
foreach (GSPlanet item2 in (List<GSPlanet>)(object)val5.Moons)
{
item2.Luminosity = val5.Luminosity;
}
}
star.genData.Set("minOrbit", Val.op_Implicit(star.RadiusAU + 0.05f));
star.genData.Set("maxOrbit", Val.op_Implicit(num9 + 1f));
star.genData.Set("minHZ", Val.op_Implicit(num8 + 0.82f * num7));
star.genData.Set("maxHZ", Val.op_Implicit(num8 + 1.7f * num7));
}
public static float Envelope(GSPlanet body)
{
float num = body.RadiusAU;
foreach (GSPlanet item in (List<GSPlanet>)(object)body.Moons)
{
num = Math.Max(num, item.OrbitRadius + Envelope(item));
}
return num;
}
public static IEnumerable<GSPlanet> Bodies(GSPlanet body)
{
yield return body;
foreach (GSPlanet item in (List<GSPlanet>)(object)body.Moons)
{
foreach (GSPlanet item2 in Bodies(item))
{
yield return item2;
}
}
}
private static void EnsureVein(GSPlanet body, EVeinType kind, int groups, int count, float richness)
{
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_0008: 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_0071: Expected O, but got Unknown
//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
//IL_00ac: Expected O, but got Unknown
GSVeinType val = ((IEnumerable<GSVeinType>)body.veinSettings.VeinTypes).FirstOrDefault((Func<GSVeinType, bool>)((GSVeinType v) => v.type == kind));
if (val == null || val.rare || !val.veins.Any((GSVein v) => v.count > 0))
{
if (val == null)
{
val = new GSVeinType(kind);
body.veinSettings.VeinTypes.Add(val);
}
val.rare = false;
val.veins = new List<GSVein>();
for (int num = 0; num < groups; num++)
{
val.veins.Add(new GSVein(count, richness));
}
}
}
private static int BaseNodeBudget(GSPlanet body)
{
if (body.Radius != 50)
{
if (!(body.Name == GSSettings.BirthPlanetName))
{
return 420;
}
return 384;
}
return 80;
}
public static int NodeBudget(GSPlanet body)
{
return BaseNodeBudget(body) * ((body.Radius != 300) ? 1 : 2);
}
public static int Nodes(GSPlanet body)
{
//IL_0040: Unknown result type (might be due to invalid IL or missing references)
//IL_0046: Invalid comparison between Unknown and I4
if (body.veinSettings == null)
{
return 0;
}
int num = 0;
foreach (GSVeinType item in (List<GSVeinType>)(object)body.veinSettings.VeinTypes)
{
foreach (GSVein vein in item.veins)
{
num += (((int)item.type == 7) ? 1 : Math.Max(1, vein.count));
}
}
return num;
}
public static void NormalizeResources(GSPlanet body)
{
//IL_0138: Unknown result type (might be due to invalid IL or missing references)
//IL_013e: Expected O, but got Unknown
//IL_0180: Unknown result type (might be due to invalid IL or missing references)
//IL_0186: Invalid comparison between Unknown and I4
//IL_0369: Unknown result type (might be due to invalid IL or missing references)
//IL_036f: Invalid comparison between Unknown and I4
//IL_03ef: Unknown result type (might be due to invalid IL or missing references)
//IL_03f5: Invalid comparison between Unknown and I4
if (body.Scale == 10f || body.veinSettings == null)
{
return;
}
GSVeinTypes veinTypes = body.veinSettings.VeinTypes;
((List<GSVeinType>)(object)veinTypes).RemoveAll((Predicate<GSVeinType>)((GSVeinType vt) => vt.veins.Count == 0));
if (body.Radius == 50)
{
List<GSVeinType> retained = (from vt in (IEnumerable<GSVeinType>)veinTypes
orderby (int)vt.type > 7 descending, (int)vt.type
select vt).Take(5).ToList();
((List<GSVeinType>)(object)veinTypes).RemoveAll((Predicate<GSVeinType>)((GSVeinType vt) => !retained.Contains(vt)));
foreach (GSVeinType item in (List<GSVeinType>)(object)veinTypes)
{
item.veins = item.veins.Take(1).Select((Func<GSVein, GSVein>)((GSVein v) => new GSVein(v.count, Math.Max(0.1f, v.richness) * 0.25f))).ToList();
}
}
Random val = new Random(body.Seed ^ 0x4F726532);
Dictionary<GSVeinType, double> dictionary = new Dictionary<GSVeinType, double>();
foreach (GSVeinType item2 in ((IEnumerable<GSVeinType>)veinTypes).OrderBy((GSVeinType vt) => (int)vt.type))
{
if ((int)item2.type == 7)
{
item2.veins = item2.veins.Take((body.Radius == 50) ? 1 : 12).ToList();
foreach (GSVein vein in item2.veins)
{
vein.count = 1;
vein.richness = 0.7f;
}
continue;
}
dictionary[item2] = item2.veins.Sum((GSVein v) => (double)Math.Max(1, (v.count < 0) ? 20 : v.count) * (double)((Finite(v.richness) && v.richness > 0f) ? v.richness : 0.6f));
foreach (GSVein vein2 in item2.veins)
{
vein2.count = ((body.Radius == 50) ? val.Next(12, 17) : val.Next(16, 25));
}
}
while (Nodes(body) > BaseNodeBudget(body))
{
GSVeinType val2 = (from vt in (IEnumerable<GSVeinType>)veinTypes
where (int)vt.type != 7 && vt.veins.Count > 1
orderby vt.veins.Count descending, (int)vt.type
select vt).FirstOrDefault();
if (val2 == null)
{
throw new InvalidOperationException("Cannot fit natural deposits: " + body.Name);
}
val2.veins.RemoveAt(val2.veins.Count - 1);
}
foreach (GSVeinType item3 in (List<GSVeinType>)(object)veinTypes)
{
if ((int)item3.type != 7)
{
float richness = (float)(dictionary[item3] / (double)item3.veins.Sum((GSVein v) => v.count));
foreach (GSVein vein3 in item3.veins)
{
vein3.richness = richness;
}
}
if (body.Radius == 300 && (int)item3.type != 7)
{
item3.veins.AddRange(item3.veins.Select((GSVein v) => v.Clone()).ToList());
}
item3.veins = (from v in item3.veins
orderby v.count, v.richness
select v).ToList();
}
body.randomizeVeinCounts = false;
}
public static int OilAmount(int planetSeed, int groupIndex, float speedMultiplier)
{
//IL_002a: Unknown result type (might be due to invalid IL or missing references)
//IL_0030: Expected O, but got Unknown
if (!Finite(speedMultiplier) || speedMultiplier <= 0f)
{
throw new ArgumentOutOfRangeException("speedMultiplier");
}
Random val = new Random(planetSeed ^ (groupIndex * 16777619) ^ 0x4F494C32);
double num = 1.5 + ((Pcg)val).NextDouble() * 4.5;
return Math.Max(1, (int)Math.Round(num / (double)speedMultiplier, MidpointRounding.ToEven));
}
public static void AddMarker(string key)
{
if (!((Dictionary<string, GSTheme>)(object)GSSettings.ThemeLibrary).ContainsKey(key))
{
GSTheme val = ((Dictionary<string, GSTheme>)(object)GSSettings.ThemeLibrary)["Barren"].Clone();
val.Name = key;
val.DisplayName = key;
val.ThemeType = (EThemeType)4;
GSSettings.ThemeLibrary.Add(key, val);
}
}
public static bool UpgradeSun()
{
if (!IsManagedGalaxy || ((Dictionary<string, GSTheme>)(object)GSSettings.ThemeLibrary).ContainsKey("GS2Tweaks.Sun.v2.1"))
{
return false;
}
GSStar birthStar = GSSettings.BirthStar;
if (birthStar == null || birthStar.Name != "太阳 · Sol")
{
return false;
}
birthStar.radius = 6f;
birthStar.physicsRadius = 7200f;
AddMarker("GS2Tweaks.Sun.v2.1");
return true;
}
public static void Finish()
{
//IL_006c: Unknown result type (might be due to invalid IL or missing references)
//IL_0076: Expected O, but got Unknown
//IL_0165: Unknown result type (might be due to invalid IL or missing references)
//IL_016b: Invalid comparison between Unknown and I4
//IL_0195: Unknown result type (might be due to invalid IL or missing references)
//IL_019b: Invalid comparison between Unknown and I4
//IL_016e: Unknown result type (might be due to invalid IL or missing references)
//IL_0174: Invalid comparison between Unknown and I4
//IL_012d: Unknown result type (might be due to invalid IL or missing references)
//IL_0131: Unknown result type (might be due to invalid IL or missing references)
//IL_02c2: Unknown result type (might be due to invalid IL or missing references)
//IL_02c6: Unknown result type (might be due to invalid IL or missing references)
if (IsManagedGalaxy)
{
return;
}
GSPlanet birthPlanet = GSSettings.BirthPlanet;
foreach (GSStar item in (List<GSStar>)(object)GSSettings.Stars)
{
foreach (GSPlanet item2 in (List<GSPlanet>)(object)item.Planets)
{
foreach (GSPlanet item3 in Bodies(item2))
{
if (item3.Scale == 10f)
{
item3.veinSettings = new GSVeinSettings();
continue;
}
if (item3.veinSettings == null)
{
item3.veinSettings = item3.GsTheme.VeinSettings.Clone();
}
if (item3 == birthPlanet)
{
EnsureVein(item3, (EVeinType)5, 5, 10, 0.7f);
EnsureVein(item3, (EVeinType)1, 7, 12, 0.8f);
EnsureVein(item3, (EVeinType)2, 5, 10, 0.8f);
EnsureVein(item3, (EVeinType)6, 5, 10, 0.8f);
EnsureVein(item3, (EVeinType)7, 8, 1, 0.7f);
EnsureVein(item3, (EVeinType)3, 3, 8, 0.6f);
EnsureVein(item3, (EVeinType)4, 3, 8, 0.6f);
EVeinType[] array = (EVeinType[])(object)new EVeinType[2]
{
(EVeinType)13,
(EVeinType)11
};
foreach (EVeinType kind in array)
{
EnsureVein(item3, kind, 2, 20, 0.8f);
}
item3.randomizeVeinCounts = false;
}
if (item3.Radius >= 200 && ((int)item.Type == 4 || (int)item.Type == 3))
{
EnsureVein(item3, (EVeinType)14, 4, 8, 0.75f);
}
if (item3.Radius >= 200 && (int)item.Type == 2)
{
EnsureVein(item3, (EVeinType)12, 3, 8, 0.7f);
EnsureVein(item3, (EVeinType)8, 3, 8, 0.7f);
}
if (item == GSSettings.BirthStar && item2.Name == "木星")
{
if (item3.Name == "木卫一")
{
EnsureVein(item3, (EVeinType)9, 2, 20, 0.8f);
}
if (item3.Name == "木卫三")
{
EnsureVein(item3, (EVeinType)12, 2, 20, 0.8f);
}
if (item3.Name == "木卫四")
{
EnsureVein(item3, (EVeinType)3, 3, 20, 0.8f);
EnsureVein(item3, (EVeinType)4, 3, 20, 0.8f);
}
item3.randomizeVeinCounts = false;
}
if (item3.Radius == 50 && item3 != item2)
{
int num;
if (!item3.Name.StartsWith("卡戎") && !(item3.Name == "木卫五"))
{
EVeinType[] array2 = new EVeinType[4];
RuntimeHelpers.InitializeArray(array2, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/);
num = (int)array2[(item3.Seed & 0x7FFFFFFF) % 4];
}
else
{
num = 10;
}
EVeinType kind2 = (EVeinType)num;
EnsureVein(item3, kind2, 1, 16, 2f);
if (item3.Name.StartsWith("卡戎"))
{
EnsureVein(item3, (EVeinType)8, 1, 16, 2f);
}
}
if (item == GSSettings.BirthStar && item3.Name == "木卫四")
{
EnsureVein(item3, (EVeinType)10, 2, 20, 0.8f);
}
NormalizeResources(item3);
}
}
}
AddMarker("GS2Tweaks.Balanced.v2");
AddMarker("GS2Tweaks.Resources.v2.2");
AddMarker("GS2Tweaks.Sun.v2.1");
AddMarker("GS2Tweaks.Layout.v2.3");
AddMarker("LivingWorlds.Generation.v1");
AddMarker("BetterSolarSystem.Surface.v3.1");
Validate();
}
public static void Validate()
{
int num = 0;
GSPlanet birthPlanet = GSSettings.BirthPlanet;
HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal);
HashSet<string> hashSet2 = new HashSet<string>(StringComparer.Ordinal);
foreach (GSStar item in (List<GSStar>)(object)GSSettings.Stars)
{
if (!hashSet.Add(item.Name))
{
throw new InvalidOperationException("Duplicate star name: " + item.Name);
}
if (item.Decorative)
{
continue;
}
float num2 = item.RadiusAU;
foreach (GSPlanet item2 in (List<GSPlanet>)(object)item.Planets)
{
if (item2.OrbitRadius - Envelope(item2) <= num2)
{
throw new InvalidOperationException("Orbit envelopes overlap: " + item2.Name);
}
num2 = item2.OrbitRadius + Envelope(item2);
foreach (GSPlanet item3 in Bodies(item2))
{
if (!hashSet2.Add(item3.Name))
{
throw new InvalidOperationException("Duplicate body name: " + item3.Name);
}
bool flag = item3 != item2;
if (item3 == birthPlanet)
{
num++;
if (!flag || item3.Radius != 300 || item3.Theme != "Prairie")
{
throw new InvalidOperationException("Invalid birth moon");
}
}
else if (flag && ((item3.Radius != 200 && item3.Radius != 50) || item3.Scale != 1f))
{
throw new InvalidOperationException("Invalid moon size: " + item3.Name);
}
if (item3.Scale != 10f && item3.Radius != 50 && item3.Radius != 200 && item3.Radius != 300)
{
throw new InvalidOperationException("Invalid planet size: " + item3.Name);
}
if (item3.Scale == 10f && (float)item3.Radius * item3.Scale < 1000f)
{
throw new InvalidOperationException("Gas giant too small");
}
if (!Finite(item3.OrbitRadius) || item3.OrbitRadius <= 0f || !Finite(item3.OrbitalPeriod) || item3.OrbitalPeriod <= 0f)
{
throw new InvalidOperationException("Invalid orbit: " + item3.Name);
}
float num3 = item3.RadiusAU;
foreach (GSPlanet item4 in (List<GSPlanet>)(object)item3.Moons)
{
if (item4.OrbitRadius - Envelope(item4) <= num3)
{
throw new InvalidOperationException("Moon orbit overlap: " + item4.Name);
}
num3 = item4.OrbitRadius + Envelope(item4);
}
if (item3.Scale != 10f && Nodes(item3) > NodeBudget(item3))
{
throw new InvalidOperationException("Vein budget exceeded: " + item3.Name);
}
}
}
int num4 = ((IEnumerable<GSPlanet>)item.Planets).SelectMany((GSPlanet p) => Bodies(p).Skip(1)).Count((GSPlanet p) => p.Radius == 50);
int num5 = ((IEnumerable<GSPlanet>)item.Planets).SelectMany((GSPlanet p) => Bodies(p).Skip(1)).Count((GSPlanet p) => p.Radius == 200);
if (num4 > 0 && num4 >= num5)
{
throw new InvalidOperationException("Small moons must remain a minority: " + item.Name);
}
if (item.bodyCount >= 100 || num2 > item.MaxOrbit)
{
throw new InvalidOperationException("System capacity exceeded: " + item.Name);
}
}
if (num != 1)
{
throw new InvalidOperationException("Birth moon is not unique");
}
}
private static bool Finite(float value)
{
if (!float.IsNaN(value))
{
return !float.IsInfinity(value);
}
return false;
}
}
internal static class ConfigMigration
{
private static readonly Dictionary<string, ConfigFile> LegacyFiles = new Dictionary<string, ConfigFile>();
public static T LegacyValue<T>(string guid, string section, string key, T fallback)
{
//IL_0032: Unknown result type (might be due to invalid IL or missing references)
//IL_0037: Unknown result type (might be due to invalid IL or missing references)
if (!LegacyFiles.TryGetValue(guid, out var value))
{
string text = Path.Combine(Paths.ConfigPath, guid + ".cfg");
value = ((!File.Exists(text)) ? ((ConfigFile)null) : new ConfigFile(text, false)
{
SaveOnConfigSet = false
});
LegacyFiles[guid] = value;
}
if (value != null)
{
return value.Bind<T>(section, key, fallback, (ConfigDescription)null).Value;
}
return fallback;
}
public static ConfigEntry<T> BindLegacy<T>(ConfigFile config, string guid, string section, string key, T fallback, string description)
{
return config.Bind<T>(section, key, LegacyValue(guid, section, key, fallback), description);
}
public static ConfigEntry<T> BindDefense<T>(ConfigFile config, string section, string key, T fallback, ConfigDescription description)
{
return config.Bind<T>("Balance - Defense / 防御 - " + section, key, LegacyValue("com.myself.globalsignaltower", section, key, fallback), description);
}
public static ConfigEntry<T> BindDefense<T>(ConfigFile config, string section, string key, T fallback, string description)
{
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
//IL_0016: Expected O, but got Unknown
return BindDefense(config, section, key, fallback, new ConfigDescription(description, (AcceptableValueBase)null, Array.Empty<object>()));
}
}
public static class LegacyVeins
{
public const string Marker = "GS2Tweaks.LegacyRepaired.v2";
public static int Repair(float baseRadius = 200f, float exponent = 1f, bool scaleRare = false)
{
//IL_0151: Unknown result type (might be due to invalid IL or missing references)
//IL_0158: Invalid comparison between Unknown and I4
//IL_0164: Unknown result type (might be due to invalid IL or missing references)
//IL_016b: Invalid comparison between Unknown and I4
//IL_0177: Unknown result type (might be due to invalid IL or missing references)
//IL_017e: Invalid comparison between Unknown and I4
//IL_018a: Unknown result type (might be due to invalid IL or missing references)
//IL_0191: Invalid comparison between Unknown and I4
//IL_027c: Unknown result type (might be due to invalid IL or missing references)
//IL_0282: Invalid comparison between Unknown and I4
//IL_02a1: Unknown result type (might be due to invalid IL or missing references)
//IL_02a7: Invalid comparison between Unknown and I4
//IL_02cd: Unknown result type (might be due to invalid IL or missing references)
//IL_02d3: Invalid comparison between Unknown and I4
//IL_02ed: Unknown result type (might be due to invalid IL or missing references)
//IL_02f7: Expected O, but got Unknown
ThemeLibrary themeLibrary = GSSettings.ThemeLibrary;
if (themeLibrary == null || BalancedGeneration.IsManagedGalaxy || ((Dictionary<string, GSTheme>)(object)themeLibrary).ContainsKey("GS2Tweaks.LegacyRepaired.v2"))
{
return 0;
}
int num = 0;
foreach (GSStar item in (List<GSStar>)(object)GSSettings.Stars)
{
foreach (GSPlanet item2 in (List<GSPlanet>)(object)item.Planets)
{
foreach (GSPlanet item3 in BalancedGeneration.Bodies(item2))
{
if (item3.Scale == 10f || item3.veinSettings == null || !((Dictionary<string, GSTheme>)(object)themeLibrary).ContainsKey(item3.Theme))
{
continue;
}
GSVeinSettings veinSettings = ((Dictionary<string, GSTheme>)(object)themeLibrary)[item3.Theme].VeinSettings;
int num2 = Mathf.Clamp(Mathf.RoundToInt(Mathf.Pow((float)item3.Radius / Mathf.Max(1f, baseRadius), exponent)), 1, 4);
foreach (GSVeinType vt in (List<GSVeinType>)(object)item3.veinSettings.VeinTypes)
{
if (vt.veins == null || vt.veins.Count == 0 || (item3.Name == GSSettings.BirthPlanetName && !vt.rare && ((int)vt.type == 13 || (int)vt.type == 11 || (int)vt.type == 12 || (int)vt.type == 9)))
{
continue;
}
GSVeinType val = ((IEnumerable<GSVeinType>)veinSettings?.VeinTypes).FirstOrDefault((Func<GSVeinType, bool>)((GSVeinType t) => t.type == vt.type));
if (val == null)
{
if (NonUniformMirror(vt.veins))
{
vt.veins.RemoveRange(vt.veins.Count / 2, vt.veins.Count / 2);
num++;
}
}
else
{
if (val.veins.Count == 0)
{
continue;
}
List<GSVein> list = new List<GSVein>();
foreach (GSVein vein in val.veins)
{
int num3 = ((vein.count < 0) ? 12 : vein.count);
int num4 = ((vt.rare && !scaleRare) ? 1 : num2);
if ((int)vt.type != 7)
{
num4 = Math.Min(num4, Math.Max(1, num3));
}
for (int num5 = 0; num5 < num4; num5++)
{
int num6 = (((int)vt.type == 7) ? 1 : (num3 / num4 + ((num5 < num3 % num4) ? 1 : 0)));
if (num6 > 0)
{
list.Add(new GSVein(num6, ((int)vt.type == 7) ? vein.richness : (vein.richness * (float)num3 / (float)num6)));
}
}
}
vt.veins = list;
num++;
}
}
}
}
}
if (!((Dictionary<string, GSTheme>)(object)themeLibrary).ContainsKey("Barren"))
{
throw new InvalidOperationException("Legacy repair needs Barren marker template");
}
GSTheme val2 = ((Dictionary<string, GSTheme>)(object)themeLibrary)["Barren"].Clone();
val2.Name = "GS2Tweaks.LegacyRepaired.v2";
val2.ThemeType = (EThemeType)4;
val2.DisplayName = "GS2Tweaks historical vein repair version 2";
themeLibrary.Add("GS2Tweaks.LegacyRepaired.v2", val2);
return num;
}
private static bool NonUniformMirror(List<GSVein> veins)
{
if (veins.Count < 4 || veins.Count % 2 != 0)
{
return false;
}
int num = veins.Count / 2;
bool result = false;
for (int i = 0; i < num; i++)
{
if (veins[i].count != veins[i + num].count || Math.Abs(veins[i].richness - veins[i + num].richness) > 0.0001f)
{
return false;
}
if (i > 0 && (veins[i].count != veins[0].count || Math.Abs(veins[i].richness - veins[0].richness) > 0.0001f))
{
result = true;
}
}
return result;
}
}
[BepInPlugin("cmx.BetterSolarSystem", "BetterSolarSystem", "3.2.0")]
[BepInIncompatibility("cmx.GS2Tweaks")]
[BepInIncompatibility("com.myself.globalsignaltower")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public sealed class Plugin : BaseUnityPlugin
{
public const string PluginGuid = "cmx.BetterSolarSystem";
public const string PluginName = "BetterSolarSystem";
public const string PluginVersion = "3.2.0";
internal static ManualLogSource Log;
internal static ConfigEntry<float> VeinBaseRadius;
internal static ConfigEntry<float> VeinExponent;
internal static ConfigEntry<bool> ScaleRareVeins;
internal static ConfigEntry<bool> SanitizeLegacySaves;
private Harmony harmony;
private Harmony travelHarmony;
private Harmony defenseHarmony;
private void Awake()
{
//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
//IL_00b7: Expected O, but got Unknown
//IL_0139: Unknown result type (might be due to invalid IL or missing references)
//IL_014e: Unknown result type (might be due to invalid IL or missing references)
//IL_015a: Expected O, but got Unknown
//IL_015a: Expected O, but got Unknown
//IL_0189: Unknown result type (might be due to invalid IL or missing references)
//IL_0195: Expected O, but got Unknown
//IL_0254: Unknown result type (might be due to invalid IL or missing references)
//IL_025e: Expected O, but got Unknown
//IL_02ae: Unknown result type (might be due to invalid IL or missing references)
//IL_02b8: Expected O, but got Unknown
Log = ((BaseUnityPlugin)this).Logger;
VeinBaseRadius = ConfigMigration.BindLegacy(((BaseUnityPlugin)this).Config, "cmx.GS2Tweaks", "1 - Vein clusters / 矿团", "Base radius / 基准半径", 200f, "Legacy save repair only. New generation uses the balanced contract.");
VeinExponent = ConfigMigration.BindLegacy(((BaseUnityPlugin)this).Config, "cmx.GS2Tweaks", "1 - Vein clusters / 矿团", "Exponent / 指数", 1f, "Legacy save repair only.");
ScaleRareVeins = ConfigMigration.BindLegacy(((BaseUnityPlugin)this).Config, "cmx.GS2Tweaks", "1 - Vein clusters / 矿团", "Scale rare veins / 稀有矿也缩放", fallback: false, "Legacy save repair only.");
SanitizeLegacySaves = ConfigMigration.BindLegacy(((BaseUnityPlugin)this).Config, "cmx.GS2Tweaks", "4 - Legacy saves / 旧存档修复", "Sanitize on load / 读档时修复", fallback: true, "Repair historical vein tables; never alter saved geometry.");
harmony = new Harmony("cmx.BetterSolarSystem");
Patch(typeof(GameData), "Import", null, "GameImportPostfix");
Patch(typeof(PlanetData), "RegenerateName", "PlanetNamePrefix");
Patch(typeof(GS2Generator2), "Generate", "GeneratePrefix", "GeneratePostfix");
harmony.Patch((MethodBase)AccessTools.Method(typeof(GS2Generator2), "GenerateStars", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(Patches), "StarsPostfix", (Type[])null), new HarmonyMethod(typeof(RuntimeCompatibility), "RepairStarNameCall", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null);
harmony.Patch((MethodBase)AccessTools.Method(typeof(GS2Generator3), "GenerateStars", (Type[])null, (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(RuntimeCompatibility), "RepairStarNameCall", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null);
Patch(typeof(GS2Generator2), "GeneratePlanetsForStar", "SystemPrefix");
Patch(typeof(GS2Generator2), "NamePlanets", "NamePrefix");
Patch(typeof(VeinAlgorithms), "AddSpecialVeins", "SpecialVeinsPrefix");
Patch(typeof(GS2), "Import", null, "ImportPostfix");
Patch(typeof(VeinAlgorithms), "GenerateVeinsGS2", null, "VeinGenPostfix");
Patch(typeof(VeinAlgorithms), "AddVeinToPlanet", "VeinAmountPrefix");
SurfaceGeneration.Apply(harmony);
RuntimeBalance.Configure(((BaseUnityPlugin)this).Config);
try
{
travelHarmony = new Harmony("cmx.BetterSolarSystem.Balance.Travel");
RuntimeBalance.Apply(travelHarmony);
}
catch (Exception ex)
{
Harmony obj = travelHarmony;
if (obj != null)
{
obj.UnpatchSelf();
}
travelHarmony = null;
Log.LogError((object)("Travel balance failed; galaxy generation remains active. " + ex));
}
try
{
defenseHarmony = new Harmony("cmx.BetterSolarSystem.Balance.Defense");
DefenseBalance.Initialize(((BaseUnityPlugin)this).Config, defenseHarmony);
}
catch (Exception ex2)
{
Harmony obj2 = defenseHarmony;
if (obj2 != null)
{
obj2.UnpatchSelf();
}
defenseHarmony = null;
DefenseBalance.Shutdown();
Log.LogError((object)("Defense balance failed; galaxy generation remains active. " + ex2));
}
Log.LogInfo((object)"BetterSolarSystem 3.2.0 enabled: galaxy generation, defense balance and travel balance.");
}
private void Patch(Type type, string name, string prefix = null, string postfix = null)
{
//IL_0036: Unknown result type (might be due to invalid IL or missing references)
//IL_004f: Unknown result type (might be due to invalid IL or missing references)
MethodInfo methodInfo = AccessTools.Method(type, name, (Type[])null, (Type[])null);
if (methodInfo == null)
{
throw new MissingMethodException(type.FullName, name);
}
harmony.Patch((MethodBase)methodInfo, (prefix == null) ? ((HarmonyMethod)null) : new HarmonyMethod(typeof(Patches), prefix, (Type[])null), (postfix == null) ? ((HarmonyMethod)null) : new HarmonyMethod(typeof(Patches), postfix, (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
}
private void Update()
{
DefenseBalance.Tick();
}
private void OnDestroy()
{
Harmony obj = harmony;
if (obj != null)
{
obj.UnpatchSelf();
}
Harmony obj2 = travelHarmony;
if (obj2 != null)
{
obj2.UnpatchSelf();
}
Harmony obj3 = defenseHarmony;
if (obj3 != null)
{
obj3.UnpatchSelf();
}
DefenseBalance.Shutdown();
}
}
internal static class Patches
{
internal static void GeneratePrefix(GS2Generator2 __instance, int starCount, Dictionary<GSStar, List<Orbit>> ___starOrbits)
{
___starOrbits.Clear();
BalancedGeneration.Configure(__instance, starCount);
}
internal static void StarsPostfix(GSStar ___birthStar)
{
BalancedGeneration.PrepareStars(___birthStar);
}
internal static bool SystemPrefix(GSStar star, GSStar ___birthStar, ref GSPlanet ___birthPlanet, Dictionary<GSStar, List<Orbit>> ___starOrbits)
{
return !BalancedGeneration.BuildSystem(star, star == ___birthStar, ref ___birthPlanet, ___starOrbits);
}
internal static bool NamePrefix(GSStar star)
{
return !star.genData.Get("balancedBuilt", (Val)null).Bool(false);
}
internal static bool SpecialVeinsPrefix()
{
return !BalancedGeneration.IsManagedGalaxy;
}
internal static void GeneratePostfix()
{
BalancedGeneration.Finish();
Plugin.Log.LogInfo((object)("[BALANCED] Validated seed=" + GSSettings.Seed + " stars=" + GSSettings.StarCount + " bodies=" + GSSettings.PlanetCount + " birth=" + GSSettings.BirthPlanetName));
}
internal static void VeinGenPostfix(GSPlanet gsPlanet)
{
//IL_0056: 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_005d: 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_0065: Invalid comparison between Unknown and I4
//IL_0067: 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_0080: 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_00d7: Invalid comparison between Unknown and I4
PlanetRawData val = gsPlanet?.planetData?.data;
int num = int.MaxValue;
int num2 = 0;
double val2 = 0.0;
VeinGroup[] array = gsPlanet?.planetData?.veinGroups;
if (array != null)
{
VeinGroup[] array2 = array;
foreach (VeinGroup val3 in array2)
{
if ((int)val3.type != 7 && val3.count > 0)
{
num = Math.Min(num, val3.count);
num2 = Math.Max(num2, val3.count);
}
}
}
if (val?.veinPool != null)
{
for (int j = 1; j < Math.Min(val.veinCursor, val.veinPool.Length); j++)
{
if (val.veinPool[j].id == j && (int)val.veinPool[j].type == 7)
{
val2 = Math.Max(val2, (double)val.veinPool[j].amount * (double)VeinData.oilSpeedMultiplier);
}
}
}
Plugin.Log.LogInfo((object)("[VEIN] DONE '" + ((gsPlanet != null) ? gsPlanet.Name : null) + "' veinCursor=" + (val?.veinCursor ?? (-1)) + " poolLen=" + (val?.veinPool?.Length ?? (-1)) + " solidGroupNodes=" + ((num2 != 0) ? num : 0) + "-" + num2 + " maxOilPerSec=" + val2.ToString("F3", CultureInfo.InvariantCulture)));
}
internal static void ImportPostfix(bool __result)
{
if (!__result || GS2.SaveOrLoadWindowOpen || !GSSettings.Instance.imported || GS2.Vanilla)
{
return;
}
if (BalancedGeneration.UpgradeSun())
{
Plugin.Log.LogInfo((object)"[UPGRADE] Sun radius=6, physicsRadius=7200; planetary orbits preserved.");
}
if (Plugin.SanitizeLegacySaves.Value)
{
int num = LegacyVeins.Repair(Plugin.VeinBaseRadius.Value, Plugin.VeinExponent.Value, Plugin.ScaleRareVeins.Value);
if (num > 0)
{
Plugin.Log.LogInfo((object)("[LEGACY] One-time repair: " + num + " tables; saved geometry preserved."));
}
}
}
internal static void VeinAmountPrefix(ref int amount, EVeinType veinType, short groupIndex, PlanetData planet)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0002: Invalid comparison between Unknown and I4
if ((int)veinType == 7 && BalancedGeneration.IsManagedGalaxy)
{
amount = BalancedGeneration.OilAmount(planet.seed, groupIndex, VeinData.oilSpeedMultiplier);
}
}
internal static void GameImportPostfix(GameData __instance)
{
if (!BalancedGeneration.IsManagedGalaxy)
{
return;
}
if (__instance.galaxy?.stars != null)
{
StarData[] stars = __instance.galaxy.stars;
foreach (StarData val in stars)
{
if (val?.planets == null)
{
continue;
}
PlanetData[] planets = val.planets;
foreach (PlanetData val2 in planets)
{
if (val2 != null)
{
GSPlanet gSPlanet = GS2.GetGSPlanet(val2);
RuntimeNames.Restore(val2, (gSPlanet != null) ? gSPlanet.Name : null);
}
}
}
}
if (Plugin.SanitizeLegacySaves.Value)
{
int num = RuntimeVeins.RepairLoadedOil(__instance);
if (num > 0)
{
Plugin.Log.LogInfo((object)("[OIL] Repaired " + num + " excessive saved springs; deposits, buildings and miners preserved."));
}
}
}
internal static bool PlanetNamePrefix(PlanetData __instance, bool notifychange)
{
if (BalancedGeneration.IsManagedGalaxy)
{
GSPlanet gSPlanet = GS2.GetGSPlanet(__instance);
if (RuntimeNames.Restore(__instance, (gSPlanet != null) ? gSPlanet.Name : null))
{
if (notifychange && string.IsNullOrEmpty(__instance.overrideName))
{
GalaxyData galaxy = __instance.galaxy;
if (galaxy != null)
{
galaxy.NotifyAstroNameChange(__instance.astroId);
}
}
return false;
}
}
return true;
}
}
public static class RuntimeBalance
{
private static ConfigEntry<bool> fogEnabled;
private static ConfigEntry<bool> sailsEnabled;
private static ConfigEntry<float> fleetMultiplier;
private static ConfigEntry<float> carrierMultiplier;
private static ConfigEntry<float> sailMultiplier;
private static ConfigEntry<int> cargoMultiplier;
public static void Configure(ConfigFile config)
{
//IL_005f: Unknown result type (might be due to invalid IL or missing references)
//IL_0069: Expected O, but got Unknown
//IL_0097: Unknown result type (might be due to invalid IL or missing references)
//IL_00a1: Expected O, but got Unknown
//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
//IL_00ce: Expected O, but got Unknown
//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
//IL_0106: Expected O, but got Unknown
fogEnabled = config.Bind<bool>("Balance - Modules / 平衡模块", "Dark Fog / 黑雾航行", true, "Restart required. / 修改后重启。");
sailsEnabled = config.Bind<bool>("Balance - Modules / 平衡模块", "Solar sails / 太阳帆寿命", true, "Restart required. / 修改后重启。");
fleetMultiplier = config.Bind<float>("Balance - Travel / 航行", "Fleet speed multiplier / 舰队速度倍率", 2f, new ConfigDescription("Stacks with the current modded speed. / 在现有模组速度上叠加。", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.25f, 10f), Array.Empty<object>()));
carrierMultiplier = config.Bind<float>("Balance - Travel / 航行", "Carrier speed multiplier / 补给速度倍率", 2f, new ConfigDescription("", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.25f, 10f), Array.Empty<object>()));
cargoMultiplier = config.Bind<int>("Balance - Travel / 航行", "Carrier cargo multiplier / 补给容量倍率", 2, new ConfigDescription("Load, source debit and dispatch threshold use the same multiplier. / 装载、扣款与门槛同步。", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 10), Array.Empty<object>()));
sailMultiplier = config.Bind<float>("Balance - Travel / 航行", "Sail lifetime multiplier / 帆寿命倍率", 4f, new ConfigDescription("Newly emitted sails; existing expiry timestamps are preserved. / 新发射生效。", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 10f), Array.Empty<object>()));
}
public static float FleetMultiplier()
{
return fleetMultiplier?.Value ?? 2f;
}
public static float CarrierLimit()
{
return 1800f * (carrierMultiplier?.Value ?? 2f);
}
public static int MatterCapacity()
{
return 6000 * (cargoMultiplier?.Value ?? 2);
}
public static int EnergyCapacity()
{
return 5000000 * (cargoMultiplier?.Value ?? 2);
}
public static float SailMultiplier()
{
return sailMultiplier?.Value ?? 4f;
}
public static void Apply(Harmony harmony)
{
//IL_0124: Unknown result type (might be due to invalid IL or missing references)
//IL_0130: Expected O, but got Unknown
//IL_0165: Unknown result type (might be due to invalid IL or missing references)
//IL_0171: Expected O, but got Unknown
//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
//IL_00c6: Expected O, but got Unknown
//IL_023b: Unknown result type (might be due to invalid IL or missing references)
//IL_0247: Expected O, but got Unknown
BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
if (fogEnabled == null || fogEnabled.Value)
{
MethodInfo[] methods = typeof(EnemyUnitComponent).GetMethods(bindingFlags);
foreach (MethodInfo methodInfo in methods)
{
if ((methodInfo.Name.Contains("_Space") || methodInfo.Name.Contains("_SLancer") || methodInfo.Name.Contains("_SHumpback") || methodInfo.Name.Contains("_SFortress")) && PatchProcessor.GetOriginalInstructions((MethodBase)methodInfo, (ILGenerator)null).Any(IsMovementField))
{
harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(RuntimeBalance), "FleetSpeed", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null);
}
}
string[] array = new string[3] { "CarrierSailLogic", "CarrierSailLogicVirtual", "SetCarrierRealized" };
foreach (string text in array)
{
harmony.Patch((MethodBase)AccessTools.Method(typeof(DFRelayComponent), text, (Type[])null, (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(RuntimeBalance), "CarrierSpeed", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null);
}
harmony.Patch((MethodBase)AccessTools.Method(typeof(DFRelayComponent), "LogicTickLogisticsOrders", (Type[])null, (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(RuntimeBalance), "CarrierCargo", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null);
}
if (sailsEnabled != null && !sailsEnabled.Value)
{
return;
}
Type[] array2 = new Type[8]
{
typeof(DysonSwarm),
typeof(DysonSphereLayer),
typeof(PlayerMove_Sail),
typeof(ItemProto),
typeof(UIDESphereInfo),
typeof(UIDESwarmOrbitInfo),
typeof(UITechTree),
typeof(UIStatisticDysonSphereGraph)
};
for (int i = 0; i < array2.Length; i++)
{
MethodInfo[] methods = array2[i].GetMethods(bindingFlags | BindingFlags.DeclaredOnly);
foreach (MethodInfo methodInfo2 in methods)
{
if (methodInfo2.GetMethodBody() != null && ReadsSailLife(methodInfo2))
{
harmony.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(RuntimeBalance), "SailLife", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null);
}
}
}
}
private static bool ReadsSailLife(MethodInfo method)
{
FieldInfo field = AccessTools.Field(typeof(GameHistoryData), "solarSailLife");
return PatchProcessor.GetOriginalInstructions((MethodBase)method, (ILGenerator)null).Any((CodeInstruction c) => CodeInstructionExtensions.LoadsField(c, field, false));
}
public static IEnumerable<CodeInstruction> FleetSpeed(IEnumerable<CodeInstruction> source)
{
foreach (CodeInstruction code in source)
{
yield return code;
if (IsMovementField(code))
{
yield return new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(RuntimeBalance), "FleetMultiplier", (Type[])null, (Type[])null));
yield return new CodeInstruction(OpCodes.Mul, (object)null);
}
}
}
public static bool IsMovementField(CodeInstruction code)
{
if (code.opcode == OpCodes.Ldfld && code.operand is FieldInfo fieldInfo && fieldInfo.DeclaringType == typeof(PrefabDesc))
{
if (!(fieldInfo.Name == "unitMarchMovementSpeed") && !(fieldInfo.Name == "unitMaxMovementSpeed"))
{
return fieldInfo.Name == "unitMaxMovementAcceleration";
}
return true;
}
return false;
}
public static IEnumerable<CodeInstruction> CarrierSpeed(IEnumerable<CodeInstruction> source)
{
int hits = 0;
foreach (CodeInstruction item in source)
{
if (item.opcode == OpCodes.Ldc_R4 && (float)item.operand == 1800f)
{
item.opcode = OpCodes.Call;
item.operand = AccessTools.Method(typeof(RuntimeBalance), "CarrierLimit", (Type[])null, (Type[])null);
hits++;
}
yield return item;
}
if (hits == 0)
{
throw new InvalidOperationException("Carrier cruise-speed constant changed.");
}
}
public static IEnumerable<CodeInstruction> CarrierCargo(IEnumerable<CodeInstruction> source)
{
int matter = 0;
int energy = 0;
foreach (CodeInstruction item in source)
{
if (CodeInstructionExtensions.LoadsConstant(item, 6000L))
{
item.opcode = OpCodes.Call;
item.operand = AccessTools.Method(typeof(RuntimeBalance), "MatterCapacity", (Type[])null, (Type[])null);
matter++;
}
else if (CodeInstructionExtensions.LoadsConstant(item, 5000000L))
{
item.opcode = OpCodes.Call;
item.operand = AccessTools.Method(typeof(RuntimeBalance), "EnergyCapacity", (Type[])null, (Type[])null);
energy++;
}
yield return item;
}
if (matter != 6 || energy != 4)
{
throw new InvalidOperationException("Carrier cargo/debit contract changed: " + matter + "/" + energy);
}
}
public static IEnumerable<CodeInstruction> SailLife(IEnumerable<CodeInstruction> source)
{
FieldInfo field = AccessTools.Field(typeof(GameHistoryData), "solarSailLife");
foreach (CodeInstruction code in source)
{
yield return code;
if (CodeInstructionExtensions.LoadsField(code, field, false))
{
yield return new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(RuntimeBalance), "SailMultiplier", (Type[])null, (Type[])null));
yield return new CodeInstruction(OpCodes.Mul, (object)null);
}
}
}
}
public static class RuntimeCompatibility
{
private static readonly MethodInfo StarName = AccessTools.Method(typeof(NameGen), "_RandomStarName", new Type[3]
{
typeof(int),
typeof(int),
typeof(StarData)
}, (Type[])null);
public static string RandomStarName(int seed, StarData star)
{
if (StarName == null)
{
throw new MissingMethodException("NameGen._RandomStarName(int,int,StarData)");
}
return (string)StarName.Invoke(null, new object[3] { seed, 1033, star });
}
public static IEnumerable<CodeInstruction> RepairStarNameCall(IEnumerable<CodeInstruction> source)
{
List<CodeInstruction> list = source.ToList();
int num = 0;
foreach (CodeInstruction item in list)
{
if (item.opcode == OpCodes.Call && (item.operand == null || (item.operand is MethodInfo methodInfo && methodInfo.DeclaringType == typeof(NameGen) && methodInfo.Name == "_RandomStarName" && methodInfo.GetParameters().Length == 2)))
{
item.operand = AccessTools.Method(typeof(RuntimeCompatibility), "RandomStarName", (Type[])null, (Type[])null);
num++;
}
}
if (num > 1)
{
throw new InvalidOperationException("Ambiguous GS2 obsolete naming call; refusing patch.");
}
return list;
}
}
public static class RuntimeNames
{
public static bool Restore(PlanetData planet, string authoredName)
{
if (planet == null || string.IsNullOrEmpty(authoredName))
{
return false;
}
planet.name = StandardName(authoredName);
return true;
}
public static string StandardName(string authoredName)
{
return authoredName switch
{
"木星 · 星海之冠" => "木星",
"木卫一 · 烬火之诗" => "木卫一",
"木卫二 · 青穹之约" => "木卫二",
"木卫三 · 霜海之镜" => "木卫三",
"木卫四 · 暮雪之庭" => "木卫四",
"木卫五 · 遗落星砂" => "木卫五",
"土卫二 · 冰湖" => "土卫二",
"土卫六 · 荒原" => "土卫六",
"土卫八 · 冻土" => "土卫八",
"谷神星 · 小行星带" => "谷神星",
"冥王星 · 柯伊伯带" => "冥王星",
"卡戎 · 冥河摆渡" => "卡戎",
_ => authoredName,
};
}
}
public static class RuntimeVeins
{
public static int RepairPool(VeinData[] pool, int cursor, VeinGroup[] groups, int seed)
{
//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_0019: 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_0026: Unknown result type (might be due to invalid IL or missing references)
//IL_002c: Invalid comparison between Unknown and I4
//IL_0031: 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_004e: 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_0065: Unknown result type (might be due to invalid IL or missing references)
//IL_006b: Invalid comparison between Unknown and I4
//IL_006e: Unknown result type (might be due to invalid IL or missing references)
//IL_0082: Unknown result type (might be due to invalid IL or missing references)
//IL_0096: Unknown result type (might be due to invalid IL or missing references)
if (pool == null || groups == null)
{
return 0;
}
int num = 0;
for (int i = 1; i < Math.Min(cursor, pool.Length); i++)
{
VeinData val = pool[i];
if (val.id == i && (int)val.type == 7 && !((float)val.amount * VeinData.oilSpeedMultiplier < 10f) && val.groupIndex > 0 && val.groupIndex < groups.Length && (int)groups[val.groupIndex].type == 7)
{
int num2 = BalancedGeneration.OilAmount(seed, val.groupIndex - 1, VeinData.oilSpeedMultiplier);
groups[val.groupIndex].amount += (long)num2 - (long)val.amount;
pool[i].amount = num2;
num++;
}
}
return num;
}
public static int RepairLoadedOil(GameData game)
{
int num = 0;
if (game?.factories == null)
{
return num;
}
for (int i = 0; i < Math.Min(game.factoryCount, game.factories.Length); i++)
{
PlanetFactory val = game.factories[i];
if (((val != null) ? val.planet : null) != null)
{
num += RepairPool(val.veinPool, val.veinCursor, val.veinGroups, val.planet.seed);
}
}
return num;
}
}
public static class SurfaceGeneration
{
public const string Marker = "BetterSolarSystem.Surface.v3.1";
public const float BirthOreBias = 0.18f;
public static Vector3 WeakenBias(Vector3 original)
{
//IL_0002: 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 ((Vector3)(ref original)).normalized * 0.18f;
}
public static void Apply(Harmony harmony)
{
//IL_0055: Unknown result type (might be due to invalid IL or missing references)
//IL_0062: Expected O, but got Unknown
MethodInfo methodInfo = AccessTools.Method(typeof(VeinAlgorithms), "InitVeinGroupVector", (Type[])null, (Type[])null);
if (methodInfo == null || methodInfo.ReturnType != typeof(Vector3))
{
throw new MissingMethodException("GS2 birth vein bias method changed.");
}
harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(SurfaceGeneration), "AdjustBirthBias", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
}
public static void AdjustBirthBias(bool birth, ref Vector3 __result)
{
//IL_001d: Unknown result type (might be due to invalid IL or missing references)
//IL_0022: Unknown result type (might be due to invalid IL or missing references)
//IL_0027: Unknown result type (might be due to invalid IL or missing references)
if (birth && BalancedGeneration.IsManagedGalaxy && ((Dictionary<string, GSTheme>)(object)GSSettings.ThemeLibrary).ContainsKey("BetterSolarSystem.Surface.v3.1"))
{
__result = WeakenBias(__result);
}
}
}
}
namespace BetterSolarSystem.Balance
{
public static class DefenseBalance
{
private sealed class PlanetState
{
internal readonly PlanetFactory Factory;
internal readonly object Gate = new object();
internal readonly Dictionary<int, int> SignalSlots = new Dictionary<int, int>();
internal long SignalTick = -1L;
internal PlanetState(PlanetFactory factory)
{
Factory = factory;
}
}
private sealed class StarState
{
internal readonly object Gate = new object();
internal long Tick = -1L;
internal SpaceSector Sector;
internal EnemyCandidateIndex Index;
}
private sealed class Baseline
{
internal PrefabDesc Descriptor;
internal float Ground;
internal float Space;
internal float Signal;
internal float Pick;
internal float Build;
}
[HarmonyPatch(typeof(VFPreload), "InvokeOnLoadWorkEnded")]
private static class LoadRanges
{
private static void Postfix()
{
ApplyRanges();
}
}
[HarmonyPatch(typeof(GameMain), "Begin")]
private static class ResetSession
{
private static void Postfix()
{
planets.Clear();
stars.Clear();
incarnations.Clear();
ApplyRanges();
}
}
[HarmonyPatch(typeof(SpaceSector), "RemoveEnemyWithComponents")]
private static class RetiredEnemy
{
private static void Prefix([HarmonyArgument(0)] int id)
{
if (Enabled)
{
Retire(id);
}
}
}
[HarmonyPatch(typeof(CombatGroundSystem), "GameTick")]
private static class RefreshGroundSignals
{
private static void Postfix(CombatGroundSystem __instance, [HarmonyArgument(0)] long tick)
{
GroundSignals(__instance.factory, tick);
}
}
[HarmonyPatch]
private static class SupplementSearch
{
private static IEnumerable<MethodBase> TargetMethods()
{
yield return AccessTools.Method(typeof(TurretComponent), "Search_Missile", (Type[])null, (Type[])null);
yield return AccessTools.Method(typeof(TurretComponent), "Search_Plasma", (Type[])null, (Type[])null);
}
private static void Postfix(ref TurretComponent __instance, PlanetFactory factory, PrefabDesc pdesc, [HarmonyArgument(2)] long tick)
{
Search(ref __instance, factory, pdesc, tick);
}
}
[HarmonyPatch(typeof(TurretComponent), "CheckEnemyIsInAttackRange")]
private static class ScaledPlanetRadius
{
private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> input)
{
//IL_0084: Unknown result type (might be due to invalid IL or missing references)
//IL_008e: Expected O, but got Unknown
List<CodeInstruction> list = new List<CodeInstruction>(input);
int num = 0;
for (int i = 0; i < list.Count; i++)
{
if (list[i].opcode == OpCodes.Ldc_R4 && object.Equals(list[i].operand, 200f))
{
list[i].opcode = OpCodes.Ldarg_1;
list[i].operand = null;
list.Insert(++i, new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(DefenseBalance), "ActualRadius", (Type[])null, (Type[])null)));
num++;
}
}
if (num != 1)
{
throw new InvalidOperationException("Unsupported native turret radius API: " + num);
}
return list;
}
}
[HarmonyPatch(typeof(TurretComponent), "Shoot_Plasma")]
private static class PlasmaFlight
{
private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> input)
{
List<CodeInstruction> list = new List<CodeInstruction>(input);
int num = 0;
int num2 = 0;
for (int i = 0; i < list.Count; i++)
{
if (list[i].opcode == OpCodes.Ldc_R8 && object.Equals(list[i].operand, 20000.0))
{
list[i].opcode = OpCodes.Call;
list[i].operand = AccessTools.Method(typeof(DefenseBalance), "PlasmaSpeed", (Type[])null, (Type[])null);
num++;
}
if (i > 0 && list[i].opcode == OpCodes.Stfld && list[i].operand is FieldInfo fieldInfo && fieldInfo.DeclaringType == typeof(GeneralProjectile) && (fieldInfo.Name == "life" || fieldInfo.Name == "lifemax"))
{
if (!CodeInstructionExtensions.LoadsConstant(list[i - 1], 120L))
{
throw new InvalidOperationException("Unsupported plasma lifetime API.");
}
list[i - 1].opcode = OpCodes.Call;
list[i - 1].operand = AccessTools.Method(typeof(DefenseBalance), "PlasmaLife", (Type[])null, (Type[])null);
num2++;
}
}
if (num != 2 || num2 != 2)
{
throw new InvalidOperationException("Unsupported native plasma API: " + num + "/" + num2);
}
return list;
}
}
private static ConfigEntry<float> range;
private static ConfigEntry<float> plasmaRange;
private static ConfigEntry<float> missileRange;
private static ConfigEntry<float> pickRange;
private static ConfigEntry<float> buildRange;
private static ConfigEntry<bool> signals;
private static ConfigEntry<bool> plasma;
private static volatile float effectivePlasmaReach = 26000f;
private static readonly ConcurrentDictionary<int, PlanetState> planets = new ConcurrentDictionary<int, PlanetState>();
private static readonly ConcurrentDictionary<int, StarState> stars = new ConcurrentDictionary<int, StarState>();
private static readonly ConcurrentDictionary<int, int> incarnations = new ConcurrentDictionary<int, int>();
private static readonly Dictionary<int, Baseline> baselines = new Dictionary<int, Baseline>();
public static bool Enabled { get; private set; }
public static void Initialize(ConfigFile config, Harmony harmony)
{
//IL_0086: Unknown result type (might be due to invalid IL or missing references)
//IL_0090: Expected O, but got Unknown
//IL_00be: Unknown result type (might be due to invalid IL or missing references)
//IL_00c8: Expected O, but got Unknown
range = ConfigMigration.BindDefense(config, "1. 范围增强", "全局范围倍率(其他炮塔/信号塔)", 4f, RangeDescription());
plasmaRange = ConfigMigration.BindDefense(config, "1. 范围增强", "电浆炮对天射程倍率", 4f, RangeDescription());
missileRange = ConfigMigration.BindDefense(config, "1. 范围增强", "导弹塔额外对天倍率", 1f, RangeDescription());
pickRange = ConfigMigration.BindDefense(config, "2. 战场基站", "拾取范围", 600f, new ConfigDescription("", (AcceptableValueBase)(object)new AcceptableValueRange<float>(100f, 700f), Array.Empty<object>()));
buildRange = ConfigMigration.BindDefense(config, "2. 战场基站", "建造范围", 600f, new ConfigDescription("", (AcceptableValueBase)(object)new AcceptableValueRange<float>(50f, 700f), Array.Empty<object>()));
signals = ConfigMigration.BindDefense(config, "3. 开关", "启用全局标记", fallback: true, "Registers ground targets only on planets with a signal tower.");
plasma = ConfigMigration.BindDefense(config, "3. 开关", "启用电浆炮增强", fallback: true, "Enables extended plasma targeting.");
ConfigMigration.BindDefense(config, "4. 性能优化", "标记逻辑使用内层锁", fallback: false, "Legacy key retained; each planet cache now owns its synchronization.");
Enabled = config.Bind<bool>("Balance - Modules / 平衡模块", "Defense / 防御增强", true, "Restart required. / 修改后重启。").Value;
ConfigEntry<float>[] array = new ConfigEntry<float>[5] { range, plasmaRange, missileRange, pickRange, buildRange };
for (int i = 0; i < array.Length; i++)
{
array[i].SettingChanged += delegate
{
ApplyRanges();
};
}
if (Enabled)
{
Type[] array2 = new Type[7]
{
typeof(LoadRanges),
typeof(ResetSession),
typeof(RefreshGroundSignals),
typeof(SupplementSearch),
typeof(ScaledPlanetRadius),
typeof(PlasmaFlight),
typeof(RetiredEnemy)
};
foreach (Type type in array2)
{
harmony.CreateClassProcessor(type).Patch();
}
}
}
private static ConfigDescription RangeDescription()
{
//IL_0019: Unknown result type (might be due to invalid IL or missing references)
//IL_001f: Expected O, but got Unknown
return new ConfigDescription("Applied from the original prototype value.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 10f), Array.Empty<object>());
}
public static void Shutdown()
{
Enabled = false;
planets.Clear();
stars.Clear();
incarnations.Clear();
baselines.Clear();
}
public static void Tick()
{
}
private static PlanetState State(PlanetFactory factory)
{
PlanetState planetState = planets.GetOrAdd(factory.planetId, (int id) => new PlanetState(factory));
if (planetState.Factory != factory)
{
planetState = new PlanetState(factory);
planets[factory.planetId] = planetState;
}
return planetState;
}
private static void ApplyRanges()
{
//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
//IL_0104: Invalid comparison between Unknown and I4
//IL_0152: Unknown result type (might be due to invalid IL or missing references)
//IL_0158: Invalid comparison between Unknown and I4
if (!Enabled || ((ProtoSet<ItemProto>)(object)LDB.items)?.dataArray == null)
{
return;
}
float num = 0f;
ItemProto[] dataArray = ((ProtoSet<ItemProto>)(object)LDB.items).dataArray;
foreach (ItemProto val in dataArray)
{
PrefabDesc val2 = val?.prefabDesc;
if (val2 == null || (!val2.isTurret && !val2.isBeacon && !val2.isBattleBase))
{
continue;
}
if (!baselines.TryGetValue(((Proto)val).ID, out var value) || value.Descriptor != val2)
{
value = new Baseline
{
Descriptor = val2,
Ground = val2.turretMaxAttackRange,
Space = val2.turretSpaceAttackRange,
Signal = val2.beaconSignalRadius,
Pick = val2.battleBasePickRange,
Build = val2.constructionRange
};
baselines[((Proto)val).ID] = value;
}
if (val2.isTurret)
{
bool flag = (int)val2.turretType == 4;
val2.turretMaxAttackRange = (flag ? (value.Space * plasmaRange.Value) : (value.Ground * range.Value));
val2.turretSpaceAttackRange = value.Space * (flag ? plasmaRange.Value : (range.Value * (((int)val2.turretType == 5) ? missileRange.Value : 1f)));
if (flag)
{
val2.turretPitchUpMax = 89f;
val2.turretPitchDownMax = 0f;
num = Math.Max(num, val2.turretSpaceAttackRange);
}
}
if (val2.isBeacon)
{
val2.beaconSignalRadius = value.Signal * range.Value;
}
if (val2.isBattleBase)
{
val2.battleBasePickRange = pickRange.Value;
val2.constructionRange = buildRange.Value;
}
}
effectivePlasmaReach = ((num > 0f) ? num : (6500f * plasmaRange.Value));
PlanetFactory[] array = GameMain.data?.factories;
if (array == null)
{
return;
}
PlanetFactory[] array2 = array;
foreach (PlanetFactory val3 in array2)
{
if (val3?.defenseSystem == null)
{
continue;
}
val3.defenseSystem.RefreshTurretSearchPair();
ObjectPool<BattleBaseComponent> battleBases = val3.defenseSystem.battleBases;
if (battleBases?.buffer == null)
{
continue;
}
for (int j = 1; j < Math.Min(battleBases.cursor, battleBases.buffer.Length); j++)
{
BattleBaseComponent val4 = battleBases.buffer[j];
if (val4 != null && val4.id == j)
{
val4.pickRange = pickRange.Value;
val4.constructRange = buildRange.Value;
}
}
}
}
private static EnemyCandidateIndex Snapshot(PlanetFactory factory, long tick)
{
//IL_013c: Unknown result type (might be due to invalid IL or missing references)
//IL_014d: Unknown result type (might be due to invalid IL or missing references)
//IL_015e: 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_01f3: Unknown result type (might be due to invalid IL or missing references)
//IL_020d: Unknown result type (might be due to invalid IL or missing references)
//IL_017a: Unknown result type (might be due to invalid IL or missing references)
StarData star = factory.planet.star;
StarState orAdd = stars.GetOrAdd(star.id, (int id) => new StarState());
lock (orAdd.Gate)
{
if (orAdd.Index != null && orAdd.Sector == factory.sector && tick >= orAdd.Tick && tick - orAdd.Tick < 6)
{
return orAdd.Index;
}
List<EnemyCandidateIndex.Candidate> list = new List<EnemyCandidateIndex.Candidate>();
SpaceSector sector = factory.sector;
if (sector?.enemyPool != null)
{
VectorLF3 val2 = default(VectorLF3);
for (int num = 1; num < Math.Min(sector.enemyCursor, sector.enemyPool.Length); num++)
{
ref EnemyData reference = ref sector.enemyPool[num];
if (reference.id != num || !reference.isSpace || ((EnemyData)(ref reference)).isInvincible || !((EnemyData)(ref reference)).positionIsValid)
{
continue;
}
EnemyDFHiveSystem val = (sector.IsHiveAstro(reference.originAstroId) ? sector.GetHiveByAstroId(reference.originAstroId) : null);
if (val == null || val.starData == star)
{
sector.TransformFromAstro_ref(reference.astroId, ref val2, ref reference.pos);
if (Finite(val2.x) && Finite(val2.y) && Finite(val2.z) && (val != null || NearestStar(sector.galaxy, val2) == star.id))
{
list.Add(new EnemyCandidateIndex.Candidate
{
Id = num,
Origin = reference.originAstroId,
Model = reference.modelId,
Prototype = reference.protoId,
Revision = Incarnation(num),
X = val2.x - star.uPosition.x,
Y = val2.y - star.uPosition.y,
Z = val2.z - star.uPosition.z
});
}
}
}
}
orAdd.Index = new EnemyCandidateIndex(list);
orAdd.Tick = tick;
orAdd.Sector = sector;
return orAdd.Index;
}
}
private static int NearestStar(GalaxyData galaxy, VectorLF3 point)
{
//IL_001c: Unknown result type (might be due to invalid IL or missing references)
//IL_002f: Unknown result type (might be due to invalid IL or missing references)
//IL_0044: Unknown result type (might be due to invalid IL or missing references)
double num = double.MaxValue;
int result = 0;
StarData[] array = galaxy.stars;
foreach (StarData val in array)
{
double num2 = point.x - val.uPosition.x;
double num3 = point.y - val.uPosition.y;
double num4 = point.z - val.uPosition.z;
double num5 = num2 * num2 + num3 * num3 + num4 * num4;
if (num5 < num)
{
num = num5;
result = val.id;
}
}
return result;
}
private static void Search(ref TurretComponent turret, PlanetFactory factory, PrefabDesc descriptor, long tick)
{
//IL_005a: Unknown result type (might be due to invalid IL or missing references)
//IL_0060: Invalid comparison between Unknown and I4
//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
//IL_010c: Unknown result type (might be due to invalid IL or missing references)
//IL_0111: Unknown result type (might be due to invalid IL or missing references)
//IL_0118: Unknown result type (might be due to invalid IL or missing references)
//IL_011d: Unknown result type (might be due to invalid IL or missing references)
//IL_01a4: Unknown result type (might be due to invalid IL or missing references)
//IL_01d3: Unknown result type (might be due to invalid IL or missing references)
//IL_01d8: Unknown result type (might be due to invalid IL or missing references)
//IL_01da: Unknown result type (might be due to invalid IL or missing references)
if (!Enabled)
{
return;
}
PlanetFactory obj = factory;
if (((obj == null) ? null : obj.planet?.star) == null || factory.sector == null || turret.target.id > 0 || ((int)turret.type == 4 && !plasma.Value) || turret.entityId <= 0 || turret.entityId >= factory.entityPool.Length || descriptor.turretSpaceAttackRange <= 0f)
{
return;
}
ref EntityData reference = ref factory.entityPool[turret.entityId];
if (reference.id != turret.entityId)
{
return;
}
VectorLF3 val = VectorLF3.op_Implicit(reference.pos);
VectorLF3 world = default(VectorLF3);
factory.sector.TransformFromAstro_ref(factory.planet.astroId, ref world, ref val);
StarData star = factory.planet.star;
TurretComponent checkTurret = turret;
EntityData checkEntity = reference;
EnemyCandidateIndex.Candidate? candidate = Snapshot(factory, tick).Nearest(world.x - star.uPosition.x, world.y - star.uPosition.y, world.z - star.uPosition.z, descriptor.turretSpaceAttackRange + 2000f, delegate(EnemyCandidateIndex.Candidate candidate2)
{
//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
//IL_00be: 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_011d: Unknown result type (might be due to invalid IL or missing references)
//IL_0140: Unknown result type (might be due to invalid IL or missing references)
//IL_0145: 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)
EnemyData[] enemyPool = factory.sector.enemyPool;
if (candidate2.Id <= 0 || candidate2.Id >= Math.Min(factory.sector.enemyCursor, enemyPool.Length))
{
return false;
}
ref EnemyData reference2 = ref enemyPool[candidate2.Id];
if (!EnemyCandidateIndex.Matches(candidate2, reference2.id, reference2.originAstroId, reference2.modelId, reference2.protoId, Incarnation(candidate2.Id)) || !reference2.isSpace || ((EnemyData)(ref reference2)).isInvincible || !((EnemyData)(ref reference2)).positionIsValid)
{
return false;
}
VectorLF3 val2 = default(VectorLF3);
factory.sector.TransformFromAstro_ref(reference2.astroId, ref val2, ref reference2.pos);
double num = val2.x - world.x;
double num2 = val2.y - world.y;
double num3 = val2.z - world.z;
double num4 = num * num + num2 * num2 + num3 * num3;
if (!Finite(num4) || num4 > (double)descriptor.turretSpaceAttackRange * (double)descriptor.turretSpaceAttackRange)
{
return false;
}
SkillTarget val3 = new SkillTarget
{
id = reference2.id,
astroId = reference2.originAstroId,
type = (ETargetType)4
};
return ((TurretComponent)(ref checkTurret)).CheckEnemyIsInAttackRange(factory, descriptor, ref checkEntity, ref val3);
});
if (candidate.HasValue)
{
turret.target = new SkillTarget
{
id = candidate.Value.Id,
astroId = candidate.Value.Origin,
type = (ETargetType)4
};
}
}
private static void GroundSignals(PlanetFactory factory, long tick)
{
//IL_0051: Unknown result type (might be due to invalid IL or missing references)
//IL_0056: Unknown result type (might be due to invalid IL or missing references)
//IL_0058: 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_006c: 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_0142: Invalid comparison between Unknown and I4
//IL_0083: Unknown result type (might be due to invalid IL or missing references)
//IL_0094: Unknown result type (might be due to invalid IL or missing references)
//IL_0144: Unknown result type (might be due to invalid IL or missing references)
//IL_0158: Unknown result type (might be due to invalid IL or missing references)
//IL_0168: Unknown result type (might be due to invalid IL or missing references)
//IL_0201: 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_0233: Unknown result type (might be due to invalid IL or missing references)
//IL_0235: Unknown result type (might be due to invalid IL or missing references)
if (!Enabled || !signals.Value || factory?.defenseSystem == null || factory.enemyPool == null)
{
return;
}
DataPool<BeaconComponent> beacons = factory.defenseSystem.beacons;
bool flag = false;
if (beacons?.buffer != null)
{
for (int i = 1; i < Math.Min(beacons.cursor, beacons.buffer.Length); i++)
{
BeaconComponent val = beacons.buffer[i];
if (val.id == i && val.entityId > 0 && val.entityId < factory.entityPool.Length && factory.entityPool[val.entityId].id == val.entityId)
{
flag = true;
break;
}
}
}
if (!flag)
{
return;
}
PlanetState planetState = State(factory);
lock (planetState.Gate)
{
if (tick >= planetState.SignalTick && tick - planetState.SignalTick < 6)
{
return;
}
planetState.SignalTick = tick;
DefenseSystem defenseSystem = factory.defenseSystem;
planetState.SignalSlots.Clear();
int num = Math.Min(defenseSystem.localGlobalTargetCursor, defenseSystem.globalTargets.Length);
for (int j = 0; j < num; j++)
{
TimedSkillTarget val2 = defenseSystem.globalTargets[j];
if ((int)val2.type == 4 && val2.astroId == factory.planet.astroId && val2.id > 0)
{
planetState.SignalSlots[val2.id] = j;
}
}
for (int k = 1; k < Math.Min(factory.enemyCursor, factory.enemyPool.Length); k++)
{
ref EnemyData reference = ref factory.enemyPool[k];
if (reference.id == k && !reference.isSpace && !((EnemyData)(ref reference)).isInvincible)
{
if (planetState.SignalSlots.TryGetValue(k, out var value))
{
defenseSystem.globalTargets[value].lifeTick = Math.Max(12, defenseSystem.globalTargets[value].lifeTick);
continue;
}
TimedSkillTarget val3 = new TimedSkillTarget
{
id = k,
astroId = factory.planet.astroId,
type = (ETargetType)4,
lifeTick = 12
};
defenseSystem.AddGlobalTargets(ref val3);
planetState.SignalSlots[k] = defenseSystem.localGlobalTargetCursor - 1;
}
}
}
}
internal static float ActualRadius(PlanetFactory factory)
{
return factory.planet.realRadius;
}
private static bool Finite(double value)
{
if (!double.IsNaN(value))
{
return !double.IsInfinity(value);
}
return false;
}
private static int Incarnation(int id)
{
if (!incarnations.TryGetValue(id, out var value))
{
return 0;
}
return value;
}
private static void Retire(int id)
{
if (id > 0)
{
incarnations.AddOrUpdate(id, 1, (int key, int prior) => prior + 1);
}
}
internal static double PlasmaSpeed()
{
return 20000.0 * (double)(plasmaRange?.Value ?? 4f);
}
internal static int FlightTicks(double reach, double speed)
{
return Math.Max(300, (int)Math.Ceiling(reach / speed * 60.0) + 120);
}
internal static int PlasmaLife()
{
return FlightTicks(effectivePlasmaReach, PlasmaSpeed());
}
}
internal sealed class EnemyCandidateIndex
{
internal struct Candidate
{
internal int Id;
internal int Origin;
internal int Model;
internal int Prototype;
internal int Revision;
internal double X;
internal double Y;
internal double Z;
internal double Axis(int axis)
{
return axis switch
{
1 => Y,
0 => X,
_ => Z,
};
}
}
private readonly Candidate[] points;
internal int Count => points.Length;
internal EnemyCandidateIndex(List<Candidate> source)
{
points = source.ToArray();
Partition(0, points.Length, 0);
}
private void Partition(int start, int end, int depth)
{
if (end - start < 2)
{
return;
}
int num = start + (end - start) / 2;
int axis = depth % 3;
int num2 = start;
int num3 = end - 1;
while (num2 < num3)
{
double num4 = points[num2 + (num3 - num2) / 2].Axis(axis);
int i = num2;
int num5 = num3;
while (i <= num5)
{
for (; points[i].Axis(axis) < num4; i++)
{
}
while (points[num5].Axis(axis) > num4)
{
num5--;
}
if (i <= num5)
{
Candidate candidate = points[i];
points[i++] = points[num5];
points[num5--] = candidate;
}
}
if (num <= num5)
{
num3 = num5;
continue;
}
if (num < i)
{
break;
}
num2 = i;
}
Partition(start, num, depth + 1);
Partition(num + 1, end, depth + 1);
}
internal Candidate? Nearest(double x, double y, double z, double range, Func<Candidate, bool> valid)
{
if (range <= 0.0 || double.IsNaN(range) || double.IsInfinity(range))
{
return null;
}
double bestDistance = range * range;
Candidate? result = null;
Visit(0, points.Length, 0, x, y, z, valid, ref bestDistance, ref result);
return result;
}
private void Visit(int start, int end, int depth, double x, double y, double z, Func<Candidate, bool> valid, ref double bestDistance, ref Candidate? result)
{
if (start >= end)
{
return;
}
int num = start + (end - start) / 2;
Candidate candidate = points[num];
double num2 = candidate.X - x;
double num3 = candidate.Y - y;
double num4 = candidate.Z - z;
double num5 = num2 * num2 + num3 * num3 + num4 * num4;
if (num5 <= bestDistance && valid(candidate))
{
bestDistance = num5;
result = candidate;
}
double num6 = ((depth % 3 == 0) ? num2 : ((depth % 3 == 1) ? num3 : num4));
if (num6 > 0.0)
{
Visit(start, num, depth + 1, x, y, z, valid, ref bestDistance, ref result);
if (num6 * num6 <= bestDistance)
{
Visit(num + 1, end, depth + 1, x, y, z, valid, ref bestDistance, ref result);
}
}
else
{
Visit(num + 1, end, depth + 1, x, y, z, valid, ref bestDistance, ref result);
if (num6 * num6 <= bestDistance)
{
Visit(start, num, depth + 1, x, y, z, valid, ref bestDistance, ref result);
}
}
}
internal static bool Matches(Candidate candidate, int id, int origin, int model, int prototype, int revision = 0)
{
if (id > 0 && candidate.Id == id && candidate.Origin == origin && candidate.Model == model && candidate.Prototype == prototype)
{
return candidate.Revision == revision;
}
return false;
}
}
}