using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using UXAssist.Common; using UXAssist.UI; using UnityEngine; using UnityEngine.Events; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("HardFog")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("HardFog")] [assembly: AssemblyCopyright("Copyright © 2026")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("8cf264f1-e863-4eaf-b956-c8330da40ba6")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyVersion("1.0.0.0")] namespace HardFog; [BepInPlugin("me.liantian.plugin.HardFog", "HardFog", "0.0.24")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class HardFogWindow : BaseUnityPlugin { private const string WindowTitleKey = "hard_fog_control"; private const string ClearCurrentPlanetKey = "clear_current_planet"; private const string ClearCurrentStarKey = "clear_current_star"; private const string FillGalaxyHivesKey = "fill_hive"; private const string SuperThreatReducerHiveKey = "super-threat-reducer-hive-enabled"; private const string SuperThreatReducerGroundKey = "super-threat-reducer-ground-enabled"; private const string SmartRelayDispatchKey = "smart-relay-dispatch-enabled"; private const string FasterRelayLaunchKey = "faster-relay-launch-enabled"; private const string FasterResearchKey = "faster-research-enabled"; private const string BuildAnywhereOnWaterKey = "build-anywhere-on-water-enabled"; private const string VeinPlacementKey = "vein-placement-enabled"; private const string OverpoweredMechaFightersKey = "overpowered-mecha-fighters-enabled"; private const string ConstructLowLatitudeRuinsKey = "surface-ruins-construct-low-latitude"; private const string ConstructMidLatitudeRuinsKey = "surface-ruins-construct-mid-latitude"; private const string ConstructHighLatitudeRuinsKey = "surface-ruins-construct-high-latitude"; private const string BuildGeothermalOnIdleRuinsKey = "surface-ruins-build-geothermal-on-idle-ruins"; private static UIButton clearCurrentPlanetButton; private static UIButton clearCurrentStarButton; private static UIButton fillGalaxyHivesButton; private static UIButton constructLowLatitudeRuinsButton; private static UIButton constructMidLatitudeRuinsButton; private static UIButton constructHighLatitudeRuinsButton; private static UIButton buildGeothermalOnIdleRuinsButton; internal static ManualLogSource Log; public void Awake() { Log = ((BaseUnityPlugin)this).Logger; DarkFogControl.Log = ((BaseUnityPlugin)this).Logger; SurfaceRuinControl.Log = ((BaseUnityPlugin)this).Logger; SuperThreatReducerControl.Init(((BaseUnityPlugin)this).Config.Bind("DarkFog", "SuperThreatReducerHiveEnabled", false, "Enable Space Hive Suppression. Zeros space hive threat and skips assault scans."), ((BaseUnityPlugin)this).Config.Bind("DarkFog", "SuperThreatReducerGroundEnabled", false, "Enable Ground Base Suppression. Skips ground base threat accumulation and assault scans."), ((BaseUnityPlugin)this).Logger); RelayControl.Init(((BaseUnityPlugin)this).Config.Bind("DarkFog", "FasterRelayLaunchEnabled", false, "Enable faster relay station launch. Checks every 120 hive ticks and dispatches one idle relay when none is already outbound."), ((BaseUnityPlugin)this).Config.Bind("DarkFog", "SmartRelayDispatchEnabled", false, "Only applies when faster relay station launch is enabled. Dispatch relay stations only to markers."), ((BaseUnityPlugin)this).Logger); FasterResearchControl.Init(((BaseUnityPlugin)this).Config.Bind("HardFog", "FasterResearchEnabled", false, "Enable research speed multiplier. Reduces tech hash needed to about 1/36."), ((BaseUnityPlugin)this).Logger); BuildAnywhereOnWaterControl.Init(((BaseUnityPlugin)this).Config.Bind("HardFog", "BuildAnywhereOnWaterEnabled", true, "Enable ignoring missing ground support build failures, including water placement."), ((BaseUnityPlugin)this).Logger); VeinPlacementControl.Init(((BaseUnityPlugin)this).Config.Bind("HardFog", "VeinPlacementEnabled", true, "Enable better vein placement for future planet vein generation."), ((BaseUnityPlugin)this).Logger); OverpoweredMechaFightersControl.Init(((BaseUnityPlugin)this).Config.Bind("HardFog", "OverpoweredMechaFightersEnabled", false, "Enable stronger mecha fighters: 10x range, 10x damage, and invincibility."), ((BaseUnityPlugin)this).Logger); I18N.Add("hard_fog_control", "Dark Fog Control", "黑雾操控"); I18N.Add("clear_current_planet", "Clear Dark Fog ground bases on current planet", "清理当前星球的地面黑雾基地"); I18N.Add("clear_current_star", "Clear space Dark Fog hives in current star system", "清理当前恒星的太空黑雾巢穴"); I18N.Add("fill_hive", "Fill the galaxy with Dark Fog hives", "为整个星系填满黑雾巢穴"); I18N.Add("super-threat-reducer-hive-enabled", "Space Hive Suppression", "太空巢穴降压"); I18N.Add("super-threat-reducer-ground-enabled", "Ground Base Suppression", "地面基地降压"); I18N.Add("smart-relay-dispatch-enabled", "Relay stations only dispatch to markers", "中继站只发往信标"); I18N.Add("faster-relay-launch-enabled", "Launch relay stations faster", "更快的发射中继站"); I18N.Add("faster-research-enabled", "Research Speed Multiplier", "研究倍速器"); I18N.Add("vein-placement-enabled", "Better vein placement", "更好的矿物位置"); I18N.Add("overpowered-mecha-fighters-enabled", "Fighters fly farther", "战斗机更远的飞行距离"); I18N.Add("surface-ruins-construct-low-latitude", "Construct low-latitude ruins", "构造低纬度废墟"); I18N.Add("surface-ruins-construct-mid-latitude", "Construct mid-latitude ruins", "构造中纬度废墟"); I18N.Add("surface-ruins-construct-high-latitude", "Construct high-latitude ruins", "构造高纬度废墟"); I18N.Add("surface-ruins-build-geothermal-on-idle-ruins", "Build geothermal power stations on idle ruins", "在空闲废墟上建造地热发电站"); I18N.Add("build-anywhere-on-water-enabled", "Ignore ground support requirement", "无需地基支撑建造"); I18N.Apply(); MyConfigWindow.OnUICreated = (Action)Delegate.Combine(MyConfigWindow.OnUICreated, new Action(CreateUI)); Log.LogInfo((object)"HardFog 初始化"); } public void OnDestroy() { MyConfigWindow.OnUICreated = (Action)Delegate.Remove(MyConfigWindow.OnUICreated, new Action(CreateUI)); SuperThreatReducerControl.Uninit(); RelayControl.Uninit(); FasterResearchControl.Uninit(); BuildAnywhereOnWaterControl.Uninit(); VeinPlacementControl.Uninit(); OverpoweredMechaFightersControl.Uninit(); } private static void CreateUI(MyConfigWindow wnd, RectTransform trans) { //IL_0199: Unknown result type (might be due to invalid IL or missing references) //IL_01a3: Expected O, but got Unknown //IL_01d0: Unknown result type (might be due to invalid IL or missing references) //IL_01da: Expected O, but got Unknown //IL_0207: Unknown result type (might be due to invalid IL or missing references) //IL_0211: Expected O, but got Unknown //IL_023e: Unknown result type (might be due to invalid IL or missing references) //IL_0248: Expected O, but got Unknown //IL_0275: Unknown result type (might be due to invalid IL or missing references) //IL_027f: Expected O, but got Unknown //IL_02ac: Unknown result type (might be due to invalid IL or missing references) //IL_02b6: Expected O, but got Unknown float num = 10f; ((MyWindowWithTabs)wnd).AddSplitter(trans, 10f); ((MyWindowWithTabs)wnd).AddTabGroup(trans, "hard_fog_control", "tab-group-hard-fog"); RectTransform val = ((MyWindowWithTabs)wnd).AddTab(trans, "hard_fog_control"); ((MyWindow)wnd).AddCheckBox(10f, num, val, SuperThreatReducerControl.EnabledConfigHive, "super-threat-reducer-hive-enabled", 16); num += 36f; ((MyWindow)wnd).AddCheckBox(10f, num, val, SuperThreatReducerControl.EnabledConfigGround, "super-threat-reducer-ground-enabled", 16); num += 36f; ((MyWindow)wnd).AddCheckBox(10f, num, val, RelayControl.FasterRelayLaunchEnabledConfig, "faster-relay-launch-enabled", 16); num += 36f; MyCheckBox smartRelayDispatchCheckBox = ((MyWindow)wnd).AddCheckBox(30f, num, val, RelayControl.SmartRelayDispatchEnabledConfig, "smart-relay-dispatch-enabled", 13); RelayControl.FasterRelayLaunchEnabledConfig.SettingChanged += RelayOptionChanged; ((MyWindow)wnd).OnFree += delegate { RelayControl.FasterRelayLaunchEnabledConfig.SettingChanged -= RelayOptionChanged; }; RelayOptionChanged(null, null); num += 36f; ((MyWindow)wnd).AddCheckBox(10f, num, val, FasterResearchControl.EnabledConfig, "faster-research-enabled", 16); num += 36f; ((MyWindow)wnd).AddCheckBox(10f, num, val, BuildAnywhereOnWaterControl.EnabledConfig, "build-anywhere-on-water-enabled", 16); num += 36f; ((MyWindow)wnd).AddCheckBox(10f, num, val, VeinPlacementControl.EnabledConfig, "vein-placement-enabled", 16); num += 36f; ((MyWindow)wnd).AddCheckBox(10f, num, val, OverpoweredMechaFightersControl.EnabledConfig, "overpowered-mecha-fighters-enabled", 16); num = 10f; clearCurrentPlanetButton = ((MyWindow)wnd).AddButton(400f, num, 240f, val, "clear_current_planet", 16, "button-clear-current-planet-dark-fog", new UnityAction(OnClearCurrentPlanetClicked)); num += 36f; clearCurrentStarButton = ((MyWindow)wnd).AddButton(400f, num, 240f, val, "clear_current_star", 16, "button-clear-current-star-dark-fog", new UnityAction(OnClearCurrentStarClicked)); num += 36f; fillGalaxyHivesButton = ((MyWindow)wnd).AddButton(400f, num, 240f, val, "fill_hive", 16, "button-fill-galaxy-dark-fog-hives", new UnityAction(OnFillGalaxyHivesClicked)); num += 36f; constructLowLatitudeRuinsButton = ((MyWindow)wnd).AddButton(400f, num, 260f, val, "surface-ruins-construct-low-latitude", 16, "button-surface-ruins-construct-low-latitude", new UnityAction(OnConstructLowLatitudeRuinsClicked)); num += 36f; constructMidLatitudeRuinsButton = ((MyWindow)wnd).AddButton(400f, num, 260f, val, "surface-ruins-construct-mid-latitude", 16, "button-surface-ruins-construct-mid-latitude", new UnityAction(OnConstructMidLatitudeRuinsClicked)); num += 36f; constructHighLatitudeRuinsButton = ((MyWindow)wnd).AddButton(400f, num, 260f, val, "surface-ruins-construct-high-latitude", 16, "button-surface-ruins-construct-high-latitude", new UnityAction(OnConstructHighLatitudeRuinsClicked)); void RelayOptionChanged(object sender, EventArgs args) { smartRelayDispatchCheckBox.SetEnable(RelayControl.FasterRelayLaunchEnabledConfig.Value); } } private static void OnClearCurrentPlanetClicked() { RunWithButtonDisabled(clearCurrentPlanetButton, DarkFogControl.ClearCurrentPlanetDarkFog); } private static void OnClearCurrentStarClicked() { RunWithButtonDisabled(clearCurrentStarButton, DarkFogControl.ClearCurrentStarSpaceDarkFog); } private static void OnFillGalaxyHivesClicked() { RunWithButtonDisabled(fillGalaxyHivesButton, DarkFogControl.FillGalaxyWithDarkFogHives); } private static void OnConstructLowLatitudeRuinsClicked() { RunWithButtonDisabled(constructLowLatitudeRuinsButton, SurfaceRuinControl.ConstructLowLatitudeRuinsOnCurrentPlanet); } private static void OnConstructMidLatitudeRuinsClicked() { RunWithButtonDisabled(constructMidLatitudeRuinsButton, SurfaceRuinControl.ConstructMidLatitudeRuinsOnCurrentPlanet); } private static void OnConstructHighLatitudeRuinsClicked() { RunWithButtonDisabled(constructHighLatitudeRuinsButton, SurfaceRuinControl.ConstructHighLatitudeRuinsOnCurrentPlanet); } private static void OnBuildGeothermalOnIdleRuinsClicked() { RunWithButtonDisabled(buildGeothermalOnIdleRuinsButton, SurfaceRuinControl.BuildGeothermalOnIdleRuinsCurrentPlanet); } private static void RunWithButtonDisabled(UIButton button, Action action) { if ((Object)(object)button != (Object)null) { ((Behaviour)button).enabled = false; } try { action(); } finally { if ((Object)(object)button != (Object)null) { ((Behaviour)button).enabled = true; } } } } internal static class DarkFogControl { private struct EnemyModelRef { public int ModelIndex; public int ModelId; } internal static ManualLogSource Log; internal static void ClearCurrentPlanetDarkFog() { SaveCurrentGame(); if (GameMain.mainPlayer != null) { PlanetData localPlanet = GameMain.localPlanet; if (localPlanet != null) { ClearPlanetDarkFog(localPlanet); } } } private static void ClearPlanetDarkFog(PlanetData planet) { LogInfo("planet.name: " + planet.name); LogInfo("astroId: " + planet.astroId); PlanetFactory orCreateFactory = GameMain.data.GetOrCreateFactory(planet); if (orCreateFactory?.enemySystem?.bases != null) { ObjectPool bases = orCreateFactory.enemySystem.bases; List list = CollectGroundBaseIdsDescending(bases); if (list.Count <= 0) { ClearDarkFogAssaultTips(); return; } HashSet baseIds = new HashSet(list); List removedModels = new List(); ClearGroundUnits(orCreateFactory, baseIds, removedModels); ClearGroundBaseFormations(orCreateFactory, list); ClearGroundNonCoreBuildings(orCreateFactory, list, removedModels); ClearGroundBaseCores(orCreateFactory, list, removedModels); ReturnRelaysForGroundBases(planet, baseIds); UnlinkGroundBaseRuins(orCreateFactory, bases, list); ClearLocalDarkFogRenderResidue(planet, orCreateFactory, list, removedModels); RefreshGroundDefenseSearch(orCreateFactory); ClearDarkFogAssaultTips(); } } private static List CollectGroundBaseIdsDescending(ObjectPool bases) { List list = new List(); if (bases?.buffer == null) { return list; } for (int num = bases.cursor - 1; num > 0; num--) { DFGBaseComponent val = bases.buffer[num]; if (val != null && val.id == num) { list.Add(num); } } return list; } private static void ClearGroundUnits(PlanetFactory planetFactory, HashSet baseIds, List removedModels) { foreach (int item in CollectGroundUnitEnemyIdsDescending(planetFactory, baseIds)) { KillGroundEnemyFinally(planetFactory, item, "unit", removedModels); } } private static void ClearGroundNonCoreBuildings(PlanetFactory planetFactory, List baseIds, List removedModels) { for (int i = 0; i < 8; i++) { int num = 0; foreach (int baseId in baseIds) { foreach (int item in CollectGroundNonCoreBuildingEnemyIdsDescending(planetFactory, baseId)) { if (KillGroundEnemyFinally(planetFactory, item, "building", removedModels)) { num++; } } } ExecuteDeferredGroundEnemyChanges(planetFactory); if (num == 0) { break; } } } private static void ClearGroundBaseCores(PlanetFactory planetFactory, List baseIds, List removedModels) { foreach (int baseId in baseIds) { int enemyId = GetGroundBase(planetFactory, baseId)?.enemyId ?? 0; if (IsGroundCoreEnemy(planetFactory, enemyId, baseId)) { KillGroundEnemyFinally(planetFactory, enemyId, "core", removedModels); } } } private static List CollectGroundUnitEnemyIdsDescending(PlanetFactory planetFactory, HashSet baseIds) { List list = new List(); HashSet hashSet = new HashSet(); DataPool val = planetFactory?.enemySystem?.units; if (planetFactory?.enemyPool == null || baseIds == null || baseIds.Count <= 0) { return list; } if (val?.buffer != null) { for (int num = val.cursor - 1; num > 0; num--) { ref EnemyUnitComponent reference = ref val.buffer[num]; if (reference.id == num && baseIds.Contains(reference.baseId) && IsGroundUnitEnemy(planetFactory, reference.enemyId, reference.baseId)) { list.Add(reference.enemyId); hashSet.Add(reference.enemyId); } } } for (int num2 = planetFactory.enemyCursor - 1; num2 > 0; num2--) { ref EnemyData reference2 = ref planetFactory.enemyPool[num2]; if (reference2.id == num2 && reference2.dynamic && !reference2.isSpace && baseIds.Contains(reference2.owner) && !hashSet.Contains(num2)) { list.Add(num2); } } return list; } private static List CollectGroundNonCoreBuildingEnemyIdsDescending(PlanetFactory planetFactory, int baseId) { List list = new List(); HashSet hashSet = new HashSet(); Builder[] array = GetGroundBase(planetFactory, baseId)?.pbuilders; if (array != null) { for (int num = array.Length - 1; num > 1; num--) { int instId = array[num].instId; if (IsGroundNonCoreBuildingEnemy(planetFactory, instId, baseId)) { list.Add(instId); hashSet.Add(instId); } } } if (planetFactory?.enemyPool == null) { return list; } for (int num2 = planetFactory.enemyCursor - 1; num2 > 0; num2--) { ref EnemyData reference = ref planetFactory.enemyPool[num2]; if (reference.id == num2 && !reference.dynamic && !reference.isSpace && reference.owner == baseId && reference.dfGBaseId != baseId && !hashSet.Contains(num2)) { list.Add(num2); } } return list; } private static bool IsGroundUnitEnemy(PlanetFactory planetFactory, int enemyId, int baseId) { if (!IsLiveGroundEnemy(planetFactory, enemyId)) { return false; } ref EnemyData reference = ref planetFactory.enemyPool[enemyId]; if (reference.dynamic) { return reference.owner == baseId; } return false; } private static bool IsGroundNonCoreBuildingEnemy(PlanetFactory planetFactory, int enemyId, int baseId) { if (!IsLiveGroundEnemy(planetFactory, enemyId)) { return false; } ref EnemyData reference = ref planetFactory.enemyPool[enemyId]; if (!reference.dynamic && reference.owner == baseId) { return reference.dfGBaseId != baseId; } return false; } private static bool IsGroundCoreEnemy(PlanetFactory planetFactory, int enemyId, int baseId) { if (!IsLiveGroundEnemy(planetFactory, enemyId)) { return false; } ref EnemyData reference = ref planetFactory.enemyPool[enemyId]; if (!reference.dynamic) { return reference.dfGBaseId == baseId; } return false; } private static bool KillGroundEnemyFinally(PlanetFactory planetFactory, int enemyId, string kind, List removedModels) { if (!IsLiveGroundEnemy(planetFactory, enemyId)) { return false; } try { RememberEnemyModel(planetFactory, enemyId, removedModels); LogInfo("KillEnemyFinally " + kind + " -> enemyData.id: " + enemyId); planetFactory.KillEnemyFinally(enemyId, ref CombatStat.empty); return true; } catch (Exception ex) { LogInfo("error to kill ground " + kind + " " + enemyId + ": " + ex.Message); return false; } } private static bool IsLiveGroundEnemy(PlanetFactory planetFactory, int enemyId) { if (planetFactory?.enemyPool != null && enemyId > 0 && enemyId < planetFactory.enemyCursor && enemyId < planetFactory.enemyPool.Length && planetFactory.enemyPool[enemyId].id == enemyId) { return !planetFactory.enemyPool[enemyId].isSpace; } return false; } private static void RememberEnemyModel(PlanetFactory planetFactory, int enemyId, List removedModels) { if (removedModels != null && IsLiveGroundEnemy(planetFactory, enemyId)) { ref EnemyData reference = ref planetFactory.enemyPool[enemyId]; if (reference.modelId > 0) { removedModels.Add(new EnemyModelRef { ModelIndex = reference.modelIndex, ModelId = reference.modelId }); } } } private static void ClearGroundBaseFormations(PlanetFactory planetFactory, List baseIds) { foreach (int baseId in baseIds) { DFGBaseComponent groundBase = GetGroundBase(planetFactory, baseId); if (groundBase == null || groundBase.forms == null) { continue; } for (int num = groundBase.forms.Length - 1; num >= 0; num--) { EnemyFormation val = groundBase.forms[num]; if (val != null && val.unitCount > 0) { try { LogInfo("clear DFGBaseComponent:" + groundBase.id + " -> form count: " + val.unitCount); val.Clear(); } catch (Exception ex) { LogInfo("error to clear form " + num + " for base " + baseId + ": " + ex.Message); } } } } } private static DFGBaseComponent GetGroundBase(PlanetFactory planetFactory, int baseId) { ObjectPool val = planetFactory?.enemySystem?.bases; if (baseId <= 0 || val?.buffer == null || baseId >= val.cursor) { return null; } DFGBaseComponent val2 = val.buffer[baseId]; if (val2 == null || val2.id != baseId) { return null; } return val2; } private static void ExecuteDeferredGroundEnemyChanges(PlanetFactory planetFactory) { try { if (planetFactory != null) { EnemyDFGroundSystem enemySystem = planetFactory.enemySystem; if (enemySystem != null) { enemySystem.ExecuteDeferredEnemyChange(); } } } catch (Exception ex) { LogInfo("error to execute deferred ground enemy changes: " + ex.Message); } } private static void ReturnRelaysForGroundBases(PlanetData planet, HashSet baseIds) { if (planet?.star != null && GameMain.spaceSector != null && baseIds != null && baseIds.Count > 0) { for (EnemyDFHiveSystem val = GameMain.spaceSector.dfHives[planet.star.index]; val != null; val = val.nextSibling) { ReturnRelaysForGroundBases(val, planet.astroId, baseIds); } } } private static void ReturnRelaysForGroundBases(EnemyDFHiveSystem hive, int planetAstroId, HashSet baseIds) { if (hive?.relays?.buffer == null) { return; } for (int num = hive.relays.cursor - 1; num > 0; num--) { DFRelayComponent val = hive.relays.buffer[num]; if (val != null && val.id == num) { bool flag = val.targetAstroId == planetAstroId && baseIds.Contains(val.baseId); bool flag2 = val.searchAstroId == planetAstroId; if (flag || flag2) { try { if (flag2) { val.ResetSearchStates(); val.ResetTargetedMarker(); } if (flag && ReturnRelay(val)) { hive.relayNeutralizedCounter++; } } catch (Exception ex) { LogInfo("error to return relay " + val.id + ": " + ex.Message); } } } } } private static bool ReturnRelay(DFRelayComponent relay) { //IL_0060: 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_0090: Unknown result type (might be due to invalid IL or missing references) LogInfo("return relay -> relay.id: " + relay.id + ", enemyId: " + relay.enemyId); if (relay.stage == 2) { relay.LeaveBase(); return true; } if (relay.direction < 0) { relay.ResetSearchStates(); relay.ResetTargetedMarker(); return false; } relay.ClearBaseReferences(); relay.targetAstroId = 0; relay.targetLPos = Vector3.zero; relay.targetYaw = 0f; relay.baseState = 0; relay.baseId = 0; relay.baseTicks = 0; relay.baseEvolve = default(EvolveData); relay.baseRespawnCD = 0; relay.direction = -1; relay.param0 = 0f; relay.RemoveAllCarriers(); relay.ResetSearchStates(); relay.ResetTargetedMarker(); return true; } private static void UnlinkGroundBaseRuins(PlanetFactory planetFactory, ObjectPool bases, List baseIds) { foreach (int baseId in baseIds) { if (baseId <= 0 || bases?.buffer == null || baseId >= bases.cursor) { continue; } DFGBaseComponent val = bases.buffer[baseId]; if (val == null || val.id != baseId) { continue; } try { int enemyId = val.enemyId; int ruinId = val.ruinId; LogInfo("unlink DFGBaseComponent -> base.id: " + baseId + ", enemyId: " + enemyId + ", ruinId: " + ruinId); val.relayId = 0; val.relayEnemyId = 0; val.hiveAstroId = 0; if (IsLiveGroundEnemy(planetFactory, enemyId)) { planetFactory.RemoveEnemyWithComponents(enemyId); } else { RemoveGroundBaseComponentOnly(planetFactory, baseId); } } catch (Exception ex) { LogInfo("error to unlink DFGBaseComponent " + baseId + ": " + ex.Message); } } } private static void RemoveGroundBaseComponentOnly(PlanetFactory planetFactory, int baseId) { if (planetFactory?.enemySystem != null && baseId > 0) { if (planetFactory.platformSystem != null) { planetFactory.platformSystem.RemoveStateArea((uint)(0x1000000uL | (ulong)baseId)); } planetFactory.enemySystem.RemoveDFGBaseComponent(baseId); } } private static void ClearLocalDarkFogRenderResidue(PlanetData planet, PlanetFactory planetFactory, List baseIds, List removedModels) { if (!((Object)(object)planet?.factoryModel == (Object)null) && planetFactory != null && planet == GameMain.localPlanet && planet.factoryLoaded) { RemoveRememberedEnemyModels(planetFactory, removedModels); ClearLocalGroundRenderer(planet.factoryModel, planetFactory, baseIds); ClearLocalFormationRenderers(planet.factoryModel); } } private static void RemoveRememberedEnemyModels(PlanetFactory planetFactory, List removedModels) { if (removedModels == null || removedModels.Count <= 0) { return; } GPUInstancingManager gpuiManager = GameMain.gpuiManager; if (((gpuiManager != null) ? gpuiManager.activeFactory : null) != planetFactory) { return; } HashSet hashSet = new HashSet(); foreach (EnemyModelRef removedModel in removedModels) { if (removedModel.ModelId > 0 && hashSet.Add(removedModel.ModelId)) { try { GameMain.gpuiManager.RemoveModel(removedModel.ModelIndex, removedModel.ModelId, true); } catch (Exception ex) { int modelId = removedModel.ModelId; LogInfo("error to remove remembered enemy model " + modelId + ": " + ex.Message); } } } } private static void ClearLocalGroundRenderer(FactoryModel factoryModel, PlanetFactory planetFactory, List baseIds) { EnemyDFGroundRenderer dfGroundRenderer = factoryModel.dfGroundRenderer; if (dfGroundRenderer == null) { return; } try { dfGroundRenderer.enemySystem = planetFactory.enemySystem; if (dfGroundRenderer.builderArr != null && baseIds != null) { foreach (int baseId in baseIds) { int num = baseId * 80; int num2 = Math.Min(num + 80, dfGroundRenderer.builderArr.Length); for (int i = num; i < num2; i++) { dfGroundRenderer.builderArr[i].instId = 0u; } } } if (dfGroundRenderer.truckSegments != null) { Array.Clear(dfGroundRenderer.truckSegments, 0, dfGroundRenderer.truckSegments.Length); } if (dfGroundRenderer.truckBuilderIndices != null) { Array.Clear(dfGroundRenderer.truckBuilderIndices, 0, dfGroundRenderer.truckBuilderIndices.Length); } } catch (Exception ex) { LogInfo("error to clear local ground renderer residue: " + ex.Message); } } private static void ClearLocalFormationRenderers(FactoryModel factoryModel) { EnemyFormationRenderer[] dfFormRenderers = factoryModel.dfFormRenderers; if (dfFormRenderers == null) { return; } EnemyFormationRenderer[] array = dfFormRenderers; foreach (EnemyFormationRenderer val in array) { if (val != null) { val.unitCount = 0; val.stateCursor = 0; val.groupCursor = 0; } } } private static void RefreshGroundDefenseSearch(PlanetFactory planetFactory) { try { if (planetFactory != null) { DefenseSystem defenseSystem = planetFactory.defenseSystem; if (defenseSystem != null) { defenseSystem.RefreshTurretSearchPair(); } } } catch (Exception ex) { LogInfo("error to refresh turret search pair: " + ex.Message); } } private static void ClearDarkFogAssaultTips() { try { UIRoot instance = UIRoot.instance; if (instance == null) { return; } UIGame uiGame = instance.uiGame; if (uiGame != null) { UIDarkFogAssaultTip dfAssaultTip = uiGame.dfAssaultTip; if (dfAssaultTip != null) { dfAssaultTip.ClearAllSpots(); } } } catch (Exception) { LogInfo("error to clear dark fog assault tips"); } } internal static void ClearCurrentStarSpaceDarkFog() { SaveCurrentGame(); if (GameMain.mainPlayer != null) { StarData localStar = GameMain.localStar; if (localStar != null) { ClearStarSpaceDarkFog(localStar); } } } private static void ClearStarSpaceDarkFog(StarData star) { SpaceSector spaceSector = GameMain.spaceSector; List list = new List(); for (int num = spaceSector.enemyCursor - 1; num > 0; num--) { ref EnemyData reference = ref spaceSector.enemyPool[num]; if (reference.id == num && !((EnemyData)(ref reference)).isInvincible && reference.dfSCoreId <= 0 && reference.astroId == star.astroId) { LogInfo("active relays -> " + reference.id); list.Add(reference.id); } } for (EnemyDFHiveSystem val = spaceSector.dfHives[star.index]; val != null; val = val.nextSibling) { if (val.isAlive) { LogInfo("hiveAstroId " + val.hiveAstroId); LogInfo("rootEnemyId " + val.rootEnemyId); CollectKillableEnemyIds(spaceSector, list, val.units, (Func)((EnemyUnitComponent component) => component.enemyId)); CollectKillableEnemyIds(spaceSector, list, val.tinders, (Func)((DFTinderComponent component) => component.enemyId)); CollectIdleRelayEnemyIds(spaceSector, list, val); CollectKillableEnemyIds(spaceSector, list, val.turrets, (Func)((DFSTurretComponent component) => component.enemyId)); CollectKillableEnemyIds(spaceSector, list, val.gammas, (Func)((DFSGammaComponent component) => component.enemyId)); CollectKillableEnemyIds(spaceSector, list, val.replicators, (Func)((DFSReplicatorComponent component) => component.enemyId)); CollectKillableEnemyIds(spaceSector, list, val.connectors, (Func)((DFSConnectorComponent component) => component.enemyId)); CollectKillableEnemyIds(spaceSector, list, val.nodes, (Func)((DFSNodeComponent component) => component.enemyId)); CollectKillableEnemyIds(spaceSector, list, val.builders, (Func)((EnemyBuilderComponent component) => component.enemyId)); ClearHiveFormations(val); DrainHiveCoreBuilders(val); } } foreach (int item in list.Distinct()) { try { spaceSector.KillEnemyFinal(item, ref CombatStat.empty); } catch (Exception) { LogInfo("error to kill " + item); } } MakeHiveCoresInvincible(star); } private static void CollectKillableEnemyIds(SpaceSector spaceSector, List enemyIds, DataPool pool, Func getEnemyId) where T : struct, IPoolElement { for (int num = pool.cursor - 1; num > 0; num--) { int num2 = getEnemyId(pool.buffer[num]); if (CanKillSpaceEnemy(spaceSector, num2)) { enemyIds.Add(num2); } } } private static void CollectIdleRelayEnemyIds(SpaceSector spaceSector, List enemyIds, EnemyDFHiveSystem hive) { for (int num = hive.idleRelayCount - 1; num > 0; num--) { DFRelayComponent val = hive.relays.buffer[hive.idleRelayIds[num]]; if (CanKillSpaceEnemy(spaceSector, val.enemyId)) { enemyIds.Add(val.enemyId); } } } private static bool CanKillSpaceEnemy(SpaceSector spaceSector, int enemyId) { if (enemyId <= 0) { return false; } ref EnemyData reference = ref spaceSector.enemyPool[enemyId]; if (!((EnemyData)(ref reference)).isInvincible) { return reference.dfSCoreId <= 0; } return false; } private static void ClearHiveFormations(EnemyDFHiveSystem hive) { EnemyFormation[] forms = hive.forms; for (int i = 0; i < forms.Length; i++) { if (forms[i].unitCount > 0) { LogInfo("clear form " + forms[i].unitCount); forms[i].Clear(); } } } private static void DrainHiveCoreBuilders(EnemyDFHiveSystem hive) { for (int num = hive.cores.cursor - 1; num > 0; num--) { ref EnemyBuilderComponent reference = ref hive.builders.buffer[hive.cores.buffer[num].builderId]; reference.matter = 0; reference.energy = 0; } } internal static void FillGalaxyWithDarkFogHives() { SaveCurrentGame(); if (GameMain.mainPlayer == null) { return; } GalaxyData galaxy = GameMain.galaxy; SpaceSector spaceSector = GameMain.spaceSector; for (int i = 0; i < galaxy.starCount; i++) { StarData val = galaxy.stars[i]; int num = Math.Min(val.maxHiveCount, 8); int num2 = CountHives(spaceSector.dfHives[val.index]); for (int j = 0; j < num - num2; j++) { EnemyDFHiveSystem val2 = spaceSector.TryCreateNewHive(val); if (val2 != null) { LogInfo(val.displayName + " Add 1 hive"); val2.SetForNewGame(); } } } } private static int CountHives(EnemyDFHiveSystem hive) { int num = 0; while (hive != null) { num++; hive = hive.nextSibling; } return num; } private static void MakeHiveCoresInvincible(StarData star) { SpaceSector spaceSector = GameMain.spaceSector; for (EnemyDFHiveSystem val = spaceSector.dfHives[star.index]; val != null; val = val.nextSibling) { for (int num = val.cores.cursor - 1; num > 0; num--) { ((EnemyData)(ref spaceSector.enemyPool[val.cores.buffer[num].enemyId])).isInvincible = true; } } } private static void SaveCurrentGame() { string arg = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); string arg2 = GameMain.data.gameDesc.galaxySeed.ToString("00000000"); GameSave.SaveCurrentGame($"[{arg2}] {arg}"); } private static void LogInfo(string message) { ManualLogSource log = Log; if (log != null) { log.LogInfo((object)message); } } } internal static class SurfaceRuinControl { private enum LatitudeBand { Low, Mid, High } private const short BasePitRuinModelIndex = 406; private const int Level30BasePitLifeTime = -31; private const float DuplicateRuinRadius = 50f; private const float SurfaceOffset = 0.2f; private const float LowLatitudeMax = 28.5f; private const float MidLatitudeMax = 46.5f; internal static ManualLogSource Log; private static readonly Vector3[] LowLatitudeRuinPositions = (Vector3[])(object)new Vector3[76] { new Vector3(-173.0104f, -47.818897f, 88.66112f), new Vector3(173.0104f, -47.818897f, 88.66112f), new Vector3(173.0104f, 47.818897f, 88.66112f), new Vector3(-173.0104f, 47.818897f, 88.66112f), new Vector3(-117.67461f, -137.77583f, 85.15015f), new Vector3(117.67461f, -137.77583f, 85.15015f), new Vector3(117.67461f, 137.77583f, 85.15015f), new Vector3(-117.67461f, 137.77583f, 85.15015f), new Vector3(-161.9652f, -100.1f, 61.865204f), new Vector3(161.9652f, -100.1f, 61.865204f), new Vector3(161.9652f, 100.1f, 61.865204f), new Vector3(-161.9652f, 100.1f, 61.865204f), new Vector3(191.2756f, 0f, 59.10741f), new Vector3(-191.2756f, 0f, 59.10741f), new Vector3(-32.524464f, -190.40152f, 52.625683f), new Vector3(32.524464f, -190.40152f, 52.625683f), new Vector3(32.524464f, 190.40152f, 52.625683f), new Vector3(-32.524464f, 190.40152f, 52.625683f), new Vector3(-88.66112f, -173.0104f, 47.818897f), new Vector3(88.66112f, -173.0104f, 47.818897f), new Vector3(88.66112f, 173.0104f, 47.818897f), new Vector3(-88.66112f, 173.0104f, 47.818897f), new Vector3(-190.40152f, -52.625683f, 32.524464f), new Vector3(190.40152f, -52.625683f, 32.524464f), new Vector3(190.40152f, 52.625683f, 32.524464f), new Vector3(-190.40152f, 52.625683f, 32.524464f), new Vector3(-136.48001f, -143.4567f, 29.553705f), new Vector3(136.48001f, -143.4567f, 29.553705f), new Vector3(136.48001f, 143.4567f, 29.553705f), new Vector3(-136.48001f, 143.4567f, 29.553705f), new Vector3(-170.3003f, -105.251366f, 0f), new Vector3(-105.251366f, -170.3003f, 0f), new Vector3(-59.10741f, -191.2756f, 0f), new Vector3(0f, -200.2f, 0f), new Vector3(59.10741f, -191.2756f, 0f), new Vector3(105.251366f, -170.3003f, 0f), new Vector3(170.3003f, -105.251366f, 0f), new Vector3(200.2f, 0f, 0f), new Vector3(170.3003f, 105.251366f, 0f), new Vector3(105.251366f, 170.3003f, 0f), new Vector3(59.10741f, 191.2756f, 0f), new Vector3(0f, 200.2f, 0f), new Vector3(-59.10741f, 191.2756f, 0f), new Vector3(-105.251366f, 170.3003f, 0f), new Vector3(-170.3003f, 105.251366f, 0f), new Vector3(-200.2f, 0f, 0f), new Vector3(-136.48001f, -143.4567f, -29.553705f), new Vector3(136.48001f, -143.4567f, -29.553705f), new Vector3(136.48001f, 143.4567f, -29.553705f), new Vector3(-136.48001f, 143.4567f, -29.553705f), new Vector3(-190.40152f, -52.625683f, -32.524464f), new Vector3(190.40152f, -52.625683f, -32.524464f), new Vector3(190.40152f, 52.625683f, -32.524464f), new Vector3(-190.40152f, 52.625683f, -32.524464f), new Vector3(-88.66112f, -173.0104f, -47.818897f), new Vector3(88.66112f, -173.0104f, -47.818897f), new Vector3(88.66112f, 173.0104f, -47.818897f), new Vector3(-88.66112f, 173.0104f, -47.818897f), new Vector3(-32.524464f, -190.40152f, -52.625683f), new Vector3(32.524464f, -190.40152f, -52.625683f), new Vector3(32.524464f, 190.40152f, -52.625683f), new Vector3(-32.524464f, 190.40152f, -52.625683f), new Vector3(191.2756f, 0f, -59.10741f), new Vector3(-191.2756f, 0f, -59.10741f), new Vector3(-161.9652f, -100.1f, -61.865204f), new Vector3(161.9652f, -100.1f, -61.865204f), new Vector3(161.9652f, 100.1f, -61.865204f), new Vector3(-161.9652f, 100.1f, -61.865204f), new Vector3(-117.67461f, -137.77583f, -85.15015f), new Vector3(117.67461f, -137.77583f, -85.15015f), new Vector3(117.67461f, 137.77583f, -85.15015f), new Vector3(-117.67461f, 137.77583f, -85.15015f), new Vector3(-173.0104f, -47.818897f, -88.66112f), new Vector3(173.0104f, -47.818897f, -88.66112f), new Vector3(173.0104f, 47.818897f, -88.66112f), new Vector3(-173.0104f, 47.818897f, -88.66112f) }; private static readonly Vector3[] MidLatitudeRuinPositions = (Vector3[])(object)new Vector3[48] { new Vector3(-29.553705f, -136.48001f, 143.4567f), new Vector3(29.553705f, -136.48001f, 143.4567f), new Vector3(29.553705f, 136.48001f, 143.4567f), new Vector3(-29.553705f, 136.48001f, 143.4567f), new Vector3(-85.15015f, -117.67461f, 137.77583f), new Vector3(85.15015f, -117.67461f, 137.77583f), new Vector3(85.15015f, 117.67461f, 137.77583f), new Vector3(-85.15015f, 117.67461f, 137.77583f), new Vector3(-143.4567f, -29.553705f, 136.48001f), new Vector3(143.4567f, -29.553705f, 136.48001f), new Vector3(143.4567f, 29.553705f, 136.48001f), new Vector3(-143.4567f, 29.553705f, 136.48001f), new Vector3(-137.77583f, -85.15015f, 117.67461f), new Vector3(137.77583f, -85.15015f, 117.67461f), new Vector3(137.77583f, 85.15015f, 117.67461f), new Vector3(-137.77583f, 85.15015f, 117.67461f), new Vector3(0f, -170.3003f, 105.251366f), new Vector3(170.3003f, 0f, 105.251366f), new Vector3(0f, 170.3003f, 105.251366f), new Vector3(-170.3003f, 0f, 105.251366f), new Vector3(-61.865204f, -161.9652f, 100.1f), new Vector3(61.865204f, -161.9652f, 100.1f), new Vector3(61.865204f, 161.9652f, 100.1f), new Vector3(-61.865204f, 161.9652f, 100.1f), new Vector3(-61.865204f, -161.9652f, -100.1f), new Vector3(61.865204f, -161.9652f, -100.1f), new Vector3(61.865204f, 161.9652f, -100.1f), new Vector3(-61.865204f, 161.9652f, -100.1f), new Vector3(0f, -170.3003f, -105.251366f), new Vector3(170.3003f, 0f, -105.251366f), new Vector3(0f, 170.3003f, -105.251366f), new Vector3(-170.3003f, 0f, -105.251366f), new Vector3(-137.77583f, -85.15015f, -117.67461f), new Vector3(137.77583f, -85.15015f, -117.67461f), new Vector3(137.77583f, 85.15015f, -117.67461f), new Vector3(-137.77583f, 85.15015f, -117.67461f), new Vector3(-143.4567f, -29.553705f, -136.48001f), new Vector3(143.4567f, -29.553705f, -136.48001f), new Vector3(143.4567f, 29.553705f, -136.48001f), new Vector3(-143.4567f, 29.553705f, -136.48001f), new Vector3(-85.15015f, -117.67461f, -137.77583f), new Vector3(85.15015f, -117.67461f, -137.77583f), new Vector3(85.15015f, 117.67461f, -137.77583f), new Vector3(-85.15015f, 117.67461f, -137.77583f), new Vector3(-29.553705f, -136.48001f, -143.4567f), new Vector3(29.553705f, -136.48001f, -143.4567f), new Vector3(29.553705f, 136.48001f, -143.4567f), new Vector3(-29.553705f, 136.48001f, -143.4567f) }; private static readonly Vector3[] HighLatitudeRuinPositions = (Vector3[])(object)new Vector3[38] { new Vector3(0f, 0f, 200.2f), new Vector3(0f, -59.10741f, 191.2756f), new Vector3(0f, 59.10741f, 191.2756f), new Vector3(-52.625683f, -32.524464f, 190.40152f), new Vector3(52.625683f, -32.524464f, 190.40152f), new Vector3(52.625683f, 32.524464f, 190.40152f), new Vector3(-52.625683f, 32.524464f, 190.40152f), new Vector3(-47.818897f, -88.66112f, 173.0104f), new Vector3(47.818897f, -88.66112f, 173.0104f), new Vector3(47.818897f, 88.66112f, 173.0104f), new Vector3(-47.818897f, 88.66112f, 173.0104f), new Vector3(0f, -105.251366f, 170.3003f), new Vector3(105.251366f, 0f, 170.3003f), new Vector3(0f, 105.251366f, 170.3003f), new Vector3(-105.251366f, 0f, 170.3003f), new Vector3(-100.1f, -61.865204f, 161.9652f), new Vector3(100.1f, -61.865204f, 161.9652f), new Vector3(100.1f, 61.865204f, 161.9652f), new Vector3(-100.1f, 61.865204f, 161.9652f), new Vector3(-100.1f, -61.865204f, -161.9652f), new Vector3(100.1f, -61.865204f, -161.9652f), new Vector3(100.1f, 61.865204f, -161.9652f), new Vector3(-100.1f, 61.865204f, -161.9652f), new Vector3(0f, -105.251366f, -170.3003f), new Vector3(105.251366f, 0f, -170.3003f), new Vector3(0f, 105.251366f, -170.3003f), new Vector3(-105.251366f, 0f, -170.3003f), new Vector3(-47.818897f, -88.66112f, -173.0104f), new Vector3(47.818897f, -88.66112f, -173.0104f), new Vector3(47.818897f, 88.66112f, -173.0104f), new Vector3(-47.818897f, 88.66112f, -173.0104f), new Vector3(-52.625683f, -32.524464f, -190.40152f), new Vector3(52.625683f, -32.524464f, -190.40152f), new Vector3(52.625683f, 32.524464f, -190.40152f), new Vector3(-52.625683f, 32.524464f, -190.40152f), new Vector3(0f, -59.10741f, -191.2756f), new Vector3(0f, 59.10741f, -191.2756f), new Vector3(0f, 0f, -200.2f) }; internal static void ConstructLowLatitudeRuinsOnCurrentPlanet() { ConstructRuinsOnCurrentPlanet(LatitudeBand.Low, "low-latitude"); } internal static void ConstructMidLatitudeRuinsOnCurrentPlanet() { ConstructRuinsOnCurrentPlanet(LatitudeBand.Mid, "mid-latitude"); } internal static void ConstructHighLatitudeRuinsOnCurrentPlanet() { ConstructRuinsOnCurrentPlanet(LatitudeBand.High, "high-latitude"); } private static void ConstructRuinsOnCurrentPlanet(LatitudeBand targetBand, string bandName) { //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0074: 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_007b: Unknown result type (might be due to invalid IL or missing references) //IL_007e: 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_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) PlanetData localPlanet = GameMain.localPlanet; if (localPlanet == null) { Report("Surface Ruins: no current planet."); return; } PlanetFactory factory = localPlanet.factory; if (factory == null || factory.ruinPool == null) { Report("Surface Ruins: planet " + (localPlanet.displayName ?? localPlanet.name) + " has no loaded factory."); return; } int num = 0; int num2 = 0; Vector3[] allRuinPositions = GetAllRuinPositions(); for (int i = 0; i < allRuinPositions.Length; i++) { Vector3 val = allRuinPositions[i]; if (GetLatitudeBand(val) == targetBand) { Vector3 val2 = SnapToSurface(localPlanet, val); if (HasRuinWithin(factory, val2, 50f)) { num2++; continue; } RuinData val3 = default(RuinData); val3.modelIndex = 406; val3.lifeTime = -31; val3.pos = val2; val3.rot = Maths.SphericalRotation(val2, DeterministicYaw(i)); factory.AddRuinDataWithComponent(val3); num++; } } Report($"Surface Ruins: created {num}, skipped {num2}, total {CountRuinPositions(targetBand)} {bandName} ruins on {localPlanet.displayName ?? localPlanet.name}."); } private static Vector3[] GetAllRuinPositions() { //IL_002d: 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_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_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) Vector3[] array = (Vector3[])(object)new Vector3[LowLatitudeRuinPositions.Length + MidLatitudeRuinPositions.Length + HighLatitudeRuinPositions.Length]; int num = 0; for (int i = 0; i < LowLatitudeRuinPositions.Length; i++) { array[num + i] = LowLatitudeRuinPositions[i]; } num += LowLatitudeRuinPositions.Length; for (int j = 0; j < MidLatitudeRuinPositions.Length; j++) { array[num + j] = MidLatitudeRuinPositions[j]; } num += MidLatitudeRuinPositions.Length; for (int k = 0; k < HighLatitudeRuinPositions.Length; k++) { array[num + k] = HighLatitudeRuinPositions[k]; } return array; } private static int CountRuinPositions(LatitudeBand targetBand) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) int num = 0; Vector3[] allRuinPositions = GetAllRuinPositions(); for (int i = 0; i < allRuinPositions.Length; i++) { if (GetLatitudeBand(allRuinPositions[i]) == targetBand) { num++; } } return num; } private static LatitudeBand GetLatitudeBand(Vector3 position) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) float num = Mathf.Abs(Mathf.Asin(Mathf.Clamp(((Vector3)(ref position)).normalized.y, -1f, 1f)) * 57.29578f); if (num < 28.5f) { return LatitudeBand.Low; } if (num < 46.5f) { return LatitudeBand.Mid; } return LatitudeBand.High; } internal static void BuildGeothermalOnIdleRuinsCurrentPlanet() { //IL_00f4: Unknown result type (might be due to invalid IL or missing references) PlanetData localPlanet = GameMain.localPlanet; if (localPlanet == null) { Report("Surface Ruins: no current planet."); return; } PlanetFactory factory = localPlanet.factory; if (factory == null || factory.ruinPool == null || factory.powerSystem == null) { Report("Surface Ruins: planet " + (localPlanet.displayName ?? localPlanet.name) + " has no loaded factory or power system."); return; } ItemProto val = FindGeothermalPowerItem(); if (val == null || val.prefabDesc == null || !val.prefabDesc.geothermal) { Report("Surface Ruins: geothermal power item not found."); return; } int num = 0; int num2 = 0; int num3 = 0; int num4 = 0; RuinData[] ruinPool = factory.ruinPool; int ruinCursor = factory.ruinCursor; for (int i = 1; i < ruinCursor; i++) { if (ruinPool[i].id == i && ruinPool[i].modelIndex == 406) { if (HasGeothermalOnBaseRuin(factory, i)) { num2++; } else if (HasBaseOnRuin(factory, i)) { num3++; } else if (BuildGeothermalEntity(factory, val, i, ruinPool[i].pos) > 0) { num++; } else { num4++; } } } Report($"Surface Ruins: built geothermal {num}, occupied {num2}, bound bases {num3}, failed {num4} on {localPlanet.displayName ?? localPlanet.name}."); } private static ItemProto FindGeothermalPowerItem() { if (((ProtoSet)(object)LDB.items)?.dataArray == null) { return null; } ItemProto[] dataArray = ((ProtoSet)(object)LDB.items).dataArray; foreach (ItemProto val in dataArray) { if (val?.prefabDesc != null && val.CanBuild && val.IsEntity && val.prefabDesc.isPowerGen && val.prefabDesc.geothermal) { return val; } } return null; } private static bool HasGeothermalOnBaseRuin(PlanetFactory factory, int baseRuinId) { if (factory == null || factory.powerSystem == null || baseRuinId <= 0) { return false; } PowerGeneratorComponent[] genPool = factory.powerSystem.genPool; int genCursor = factory.powerSystem.genCursor; for (int i = 1; i < genCursor; i++) { ref PowerGeneratorComponent reference = ref genPool[i]; if (reference.id == i && reference.geothermal && reference.baseRuinId == baseRuinId) { return true; } } PrebuildData[] prebuildPool = factory.prebuildPool; int prebuildCursor = factory.prebuildCursor; for (int j = 1; j < prebuildCursor; j++) { ref PrebuildData reference2 = ref prebuildPool[j]; if (reference2.id == j && reference2.paramCount > 0 && reference2.parameters != null && reference2.parameters[0] == baseRuinId) { ItemProto val = ((ProtoSet)(object)LDB.items).Select((int)reference2.protoId); if (val?.prefabDesc != null && val.prefabDesc.geothermal) { return true; } } } return false; } private static bool HasBaseOnRuin(PlanetFactory factory, int baseRuinId) { if (factory?.enemySystem?.bases == null || baseRuinId <= 0) { return false; } ObjectPool bases = factory.enemySystem.bases; for (int i = 1; i < bases.cursor; i++) { DFGBaseComponent val = bases.buffer[i]; if (val != null && val.id == i && val.ruinId == baseRuinId) { return true; } } return false; } private static int BuildGeothermalEntity(PlanetFactory factory, ItemProto geothermalItem, int baseRuinId, Vector3 ruinPos) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: 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_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_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0081: 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_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: 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_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_0179: Unknown result type (might be due to invalid IL or missing references) //IL_01c5: Unknown result type (might be due to invalid IL or missing references) if (((factory != null) ? factory.planet : null) == null || geothermalItem?.prefabDesc == null || baseRuinId <= 0) { return 0; } Vector3 val = SnapGeothermalBuildPosition(factory.planet, ruinPos); Quaternion val2 = Maths.SphericalRotation(val, 0f); PrebuildData val3 = default(PrebuildData); val3.isDestroyed = false; val3.protoId = (short)((Proto)geothermalItem).ID; val3.modelIndex = (short)geothermalItem.ModelIndex; val3.pos = val; val3.pos2 = val; val3.rot = val2; val3.rot2 = val2; ((PrebuildData)(ref val3)).InitParametersArray(1); val3.parameters[0] = baseRuinId; int num = factory.AddPrebuildDataWithComponents(val3); if (num <= 0) { return 0; } EntityData val4 = default(EntityData); val4.protoId = val3.protoId; val4.modelIndex = val3.modelIndex; val4.pos = val3.pos; val4.rot = val3.rot; val4.alt = ((Vector3)(ref val4.pos)).magnitude; val4.tilt = val3.tilt; ((EntityData)(ref val4)).localized = factory.planet == GameMain.localPlanet && factory.planet.factoryLoaded; int num2 = factory.AddEntityDataWithComponents(val4, num); if (num2 <= 0) { factory.RemovePrebuildWithComponents(num); return 0; } Player mainPlayer = GameMain.mainPlayer; if (mainPlayer != null) { PlayerController controller = mainPlayer.controller; if (controller != null) { PlayerAction_Build actionBuild = controller.actionBuild; if (actionBuild != null) { actionBuild.NotifyBuilt(-num, num2); } } } factory.RemovePrebuildWithComponents(num); GameHistoryData history = GameMain.history; if (history != null) { history.MarkItemBuilt((int)val3.protoId, 1); } if (factory.entityPool[num2].beltId > 0) { factory.OnBeltBuilt(num2); } if (factory.entityPool[num2].inserterId > 0) { factory.OnInserterBuilt(num2); } if ((int)geothermalItem.prefabDesc.addonType != 0) { factory.OnAddonBuilt(num2); } factory.OnBuildEntity(num2, num); if (!PlanetFactory.batchBuild) { factory.OnSinglyBuildEntity(num2, num); } GameScenarioLogic gameScenario = GameMain.gameScenario; if (gameScenario != null) { gameScenario.NotifyOnBuild(factory.planet.id, (int)factory.entityPool[num2].protoId, num2); } return num2; } private static Vector3 SnapGeothermalBuildPosition(PlanetData planet, Vector3 ruinPos) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) if (planet.aux != null) { return planet.aux.Snap(ruinPos, true); } return ((Vector3)(ref ruinPos)).normalized * (planet.realRadius + 0.2f); } private static Vector3 SnapToSurface(PlanetData planet, Vector3 templatePos) { //IL_000f: 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_001a: 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_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) float num = planet.realRadius + 0.2f; Vector3 val = ((Vector3)(ref templatePos)).normalized * num; if (planet.aux != null) { val = planet.aux.Snap(val, true); } return val; } private static bool HasRuinWithin(PlanetFactory factory, Vector3 pos, float radius) { //IL_002c: 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_0037: Unknown result type (might be due to invalid IL or missing references) float num = radius * radius; RuinData[] ruinPool = factory.ruinPool; int ruinCursor = factory.ruinCursor; for (int i = 1; i < ruinCursor; i++) { if (ruinPool[i].id == i) { Vector3 val = ruinPool[i].pos - pos; if (((Vector3)(ref val)).sqrMagnitude < num) { return true; } } } return false; } private static float DeterministicYaw(int index) { return (float)index * 137.50777f % 360f; } private static void Report(string message) { ManualLogSource log = Log; if (log != null) { log.LogInfo((object)message); } UIRealtimeTip.Popup(message, false, 0); } } [HarmonyPatch] internal static class BuildAnywhereOnWaterControl { private const string PatchGuid = "me.liantian.plugin.HardFog.BuildAnywhereOnWater"; private static ManualLogSource Log; private static Harmony harmony; private static EventHandler settingChangedHandler; internal static ConfigEntry EnabledConfig { get; private set; } internal static void Init(ConfigEntry enabledConfig, ManualLogSource log) { if (EnabledConfig != null && settingChangedHandler != null) { EnabledConfig.SettingChanged -= settingChangedHandler; } Log = log; EnabledConfig = enabledConfig; settingChangedHandler = OnSettingChanged; EnabledConfig.SettingChanged += settingChangedHandler; SetActive(EnabledConfig.Value); } internal static void Uninit() { if (EnabledConfig != null && settingChangedHandler != null) { EnabledConfig.SettingChanged -= settingChangedHandler; } SetActive(active: false); settingChangedHandler = null; EnabledConfig = null; Log = null; } private static void OnSettingChanged(object sender, EventArgs args) { SetActive(EnabledConfig != null && EnabledConfig.Value); } private static void SetActive(bool active) { if (active) { if (harmony == null) { harmony = Harmony.CreateAndPatchAll(typeof(BuildAnywhereOnWaterControl), "me.liantian.plugin.HardFog.BuildAnywhereOnWater"); ManualLogSource log = Log; if (log != null) { log.LogInfo((object)"BuildAnywhereOnWater enabled"); } } } else if (harmony != null) { harmony.UnpatchSelf(); harmony = null; ManualLogSource log2 = Log; if (log2 != null) { log2.LogInfo((object)"BuildAnywhereOnWater disabled"); } } } [HarmonyPostfix] [HarmonyPatch(typeof(BuildTool_Click), "CheckBuildConditions")] private static void BuildToolClickCheckBuildConditionsPostfix(BuildTool_Click __instance, ref bool __result) { if (((__instance != null) ? ((BuildTool)__instance).buildPreviews : null) != null && ClearNeedGroundConditions(((BuildTool)__instance).buildPreviews)) { __result = IsManualBuildAllowed(((BuildTool)__instance).buildPreviews); RefreshManualCursor(__instance, __result); } } [HarmonyPostfix] [HarmonyPatch(typeof(BuildTool_BlueprintPaste), "CheckBuildConditions")] private static void BuildToolBlueprintPasteCheckBuildConditionsPostfix(BuildTool_BlueprintPaste __instance, ref bool __result) { if (__instance?.bpPool != null && __instance.bpCursor > 0 && ClearNeedGroundConditions(__instance.bpPool, __instance.bpCursor)) { bool removeConnectionErrors = ClearConnectionErrors(__instance.bpPool, __instance.bpCursor); RemoveClearedBlueprintErrors(__instance, removeConnectionErrors); __result = IsBlueprintBuildAllowed(__instance); if (__result && ((BuildTool)__instance).actionBuild?.model != null) { ((BuildTool)__instance).actionBuild.model.cursorState = 0; } } } private static bool ClearNeedGroundConditions(IList previews) { bool flag = false; for (int i = 0; i < previews.Count; i++) { flag |= ClearNeedGroundCondition(previews[i]); } return flag; } private static bool ClearNeedGroundConditions(BuildPreview[] previews, int count) { bool flag = false; int num = Math.Min(count, previews.Length); for (int i = 0; i < num; i++) { flag |= ClearNeedGroundCondition(previews[i]); } return flag; } private static bool ClearNeedGroundCondition(BuildPreview bp) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Invalid comparison between Unknown and I4 //IL_0011: Unknown result type (might be due to invalid IL or missing references) if (bp == null) { return false; } if ((int)bp.condition == 23) { bp.condition = (EBuildCondition)0; return true; } return false; } private static bool ClearConnectionErrors(BuildPreview[] previews, int count) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Invalid comparison between Unknown and I4 //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Invalid comparison between Unknown and I4 //IL_003b: Unknown result type (might be due to invalid IL or missing references) bool result = false; int num = Math.Min(count, previews.Length); for (int i = 0; i < num; i++) { BuildPreview val = previews[i]; if (val != null && (int)val.condition == 201 && AreConnectionsAllowed(val) && (int)val.condition == 201) { val.condition = (EBuildCondition)0; result = true; } } return result; } private static bool AreConnectionsAllowed(BuildPreview bp) { if (IsConnectedPreviewAllowed(bp.input)) { return IsConnectedPreviewAllowed(bp.output); } return false; } private static bool IsConnectedPreviewAllowed(BuildPreview bp) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Invalid comparison between Unknown and I4 //IL_0010: Unknown result type (might be due to invalid IL or missing references) if (bp == null || (int)bp.condition == 51) { return true; } return IsBlueprintAllowedCondition(bp.condition); } private static bool IsManualBuildAllowed(IList previews) { //IL_0010: 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_001f: Invalid comparison between Unknown and I4 for (int i = 0; i < previews.Count; i++) { BuildPreview val = previews[i]; if (val != null && (int)val.condition != 0 && (int)val.condition != 28) { return false; } } return true; } private static bool IsBlueprintBuildAllowed(BuildTool_BlueprintPaste tool) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) int num = Math.Min(tool.bpCursor, tool.bpPool.Length); for (int i = 0; i < num; i++) { BuildPreview val = tool.bpPool[i]; if (val != null && val.bpgpuiModelId > 0 && !IsBlueprintAllowedCondition(val.condition)) { return false; } } return true; } private static bool IsBlueprintAllowedCondition(EBuildCondition condition) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Invalid comparison between Unknown and I4 //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Invalid comparison between Unknown and I4 if ((int)condition != 0 && (int)condition != 28) { return (int)condition == 2; } return true; } private static void RemoveClearedBlueprintErrors(BuildTool_BlueprintPaste tool, bool removeConnectionErrors) { RemoveCondition(tool._tmp_error_types, (EBuildCondition)23); RemoveConditionErrorBuildings(tool, (EBuildCondition)23); if (removeConnectionErrors) { RemoveCondition(tool._tmp_error_types, (EBuildCondition)201); RemoveConditionErrorBuildings(tool, (EBuildCondition)201); } if (tool.rootGridErrors == null) { return; } List list = new List(); foreach (KeyValuePair> rootGridError in tool.rootGridErrors) { if (rootGridError.Value == null) { list.Add(rootGridError.Key); continue; } rootGridError.Value.Remove((EBuildCondition)23); if (removeConnectionErrors) { rootGridError.Value.Remove((EBuildCondition)201); } if (rootGridError.Value.Count == 0) { list.Add(rootGridError.Key); } } for (int i = 0; i < list.Count; i++) { tool.rootGridErrors.Remove(list[i]); } } private static void RemoveCondition(List conditions, EBuildCondition condition) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) if (conditions != null) { while (conditions.Remove(condition)) { } } } private static void RemoveConditionErrorBuildings(BuildTool_BlueprintPaste tool, EBuildCondition condition) { //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Invalid comparison between I4 and Unknown if (tool._tmpErrorBuildings == null || tool._tmpErrorTipsCursor <= 0) { return; } int num = 0; int num2 = Math.Min(tool._tmpErrorTipsCursor, tool._tmpErrorBuildings.Length); for (int i = 0; i < num2; i++) { ulong num3 = tool._tmpErrorBuildings[i]; if ((int)(num3 >> 48) != (int)condition) { if (num != i) { tool._tmpErrorBuildings[num] = num3; } num++; } } for (int j = num; j < num2; j++) { tool._tmpErrorBuildings[j] = 0uL; } tool._tmpErrorTipsCursor = num; } private static void RefreshManualCursor(BuildTool_Click tool, bool allowed) { //IL_0055: 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_0064: Invalid comparison between Unknown and I4 if (((BuildTool)tool).actionBuild?.model == null) { return; } if (allowed) { ((BuildTool)tool).actionBuild.model.cursorState = 0; ((BuildTool)tool).actionBuild.model.cursorText = BuildPreview.GetConditionText((EBuildCondition)0); return; } for (int i = 0; i < ((BuildTool)tool).buildPreviews.Count; i++) { BuildPreview val = ((BuildTool)tool).buildPreviews[i]; if (val != null && (int)val.condition != 0 && (int)val.condition != 28) { ((BuildTool)tool).actionBuild.model.cursorState = -1; ((BuildTool)tool).actionBuild.model.cursorText = val.conditionText; break; } } } } [HarmonyPatch] internal static class SuperThreatReducerControl { private const string PatchGuid = "me.liantian.plugin.HardFog.SuperThreatReducer"; private static ManualLogSource Log; private static Harmony harmony; private static EventHandler settingChangedHandler; internal static ConfigEntry EnabledConfigHive { get; private set; } internal static ConfigEntry EnabledConfigGround { get; private set; } private static bool IsAnyEnabled { get { if (EnabledConfigHive == null || !EnabledConfigHive.Value) { if (EnabledConfigGround != null) { return EnabledConfigGround.Value; } return false; } return true; } } internal static void Init(ConfigEntry enabledConfigHive, ConfigEntry enabledConfigGround, ManualLogSource log) { if (EnabledConfigHive != null && settingChangedHandler != null) { EnabledConfigHive.SettingChanged -= settingChangedHandler; EnabledConfigGround.SettingChanged -= settingChangedHandler; } Log = log; EnabledConfigHive = enabledConfigHive; EnabledConfigGround = enabledConfigGround; settingChangedHandler = OnSettingChanged; EnabledConfigHive.SettingChanged += settingChangedHandler; EnabledConfigGround.SettingChanged += settingChangedHandler; UpdateHarmonyState(); } internal static void Uninit() { if (EnabledConfigHive != null && settingChangedHandler != null) { EnabledConfigHive.SettingChanged -= settingChangedHandler; EnabledConfigGround.SettingChanged -= settingChangedHandler; } DestroyHarmony(); settingChangedHandler = null; EnabledConfigHive = null; EnabledConfigGround = null; Log = null; } private static void OnSettingChanged(object sender, EventArgs args) { UpdateHarmonyState(); } private static void UpdateHarmonyState() { if (IsAnyEnabled) { EnsureHarmony(); } else { DestroyHarmony(); } } private static void EnsureHarmony() { if (harmony == null) { harmony = Harmony.CreateAndPatchAll(typeof(SuperThreatReducerControl), "me.liantian.plugin.HardFog.SuperThreatReducer"); ManualLogSource log = Log; if (log != null) { log.LogInfo((object)"SuperThreatReducer enabled"); } } } private static void DestroyHarmony() { if (harmony != null) { harmony.UnpatchSelf(); harmony = null; ManualLogSource log = Log; if (log != null) { log.LogInfo((object)"SuperThreatReducer disabled"); } } } [HarmonyPostfix] [HarmonyPatch(typeof(EnemyDFHiveSystem), "DecisionAI")] private static void EnemyDFHiveSystem_DecisionAI_Postfix(EnemyDFHiveSystem __instance) { if (EnabledConfigHive != null && EnabledConfigHive.Value && __instance != null && __instance.realized && __instance.isAlive) { __instance.evolve.threat = 0; __instance.evolve.threatshr = 0; } } [HarmonyPrefix] [HarmonyPatch(typeof(EnemyDFHiveSystem), "AssaultingWavesDetermineAI")] private static bool EnemyDFHiveSystem_AssaultingWavesDetermineAI_Prefix() { if (EnabledConfigHive == null || !EnabledConfigHive.Value) { return true; } return false; } [HarmonyPrefix] [HarmonyPatch(typeof(DFGBaseComponent), "UpdateFactoryThreat")] private static bool DFGBaseComponent_UpdateFactoryThreat_Prefix() { if (EnabledConfigGround == null || !EnabledConfigGround.Value) { return true; } return false; } } [HarmonyPatch] internal static class RelayControl { private const string PatchGuid = "me.liantian.plugin.HardFog.RelayControl"; private const int VanillaRelayDemandInterval = 600; private const int FasterRelayDemandInterval = 120; private static ManualLogSource Log; private static Harmony harmony; private static EventHandler fasterRelayLaunchChangedHandler; internal static ConfigEntry FasterRelayLaunchEnabledConfig { get; private set; } internal static ConfigEntry SmartRelayDispatchEnabledConfig { get; private set; } internal static void Init(ConfigEntry fasterRelayLaunchEnabledConfig, ConfigEntry smartRelayDispatchEnabledConfig, ManualLogSource log) { if (FasterRelayLaunchEnabledConfig != null && fasterRelayLaunchChangedHandler != null) { FasterRelayLaunchEnabledConfig.SettingChanged -= fasterRelayLaunchChangedHandler; } Log = log; FasterRelayLaunchEnabledConfig = fasterRelayLaunchEnabledConfig; SmartRelayDispatchEnabledConfig = smartRelayDispatchEnabledConfig; fasterRelayLaunchChangedHandler = OnFasterRelayLaunchChanged; FasterRelayLaunchEnabledConfig.SettingChanged += fasterRelayLaunchChangedHandler; SetActive(FasterRelayLaunchEnabledConfig.Value); } internal static void Uninit() { if (FasterRelayLaunchEnabledConfig != null && fasterRelayLaunchChangedHandler != null) { FasterRelayLaunchEnabledConfig.SettingChanged -= fasterRelayLaunchChangedHandler; } SetActive(active: false); fasterRelayLaunchChangedHandler = null; FasterRelayLaunchEnabledConfig = null; SmartRelayDispatchEnabledConfig = null; Log = null; } private static void OnFasterRelayLaunchChanged(object sender, EventArgs args) { SetActive(FasterRelayLaunchEnabledConfig != null && FasterRelayLaunchEnabledConfig.Value); } private static void SetActive(bool active) { if (active) { if (harmony == null) { harmony = Harmony.CreateAndPatchAll(typeof(RelayControl), "me.liantian.plugin.HardFog.RelayControl"); ManualLogSource log = Log; if (log != null) { log.LogInfo((object)"RelayControl enabled"); } } } else if (harmony != null) { harmony.UnpatchSelf(); harmony = null; ManualLogSource log2 = Log; if (log2 != null) { log2.LogInfo((object)"RelayControl disabled"); } } } [HarmonyPrefix] [HarmonyPatch(typeof(EnemyDFHiveSystem), "DetermineRelayDemand")] private static bool EnemyDFHiveSystemDetermineRelayDemandPrefix(EnemyDFHiveSystem __instance) { DispatchOneIdleRelayIfAllowed(__instance); return false; } [HarmonyTranspiler] [HarmonyPatch(typeof(EnemyDFHiveSystem), "UpdateMatterStatisticsVirtual")] private static IEnumerable EnemyDFHiveSystemUpdateMatterStatisticsVirtualTranspiler(IEnumerable instructions) { return ReplaceRelayDemandInterval(instructions); } [HarmonyTranspiler] [HarmonyPatch(typeof(EnemyDFHiveSystem), "UpdateMatterStatisticsRealized")] private static IEnumerable EnemyDFHiveSystemUpdateMatterStatisticsRealizedTranspiler(IEnumerable instructions) { return ReplaceRelayDemandInterval(instructions); } [HarmonyPrefix] [HarmonyPatch(typeof(DFRelayComponent), "SearchTargetPlaceProcess")] private static bool DFRelayComponentSearchTargetPlaceProcessPrefix(DFRelayComponent __instance, ref bool __result) { //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) if (__instance == null) { return true; } if (IsMarkerOnlyEnabled()) { if (IsRelayMarkerStillValid(__instance)) { return true; } CancelDockDispatch(__instance); __result = false; return false; } if (__instance.dstMarkerAstroId > 0 || __instance.dstMarkerId > 0 || __instance.searchAstroId != 0) { return true; } EnemyDFHiveSystem hive = __instance.hive; StarData val = hive?.starData; if (val == null) { return true; } int num = CountNonGasPlanets(val); if (num <= 0) { return true; } int pick = RandomTable.Integer(ref hive.rtseed, num); PlanetData val2 = PickNonGasPlanet(val, pick); if (val2 == null) { return true; } __instance.searchAstroId = val2.astroId; __instance.searchBaseId = 0; __instance.searchChance = 5; __instance.searchLPos = Vector3.zero; __instance.searchEntityCursor = 0; __result = false; return false; } private static IEnumerable ReplaceRelayDemandInterval(IEnumerable instructions) { List list = new List(instructions); int num = 0; for (int i = 0; i < list.Count; i++) { if (LoadsInt(list[i], 600)) { list[i].opcode = OpCodes.Ldc_I4; list[i].operand = 120; num++; } } if (num == 0) { ManualLogSource log = Log; if (log != null) { log.LogWarning((object)"Failed to patch relay demand interval."); } } return list; } private static bool LoadsInt(CodeInstruction code, int value) { if (code.opcode == OpCodes.Ldc_I4 && code.operand is int num) { return num == value; } if (code.opcode == OpCodes.Ldc_I4_S && code.operand is sbyte b) { return b == value; } if (code.opcode == OpCodes.Ldc_I4_0) { return value == 0; } if (code.opcode == OpCodes.Ldc_I4_1) { return value == 1; } if (code.opcode == OpCodes.Ldc_I4_2) { return value == 2; } if (code.opcode == OpCodes.Ldc_I4_3) { return value == 3; } if (code.opcode == OpCodes.Ldc_I4_4) { return value == 4; } if (code.opcode == OpCodes.Ldc_I4_5) { return value == 5; } if (code.opcode == OpCodes.Ldc_I4_6) { return value == 6; } if (code.opcode == OpCodes.Ldc_I4_7) { return value == 7; } if (code.opcode == OpCodes.Ldc_I4_8) { return value == 8; } return false; } private static void DispatchOneIdleRelayIfAllowed(EnemyDFHiveSystem hive) { if (hive == null || hive.relays == null || hive.idleRelayCount <= 0 || HasOutgoingRelay(hive)) { return; } if (IsMarkerOnlyEnabled()) { DispatchOneIdleRelayToMarkerIfAllowed(hive); return; } for (int i = 0; i < hive.idleRelayCount; i++) { int num = hive.idleRelayIds[i]; if (num > 0) { DFRelayComponent val = hive.relays.buffer[num]; if (val != null && val.id == num && val.TryDispatchFromHive()) { break; } } } } private static void DispatchOneIdleRelayToMarkerIfAllowed(EnemyDFHiveSystem hive) { if (!TryPickAvailableRelayMarker(hive, out var factory, out var markerId)) { return; } for (int i = 0; i < hive.idleRelayCount; i++) { int num = hive.idleRelayIds[i]; if (num <= 0) { continue; } DFRelayComponent val = hive.relays.buffer[num]; if (val != null && val.id == num && val.TryDispatchFromHive()) { val.SetTargetedMarker(factory, markerId); if (!IsRelayMarkerStillValid(val)) { CancelDockDispatch(val); } break; } } } private static bool TryPickAvailableRelayMarker(EnemyDFHiveSystem hive, out PlanetFactory factory, out int markerId) { factory = null; markerId = 0; int num = CountAvailableRelayMarkers(hive); if (num <= 0) { return false; } int num2 = num; StarData starData = hive.starData; for (int i = 0; i < starData.planetCount; i++) { PlanetData planet = starData.planets[i]; PlanetFactory markerPlanetFactory = GetMarkerPlanetFactory(hive, planet); if (markerPlanetFactory == null) { continue; } ObjectPool markers = markerPlanetFactory.digitalSystem.markers; for (int j = 1; j < markers.cursor; j++) { MarkerComponent val = markers[j]; if (IsAvailableRelayMarker(hive, markerPlanetFactory, val, j)) { float num3 = val.power / (float)num2; if (Random.value < num3) { factory = markerPlanetFactory; markerId = j; return true; } num2--; } } } return false; } private static int CountAvailableRelayMarkers(EnemyDFHiveSystem hive) { int num = 0; StarData starData = hive.starData; for (int i = 0; i < starData.planetCount; i++) { PlanetData planet = starData.planets[i]; PlanetFactory markerPlanetFactory = GetMarkerPlanetFactory(hive, planet); if (markerPlanetFactory == null) { continue; } ObjectPool markers = markerPlanetFactory.digitalSystem.markers; for (int j = 1; j < markers.cursor; j++) { if (IsAvailableRelayMarker(hive, markerPlanetFactory, markers[j], j)) { num++; } } } return num; } private static PlanetFactory GetMarkerPlanetFactory(EnemyDFHiveSystem hive, PlanetData planet) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Invalid comparison between Unknown and I4 if (hive == null || planet == null || (int)planet.type == 5 || planet.star != hive.starData || planet.factory == null || planet.factory.entityCount == 0 || planet.factory.digitalSystem == null) { return null; } return planet.factory; } private static bool IsAvailableRelayMarker(EnemyDFHiveSystem hive, PlanetFactory factory, MarkerComponent marker, int markerId) { if (marker != null && marker.id == markerId && marker.attractsDFRelay) { return !IsMarkerAlreadyTargeted(hive, factory.planet.astroId, markerId); } return false; } private static bool IsMarkerAlreadyTargeted(EnemyDFHiveSystem hive, int astroId, int markerId) { for (EnemyDFHiveSystem val = hive.firstSibling; val != null; val = val.nextSibling) { DFRelayComponent[] buffer = val.relays.buffer; int cursor = val.relays.cursor; for (int i = 1; i < cursor; i++) { DFRelayComponent val2 = buffer[i]; if (val2 != null && val2.id == i && val2.direction > 0 && val2.dstMarkerAstroId == astroId && val2.dstMarkerId == markerId) { return true; } } } return false; } private static bool HasOutgoingRelay(EnemyDFHiveSystem hive) { DFRelayComponent[] buffer = hive.relays.buffer; int cursor = hive.relays.cursor; for (int i = 1; i < cursor; i++) { DFRelayComponent val = buffer[i]; if (val != null && val.id == i && val.direction > 0) { return true; } } return false; } private static bool IsRelayMarkerStillValid(DFRelayComponent relay) { //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Invalid comparison between Unknown and I4 //IL_0114: 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_011f: 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) if (relay.dstMarkerAstroId <= 0 || relay.dstMarkerId <= 0 || relay.hive == null) { return false; } PlanetFactory val = relay.hive.sector.galaxy.astrosFactory[relay.dstMarkerAstroId]; if (val == null || (int)val.planet.type == 5 || val.planet.star != relay.hive.starData || val.digitalSystem == null || relay.dstMarkerId >= val.digitalSystem.markers.cursor) { return false; } MarkerComponent val2 = val.digitalSystem.markers[relay.dstMarkerId]; if (val2 == null || val2.id != relay.dstMarkerId || !val2.attractsDFRelay) { return false; } if (((Vector3)(ref relay.dstMarkerLPos)).sqrMagnitude < (val.planet.realRadius - 2f) * (val.planet.realRadius - 2f)) { return false; } if (val2.entityId <= 0 || val2.entityId >= val.entityPool.Length) { return false; } Vector3 val3 = val.entityPool[val2.entityId].pos - relay.dstMarkerLPos; return ((Vector3)(ref val3)).sqrMagnitude <= 0.25f; } private static void CancelDockDispatch(DFRelayComponent relay) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000d: 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) relay.targetAstroId = 0; relay.targetLPos = Vector3.zero; relay.targetYaw = 0f; relay.baseState = 0; relay.baseId = 0; relay.baseTicks = 0; relay.baseEvolve = default(EvolveData); relay.baseRespawnCD = 0; relay.direction = 0; relay.param0 = 0f; relay.uSpeed = 0f; relay.ResetSearchStates(); relay.ResetTargetedMarker(); } private static bool IsMarkerOnlyEnabled() { if (FasterRelayLaunchEnabledConfig != null && FasterRelayLaunchEnabledConfig.Value && SmartRelayDispatchEnabledConfig != null) { return SmartRelayDispatchEnabledConfig.Value; } return false; } private static int CountNonGasPlanets(StarData starData) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Invalid comparison between Unknown and I4 int num = 0; for (int i = 0; i < starData.planetCount; i++) { PlanetData val = starData.planets[i]; if (val != null && (int)val.type != 5) { num++; } } return num; } private static PlanetData PickNonGasPlanet(StarData starData, int pick) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Invalid comparison between Unknown and I4 for (int i = 0; i < starData.planetCount; i++) { PlanetData val = starData.planets[i]; if (val != null && (int)val.type != 5) { if (pick == 0) { return val; } pick--; } } return null; } } [HarmonyPatch] internal static class FasterResearchControl { private const string PatchGuid = "me.liantian.plugin.HardFog.FasterResearch"; private const int Multiplier = 48; private static ManualLogSource Log; private static Harmony harmony; private static EventHandler settingChangedHandler; internal static ConfigEntry EnabledConfig { get; private set; } internal static void Init(ConfigEntry enabledConfig, ManualLogSource log) { if (EnabledConfig != null && settingChangedHandler != null) { EnabledConfig.SettingChanged -= settingChangedHandler; } Log = log; EnabledConfig = enabledConfig; settingChangedHandler = OnSettingChanged; EnabledConfig.SettingChanged += settingChangedHandler; SetActive(EnabledConfig.Value); } internal static void Uninit() { if (EnabledConfig != null && settingChangedHandler != null) { EnabledConfig.SettingChanged -= settingChangedHandler; } SetActive(active: false); settingChangedHandler = null; EnabledConfig = null; Log = null; } private static void OnSettingChanged(object sender, EventArgs args) { SetActive(EnabledConfig != null && EnabledConfig.Value); } private static void SetActive(bool active) { if (active) { if (harmony == null) { harmony = Harmony.CreateAndPatchAll(typeof(FasterResearchControl), "me.liantian.plugin.HardFog.FasterResearch"); ManualLogSource log = Log; if (log != null) { log.LogInfo((object)("FasterResearch enabled, multiplier = " + 48)); } } SyncCurrentTechHashNeeded(GameMain.history); } else if (harmony != null) { harmony.UnpatchSelf(); harmony = null; ManualLogSource log2 = Log; if (log2 != null) { log2.LogInfo((object)"FasterResearch disabled"); } SyncCurrentTechHashNeeded(GameMain.history); } } [HarmonyPostfix] [HarmonyPatch(typeof(TechProto), "GetHashNeeded")] private static void TechProtoGetHashNeededPostfix(ref long __result) { __result = DivideRoundUp(__result, 48); } [HarmonyPostfix] [HarmonyPatch(typeof(GameHistoryData), "SetForNewGame")] private static void GameHistoryDataSetForNewGamePostfix(GameHistoryData __instance) { SyncCurrentTechHashNeeded(__instance); } [HarmonyPostfix] [HarmonyPatch(typeof(GameHistoryData), "Import")] private static void GameHistoryDataImportPostfix(GameHistoryData __instance, bool isPreview) { if (!isPreview) { SyncCurrentTechHashNeeded(__instance); } } private static long DivideRoundUp(long value, int divisor) { if (value <= 0) { return value; } return (value + divisor - 1) / divisor; } private static void SyncCurrentTechHashNeeded(GameHistoryData history) { //IL_0036: 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_003c: 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_0066: 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_008b: 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) if (history?.techStates == null) { return; } foreach (int item in new List(history.techStates.Keys)) { TechState val = history.techStates[item]; if (val.unlocked) { continue; } TechProto val2 = ((ProtoSet)(object)LDB.techs).Select(item); if (val2 != null) { val.hashNeeded = val2.GetHashNeeded(val.curLevel); if (val.hashUploaded >= val.hashNeeded) { val.hashUploaded = val.hashNeeded - 1; } history.techStates[item] = val; } } } } [HarmonyPatch] internal static class VeinPlacementControl { private sealed class VeinGroupWork { public readonly short GroupIndex; public readonly EVeinType Type; public readonly List VeinIds = new List(); public VeinGroupWork(short groupIndex, EVeinType type) { //IL_0019: 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) GroupIndex = groupIndex; Type = type; } } private const string PatchGuid = "me.liantian.plugin.HardFog.VeinPlacement"; private const int ModSeedSalt = 1448095793; private const float TargetLatitudeDegrees = 40f; private const float TargetLongitudeDegrees = 80f; private const float NormalGroupSpacing = 196f; private const float OilGroupSpacing = 100f; private const float InnerVeinMinDistanceSqr = 0.5f; private const float InnerVeinMaxRadiusSqr = 13f; private const int GroupPlacementAttempts = 24; private const int LongitudeExpansionPasses = 100; private const float LongitudeExpansionStepDegrees = 30f; private const int LocalShapePasses = 20; private const int LocalFallbackAttempts = 8192; private static ManualLogSource Log; private static Harmony harmony; private static EventHandler settingChangedHandler; private static readonly FieldRef PlanetRef = AccessTools.FieldRefAccess("planet"); internal static ConfigEntry EnabledConfig { get; private set; } internal static void Init(ConfigEntry enabledConfig, ManualLogSource log) { if (EnabledConfig != null && settingChangedHandler != null) { EnabledConfig.SettingChanged -= settingChangedHandler; } Log = log; EnabledConfig = enabledConfig; settingChangedHandler = OnSettingChanged; EnabledConfig.SettingChanged += settingChangedHandler; SetActive(EnabledConfig.Value); } internal static void Uninit() { if (EnabledConfig != null && settingChangedHandler != null) { EnabledConfig.SettingChanged -= settingChangedHandler; } SetActive(active: false); settingChangedHandler = null; EnabledConfig = null; Log = null; } private static void OnSettingChanged(object sender, EventArgs args) { SetActive(EnabledConfig != null && EnabledConfig.Value); } private static void SetActive(bool active) { if (active) { if (harmony == null) { harmony = Harmony.CreateAndPatchAll(typeof(VeinPlacementControl), "me.liantian.plugin.HardFog.VeinPlacement"); ManualLogSource log = Log; if (log != null) { log.LogInfo((object)"VeinPlacement enabled"); } } } else if (harmony != null) { harmony.UnpatchSelf(); harmony = null; ManualLogSource log2 = Log; if (log2 != null) { log2.LogInfo((object)"VeinPlacement disabled"); } } } private static void ApplyPlacement(PlanetAlgorithm algorithm) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Invalid comparison between Unknown and I4 //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_0094: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) PlanetData planet = GetPlanet(algorithm); if (planet == null || (int)planet.type == 5 || planet.data == null || planet.data.veinPool == null || planet.data.veinCursor <= 1) { return; } List list = InterleaveGroupsByType(CollectGroups(planet)); if (list.Count == 0) { return; } DotNet35Random rng = CreateRandom(planet); Vector3 birthDirection = EnsureBirthPointDirection(planet); if (((Vector3)(ref birthDirection)).sqrMagnitude < 0.5f) { ManualLogSource log = Log; if (log != null) { log.LogWarning((object)("Unable to read birth point on planet " + (planet.displayName ?? planet.name))); } return; } List list2 = PlaceGroupCenters(planet, list, birthDirection, rng); PlanetRawData data = planet.data; for (int i = 0; i < list.Count; i++) { Vector3 val = list2[i]; if (!(((Vector3)(ref val)).sqrMagnitude < 0.5f)) { RegenerateGroupVeins(planet, data, list[i], list2[i], rng); } } planet.SummarizeVeinGroups(); } private static PlanetData GetPlanet(PlanetAlgorithm algorithm) { if (algorithm == null) { return null; } try { return PlanetRef.Invoke(algorithm); } catch (Exception ex) { ManualLogSource log = Log; if (log != null) { log.LogWarning((object)("Unable to read PlanetAlgorithm.planet: " + ex.Message)); } return null; } } private static DotNet35Random CreateRandom(PlanetData planet) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Expected O, but got Unknown return new DotNet35Random((((planet.seed * 397) ^ planet.id) * 397) ^ planet.algoId ^ 0x56503031); } private static List CollectGroups(PlanetData planet) { //IL_0042: 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) Dictionary dictionary = new Dictionary(); List list = new List(); VeinData[] veinPool = planet.data.veinPool; int veinCursor = planet.data.veinCursor; for (int i = 1; i < veinCursor; i++) { if (veinPool[i].id != i || (int)veinPool[i].type == 0) { continue; } short groupIndex = veinPool[i].groupIndex; if (groupIndex > 0) { if (!dictionary.TryGetValue(groupIndex, out var value)) { value = (dictionary[groupIndex] = new VeinGroupWork(groupIndex, veinPool[i].type)); list.Add(value); } value.VeinIds.Add(i); } } return list; } private static List InterleaveGroupsByType(List groups) { //IL_0020: 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) Dictionary> dictionary = new Dictionary>(); List> list = new List>(); int num = 0; for (int i = 0; i < groups.Count; i++) { VeinGroupWork veinGroupWork = groups[i]; if (!dictionary.TryGetValue(veinGroupWork.Type, out var value)) { value = new List(); dictionary[veinGroupWork.Type] = value; list.Add(value); } value.Add(veinGroupWork); if (value.Count > num) { num = value.Count; } } List list2 = new List(groups.Count); for (int j = 0; j < num; j++) { for (int k = 0; k < list.Count; k++) { if (j < list[k].Count) { list2.Add(list[k][j]); } } } return list2; } private static void Shuffle(IList items, DotNet35Random rng) { for (int num = items.Count - 1; num > 0; num--) { int index = rng.Next(num + 1); T value = items[num]; items[num] = items[index]; items[index] = value; } } private static Vector3 EnsureBirthPointDirection(PlanetData planet) { //IL_0070: 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) if (((Vector3)(ref planet.birthPoint)).sqrMagnitude < 1E-08f) { try { planet.GenBirthPoints(); } catch (Exception ex) { ManualLogSource log = Log; if (log != null) { log.LogWarning((object)("Unable to generate birth point on planet " + (planet.displayName ?? planet.name) + ": " + ex.Message)); } } } if (((Vector3)(ref planet.birthPoint)).sqrMagnitude < 1E-08f) { return Vector3.zero; } return ((Vector3)(ref planet.birthPoint)).normalized; } private static List PlaceGroupCenters(PlanetData planet, List groups, Vector3 birthDirection, DotNet35Random rng) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_002a: 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_0037: 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_0047: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_007d: 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_0055: 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_0064: 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_0093: Unknown result type (might be due to invalid IL or missing references) List list = new List(groups.Count); List list2 = new List(groups.Count); if (groups.Count == 0) { return list; } float centerLongitude = LongitudeFromDirection(birthDirection); list.Add(birthDirection); list2.Add(birthDirection); Vector3 anchor = birthDirection; for (int i = 1; i < groups.Count; i++) { if (TryPlaceGroupCenter(planet, groups[i], anchor, centerLongitude, rng, list2, out var center)) { list.Add(center); list2.Add(center); anchor = center; continue; } list.Add(Vector3.zero); Vector3 originalGroupCenter = GetOriginalGroupCenter(planet, groups[i]); if (((Vector3)(ref originalGroupCenter)).sqrMagnitude > 0.5f) { list2.Add(originalGroupCenter); } } return list; } private static bool TryPlaceGroupCenter(PlanetData planet, VeinGroupWork group, Vector3 anchor, float centerLongitude, DotNet35Random rng, List placedCenters, out Vector3 center) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) float minDistanceSqr = GetMinDistanceSqr(planet, group); float num = Mathf.Sqrt(minDistanceSqr); for (int i = 1; i <= 3; i++) { if (TryPlaceOnDistanceBand(planet, group, anchor, num * (float)i, num * (float)(i + 1), centerLongitude, 80f, rng, placedCenters, minDistanceSqr, out center)) { return true; } } if (TryPlaceRandomInWindow(planet, group, centerLongitude, 80f, rng, placedCenters, minDistanceSqr, out center)) { return true; } for (int j = 1; j <= 100; j++) { float longitudeHalfWidthDegrees = 80f + 30f * (float)j; if (TryPlaceRandomInWindow(planet, group, centerLongitude, longitudeHalfWidthDegrees, rng, placedCenters, minDistanceSqr, out center)) { return true; } } center = Vector3.zero; return false; } private static bool TryPlaceOnDistanceBand(PlanetData planet, VeinGroupWork group, Vector3 anchor, float minDistance, float maxDistance, float centerLongitude, float longitudeHalfWidthDegrees, DotNet35Random rng, List placedCenters, float minDistanceSqr, out Vector3 center) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0034: 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_003c: 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_004e: 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) for (int i = 0; i < 24; i++) { float chordDistance = minDistance + (float)rng.NextDouble() * (maxDistance - minDistance); float angle = (float)(rng.NextDouble() * Math.PI * 2.0); Vector3 val = DirectionAtChordDistance(anchor, chordDistance, angle); if (IsValidCandidate(planet, group, val, centerLongitude, longitudeHalfWidthDegrees, placedCenters, minDistanceSqr)) { center = val; return true; } } center = Vector3.zero; return false; } private static bool TryPlaceRandomInWindow(PlanetData planet, VeinGroupWork group, float centerLongitude, float longitudeHalfWidthDegrees, DotNet35Random rng, List placedCenters, float minDistanceSqr, out Vector3 center) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0010: 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) //IL_003c: 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) for (int i = 0; i < 24; i++) { Vector3 candidate = RandomDirectionInTargetWindow(centerLongitude, longitudeHalfWidthDegrees, rng); if (IsValidCenter(planet, group, candidate, placedCenters, minDistanceSqr)) { center = ((Vector3)(ref candidate)).normalized; return true; } } center = Vector3.zero; return false; } private static Vector3 RandomDirectionInTargetWindow(float centerLongitude, float longitudeHalfWidthDegrees, DotNet35Random rng) { //IL_0051: Unknown result type (might be due to invalid IL or missing references) float latitude = Deg2Rad((float)((rng.NextDouble() * 2.0 - 1.0) * 40.0)); float longitude = centerLongitude + Deg2Rad((float)((rng.NextDouble() * 2.0 - 1.0) * (double)longitudeHalfWidthDegrees)); return DirectionFromLatLon(latitude, longitude); } private static bool IsValidCandidate(PlanetData planet, VeinGroupWork group, Vector3 candidate, float centerLongitude, float longitudeHalfWidthDegrees, List placedCenters, float minDistanceSqr) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) if (!IsInTargetWindow(candidate, centerLongitude, longitudeHalfWidthDegrees)) { return false; } return IsValidCenter(planet, group, candidate, placedCenters, minDistanceSqr); } private static bool IsInTargetWindow(Vector3 candidate, float centerLongitude, float longitudeHalfWidthDegrees) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //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_0021: Unknown result type (might be due to invalid IL or missing references) Vector3 normalized = ((Vector3)(ref candidate)).normalized; if (Mathf.Abs(LatitudeFromDirection(normalized)) > Deg2Rad(40f)) { return false; } return AbsLongitudeDelta(LongitudeFromDirection(normalized), centerLongitude) <= Deg2Rad(longitudeHalfWidthDegrees); } private static bool IsValidCenter(PlanetData planet, VeinGroupWork group, Vector3 candidate, List placedCenters, float minDistanceSqr) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //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_0018: 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) if (!IsValidTerrainCandidate(planet, group, candidate)) { return false; } for (int i = 0; i < placedCenters.Count; i++) { Vector3 val = placedCenters[i] - candidate; if (((Vector3)(ref val)).sqrMagnitude < minDistanceSqr) { return false; } } return true; } private static bool IsValidTerrainCandidate(PlanetData planet, VeinGroupWork group, Vector3 candidate) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) if (IsWaterAllowedVeinGroup(group)) { return true; } return planet.data.QueryHeight(candidate) >= planet.radius; } private static bool IsWaterAllowedVeinGroup(VeinGroupWork group) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Invalid comparison between Unknown and I4 //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Invalid comparison between Unknown and I4 if ((int)group.Type != 7) { return (int)group.Type == 13; } return true; } private static float GetMinDistanceSqr(PlanetData planet, VeinGroupWork group) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Invalid comparison between Unknown and I4 float num = 2.1f / planet.radius; float num2 = (((int)group.Type == 7) ? 100f : 196f); return num * num * num2; } private static Vector3 DirectionAtChordDistance(Vector3 anchor, float chordDistance, float angle) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //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_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: 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_0036: 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) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0040: 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_004c: Unknown result type (might be due to invalid IL or missing references) //IL_004d: 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_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_0063: 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_008f: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: 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_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) Vector3 normalized = ((Vector3)(ref anchor)).normalized; Vector3 val = Vector3.Cross(normalized, Vector3.up); if (((Vector3)(ref val)).sqrMagnitude < 1E-08f) { val = Vector3.Cross(normalized, Vector3.right); } ((Vector3)(ref val)).Normalize(); Vector3 val2 = Vector3.Cross(normalized, val); Vector3 normalized2 = ((Vector3)(ref val2)).normalized; Vector3 val3 = Mathf.Cos(angle) * val + Mathf.Sin(angle) * normalized2; float num = 2f * Mathf.Asin(Mathf.Clamp(chordDistance * 0.5f, 0f, 0.999999f)); val2 = Mathf.Cos(num) * normalized + Mathf.Sin(num) * val3; return ((Vector3)(ref val2)).normalized; } private static Vector3 GetOriginalGroupCenter(PlanetData planet, VeinGroupWork group) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: 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_0072: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) Vector3 val = Vector3.zero; VeinData[] veinPool = planet.data.veinPool; for (int i = 0; i < group.VeinIds.Count; i++) { Vector3 pos = veinPool[group.VeinIds[i]].pos; if (((Vector3)(ref pos)).sqrMagnitude > 1E-08f) { val += ((Vector3)(ref pos)).normalized; } } if (((Vector3)(ref val)).sqrMagnitude < 1E-08f) { return Vector3.zero; } return ((Vector3)(ref val)).normalized; } private static Vector3 DirectionFromLatLon(float latitude, float longitude) { //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_0025: Unknown result type (might be due to invalid IL or missing references) float num = Mathf.Cos(latitude); Vector3 val = new Vector3(Mathf.Cos(longitude) * num, Mathf.Sin(latitude), Mathf.Sin(longitude) * num); return ((Vector3)(ref val)).normalized; } private static float LongitudeFromDirection(Vector3 direction) { //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) return Mathf.Atan2(direction.z, direction.x); } private static float LatitudeFromDirection(Vector3 direction) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) return Mathf.Asin(Mathf.Clamp(direction.y, -1f, 1f)); } private static float AbsLongitudeDelta(float longitude, float centerLongitude) { float num; for (num = longitude - centerLongitude; num > (float)Math.PI; num -= (float)Math.PI * 2f) { } for (; num < -(float)Math.PI; num += (float)Math.PI * 2f) { } return Mathf.Abs(num); } private static float Deg2Rad(float degrees) { return degrees * (float)Math.PI / 180f; } private static void RegenerateGroupVeins(PlanetData planet, PlanetRawData data, VeinGroupWork group, Vector3 center, DotNet35Random rng) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0014: 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_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: 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_002a: 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_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0078: 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_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0088: 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_0095: 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) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Invalid comparison between Unknown and I4 //IL_00c1: 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_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: 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) List list = GenerateLocalOffsets(group, rng); Quaternion val = Quaternion.FromToRotation(Vector3.up, center); Vector3 val2 = val * Vector3.right; Vector3 val3 = val * Vector3.forward; float num = 2.1f / planet.radius; VeinData[] veinPool = data.veinPool; for (int i = 0; i < group.VeinIds.Count; i++) { int num2 = group.VeinIds[i]; VeinData val4 = veinPool[num2]; Vector3 val5 = (list[i].x * val2 + list[i].y * val3) * num; Vector3 val6 = center + val5; if ((int)val4.type == 7 && planet.aux != null) { val6 = planet.aux.RawSnap(val6); } float num3 = data.QueryHeight(val6); data.EraseVegetableAtPoint(val6); val4.pos = ((Vector3)(ref val6)).normalized * num3; veinPool[num2] = val4; } } private static List GenerateLocalOffsets(VeinGroupWork group, DotNet35Random rng) { //IL_0014: 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_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: 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_0087: 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_0096: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) int count = group.VeinIds.Count; List list = new List(count); list.Add(Vector2.zero); int num = 0; Vector2 val2 = default(Vector2); while (num++ < 20 && list.Count < count) { int count2 = list.Count; for (int i = 0; i < count2; i++) { if (list.Count >= count) { break; } Vector2 val = list[i]; if (!(((Vector2)(ref val)).sqrMagnitude > 13f)) { double num2 = rng.NextDouble() * Math.PI * 2.0; ((Vector2)(ref val2))..ctor((float)Math.Cos(num2), (float)Math.Sin(num2)); val2 += list[i] * 0.2f; ((Vector2)(ref val2)).Normalize(); Vector2 val3 = list[i] + val2; if (!(((Vector2)(ref val3)).sqrMagnitude > 13f) && IsValidLocalOffset(val3, list)) { list.Add(val3); } } } } while (list.Count < count) { if (!TryAddFallbackOffset(list, rng)) { ManualLogSource log = Log; if (log != null) { log.LogWarning((object)$"Unable to keep local vein spacing for group {group.GroupIndex}; preserving vein count with relaxed fallback"); } list.Add(RandomFallbackOffset(rng)); } } return list; } private static bool TryAddFallbackOffset(List offsets, DotNet35Random rng) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: 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_0015: Unknown result type (might be due to invalid IL or missing references) for (int i = 0; i < 8192; i++) { Vector2 val = RandomFallbackOffset(rng); if (IsValidLocalOffset(val, offsets)) { offsets.Add(val); return true; } } return false; } private static bool IsValidLocalOffset(Vector2 candidate, List offsets) { //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_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) if (((Vector2)(ref candidate)).sqrMagnitude > 13f) { return false; } for (int i = 0; i < offsets.Count; i++) { Vector2 val = offsets[i] - candidate; if (((Vector2)(ref val)).sqrMagnitude < 0.5f) { return false; } } return true; } private static Vector2 RandomFallbackOffset(DotNet35Random rng) { //IL_003f: Unknown result type (might be due to invalid IL or missing references) float num = Mathf.Sqrt((float)rng.NextDouble() * 13f); float num2 = (float)(rng.NextDouble() * Math.PI * 2.0); return new Vector2(Mathf.Cos(num2) * num, Mathf.Sin(num2) * num); } [HarmonyPostfix] [HarmonyPatch(typeof(PlanetAlgorithm), "GenerateVeins")] private static void PlanetAlgorithmGenerateVeinsPostfix(PlanetAlgorithm __instance) { ApplyPlacement(__instance); } [HarmonyPostfix] [HarmonyPatch(typeof(PlanetAlgorithm0), "GenerateVeins")] private static void PlanetAlgorithm0GenerateVeinsPostfix(PlanetAlgorithm __instance) { ApplyPlacement(__instance); } [HarmonyPostfix] [HarmonyPatch(typeof(PlanetAlgorithm7), "GenerateVeins")] private static void PlanetAlgorithm7GenerateVeinsPostfix(PlanetAlgorithm __instance) { ApplyPlacement(__instance); } [HarmonyPostfix] [HarmonyPatch(typeof(PlanetAlgorithm11), "GenerateVeins")] private static void PlanetAlgorithm11GenerateVeinsPostfix(PlanetAlgorithm __instance) { ApplyPlacement(__instance); } [HarmonyPostfix] [HarmonyPatch(typeof(PlanetAlgorithm12), "GenerateVeins")] private static void PlanetAlgorithm12GenerateVeinsPostfix(PlanetAlgorithm __instance) { ApplyPlacement(__instance); } [HarmonyPostfix] [HarmonyPatch(typeof(PlanetAlgorithm13), "GenerateVeins")] private static void PlanetAlgorithm13GenerateVeinsPostfix(PlanetAlgorithm __instance) { ApplyPlacement(__instance); } } [HarmonyPatch] internal static class OverpoweredMechaFightersControl { private struct SensorRangeState { public bool boosted; public float originalRange; } private struct DamageRatioState { public bool boosted; public float originalRatio; } private struct FleetDescState { public bool boosted; public PrefabDesc desc; public float originalSensorRange; public float originalActiveArea; } private struct FighterBehaviorState { public DamageRatioState damageRatio; public FleetDescState fleetDesc; } private const string PatchGuid = "me.liantian.plugin.HardFog.OverpoweredMechaFighters"; private const float RangeMultiplier = 5f; private const float DamageMultiplier = 5f; private static ManualLogSource Log; private static Harmony harmony; private static EventHandler settingChangedHandler; internal static ConfigEntry EnabledConfig { get; private set; } internal static void Init(ConfigEntry enabledConfig, ManualLogSource log) { if (EnabledConfig != null && settingChangedHandler != null) { EnabledConfig.SettingChanged -= settingChangedHandler; } Log = log; EnabledConfig = enabledConfig; settingChangedHandler = OnSettingChanged; EnabledConfig.SettingChanged += settingChangedHandler; SetActive(EnabledConfig.Value); } internal static void Uninit() { if (EnabledConfig != null && settingChangedHandler != null) { EnabledConfig.SettingChanged -= settingChangedHandler; } SetActive(active: false); settingChangedHandler = null; EnabledConfig = null; Log = null; } private static void OnSettingChanged(object sender, EventArgs args) { SetActive(EnabledConfig != null && EnabledConfig.Value); } private static void SetActive(bool active) { if (active) { if (harmony == null) { harmony = Harmony.CreateAndPatchAll(typeof(OverpoweredMechaFightersControl), "me.liantian.plugin.HardFog.OverpoweredMechaFighters"); SetLoadedMechaFightersInvincible(invincible: true); ManualLogSource log = Log; if (log != null) { log.LogInfo((object)"OverpoweredMechaFighters enabled"); } } } else if (harmony != null) { harmony.UnpatchSelf(); harmony = null; SetLoadedMechaFightersInvincible(invincible: false); ManualLogSource log2 = Log; if (log2 != null) { log2.LogInfo((object)"OverpoweredMechaFighters disabled"); } } } private static bool IsMechaFighter(ref CraftData craft, CraftData[] craftPool) { if (craftPool == null || craft.id <= 0 || craft.owner <= 0 || craft.owner >= craftPool.Length || craft.unitId <= 0) { return false; } ref CraftData reference = ref craftPool[craft.owner]; if (reference.id == craft.owner) { return reference.owner == -1; } return false; } private static bool TryGetMechaFleetDesc(ref CraftData craft, CraftData[] craftPool, out PrefabDesc fleetDesc) { fleetDesc = null; if (!IsMechaFighter(ref craft, craftPool)) { return false; } ref CraftData reference = ref craftPool[craft.owner]; if (reference.modelIndex < 0 || reference.modelIndex >= PlanetFactory.PrefabDescByModelIndex.Length) { return false; } fleetDesc = PlanetFactory.PrefabDescByModelIndex[reference.modelIndex]; return fleetDesc != null; } private static void MakeInvincible(ref CraftData craft, CraftData[] craftPool, SkillSystem skillSystem) { SetInvincible(ref craft, craftPool, skillSystem, invincible: true); } private static void SetInvincible(ref CraftData craft, CraftData[] craftPool, SkillSystem skillSystem, bool invincible) { if (!IsMechaFighter(ref craft, craftPool)) { return; } ((CraftData)(ref craft)).isInvincible = invincible; if (invincible && skillSystem != null && craft.combatStatId > 0) { ref CombatStat reference = ref skillSystem.combatStats.buffer[craft.combatStatId]; if (reference.id == craft.combatStatId) { reference.hp = reference.hpMax; reference.hpIncoming = 0; } } } private static void BoostSensorRange(CombatModuleComponent module, ref SensorRangeState __state) { __state = default(SensorRangeState); if (module != null && module.entityId == 0) { __state.boosted = true; __state.originalRange = module.sensorRange; module.sensorRange *= 5f; } } private static void RestoreSensorRange(CombatModuleComponent module, SensorRangeState state) { if (state.boosted && module != null) { module.sensorRange = state.originalRange; } } private static void BoostDamageForMechaFighter(ref CraftData craft, CraftData[] craftPool, ref CombatUpgradeData combatUpgradeData, ref DamageRatioState __state) { __state = default(DamageRatioState); if (IsMechaFighter(ref craft, craftPool)) { __state.boosted = true; __state.originalRatio = combatUpgradeData.combatDroneDamageRatio; combatUpgradeData.combatDroneDamageRatio *= 5f; } } private static void RestoreDamageRatio(ref CombatUpgradeData combatUpgradeData, DamageRatioState state) { if (state.boosted) { combatUpgradeData.combatDroneDamageRatio = state.originalRatio; } } private static void BoostFleetDesc(PrefabDesc pdesc, ref FleetDescState __state) { __state = default(FleetDescState); if (pdesc != null) { __state.boosted = true; __state.desc = pdesc; __state.originalSensorRange = pdesc.fleetSensorRange; __state.originalActiveArea = pdesc.fleetMaxActiveArea; pdesc.fleetSensorRange *= 5f; pdesc.fleetMaxActiveArea *= 5f; } } private static void BoostFleetDescForMechaFleet(ref CraftData fleetCraft, PrefabDesc pdesc, ref FleetDescState __state) { __state = default(FleetDescState); if (fleetCraft.owner == -1) { BoostFleetDesc(pdesc, ref __state); } } private static void RestoreFleetDesc(FleetDescState state) { if (state.boosted && state.desc != null) { state.desc.fleetSensorRange = state.originalSensorRange; state.desc.fleetMaxActiveArea = state.originalActiveArea; } } private static void BoostFighterBehavior(ref CraftData craft, CraftData[] craftPool, ref CombatUpgradeData combatUpgradeData, ref FighterBehaviorState __state) { __state = default(FighterBehaviorState); BoostDamageForMechaFighter(ref craft, craftPool, ref combatUpgradeData, ref __state.damageRatio); BoostFighterFleetDesc(ref craft, craftPool, ref __state.fleetDesc); } private static void BoostFighterFleetDesc(ref CraftData craft, CraftData[] craftPool, ref FleetDescState __state) { __state = default(FleetDescState); if (TryGetMechaFleetDesc(ref craft, craftPool, out var fleetDesc)) { BoostFleetDesc(fleetDesc, ref __state); } } private static void RestoreFighterBehavior(ref CombatUpgradeData combatUpgradeData, FighterBehaviorState state) { RestoreDamageRatio(ref combatUpgradeData, state.damageRatio); RestoreFleetDesc(state.fleetDesc); } private static void SetLoadedMechaFightersInvincible(bool invincible) { GameData data = GameMain.data; if (data?.factories != null) { for (int i = 0; i < data.factories.Length; i++) { RefreshGroundMechaFighters(data.factories[i]?.combatGroundSystem, invincible); } } RefreshSpaceMechaFighters(GameMain.spaceSector?.combatSpaceSystem, invincible); } private static void RefreshGroundMechaFighters(CombatGroundSystem combatSystem) { RefreshGroundMechaFighters(combatSystem, invincible: true); } private static void RefreshGroundMechaFighters(CombatGroundSystem combatSystem, bool invincible) { if (combatSystem?.factory?.craftPool == null || combatSystem.units == null) { return; } CraftData[] craftPool = combatSystem.factory.craftPool; UnitComponent[] buffer = combatSystem.units.buffer; int cursor = combatSystem.units.cursor; for (int i = 1; i < cursor; i++) { ref UnitComponent reference = ref buffer[i]; if (reference.id == i && reference.craftId > 0) { SetInvincible(ref craftPool[reference.craftId], craftPool, combatSystem.factory.skillSystem, invincible); } } } private static void RefreshSpaceMechaFighters(CombatSpaceSystem combatSystem) { RefreshSpaceMechaFighters(combatSystem, invincible: true); } private static void RefreshSpaceMechaFighters(CombatSpaceSystem combatSystem, bool invincible) { if (combatSystem?.spaceSector?.craftPool == null || combatSystem.units == null) { return; } CraftData[] craftPool = combatSystem.spaceSector.craftPool; UnitComponent[] buffer = combatSystem.units.buffer; int cursor = combatSystem.units.cursor; for (int i = 1; i < cursor; i++) { ref UnitComponent reference = ref buffer[i]; if (reference.id == i && reference.craftId > 0) { SetInvincible(ref craftPool[reference.craftId], craftPool, combatSystem.spaceSector.skillSystem, invincible); } } } [HarmonyPostfix] [HarmonyPatch(typeof(CombatGroundSystem), "NewUnitComponent")] private static void CombatGroundSystemNewUnitComponentPostfix(CombatGroundSystem __instance, int craftId) { if (__instance?.factory?.craftPool != null && craftId > 0 && craftId < __instance.factory.craftPool.Length) { MakeInvincible(ref __instance.factory.craftPool[craftId], __instance.factory.craftPool, __instance.factory.skillSystem); } } [HarmonyPostfix] [HarmonyPatch(typeof(CombatSpaceSystem), "NewUnitComponent")] private static void CombatSpaceSystemNewUnitComponentPostfix(CombatSpaceSystem __instance, int craftId) { if (__instance?.spaceSector?.craftPool != null && craftId > 0 && craftId < __instance.spaceSector.craftPool.Length) { MakeInvincible(ref __instance.spaceSector.craftPool[craftId], __instance.spaceSector.craftPool, __instance.spaceSector.skillSystem); } } [HarmonyPostfix] [HarmonyPatch(typeof(CombatGroundSystem), "GameTick")] private static void CombatGroundSystemGameTickPostfix(CombatGroundSystem __instance, long tick) { if (tick % 60 == 0L) { RefreshGroundMechaFighters(__instance); } } [HarmonyPostfix] [HarmonyPatch(typeof(CombatSpaceSystem), "GameTick")] private static void CombatSpaceSystemGameTickPostfix(CombatSpaceSystem __instance, long tick) { if (tick % 60 == 0L) { RefreshSpaceMechaFighters(__instance); } } [HarmonyPrefix] [HarmonyPatch(typeof(CombatModuleComponent), "DiscoverLocalEnemy")] private static void CombatModuleComponentDiscoverLocalEnemyPrefix(CombatModuleComponent __instance, ref SensorRangeState __state) { BoostSensorRange(__instance, ref __state); } [HarmonyPostfix] [HarmonyPatch(typeof(CombatModuleComponent), "DiscoverLocalEnemy")] private static void CombatModuleComponentDiscoverLocalEnemyPostfix(CombatModuleComponent __instance, SensorRangeState __state) { RestoreSensorRange(__instance, __state); } [HarmonyPrefix] [HarmonyPatch(typeof(CombatModuleComponent), "DiscoverSpaceEnemy")] private static void CombatModuleComponentDiscoverSpaceEnemyPrefix(CombatModuleComponent __instance, ref SensorRangeState __state) { BoostSensorRange(__instance, ref __state); } [HarmonyPostfix] [HarmonyPatch(typeof(CombatModuleComponent), "DiscoverSpaceEnemy")] private static void CombatModuleComponentDiscoverSpaceEnemyPostfix(CombatModuleComponent __instance, SensorRangeState __state) { RestoreSensorRange(__instance, __state); } [HarmonyPrefix] [HarmonyPatch(typeof(FleetComponent), "SensorLogic_Ground")] private static void FleetComponentSensorLogicGroundPrefix(ref CraftData craft, PrefabDesc pdesc, ref FleetDescState __state) { BoostFleetDescForMechaFleet(ref craft, pdesc, ref __state); } [HarmonyFinalizer] [HarmonyPatch(typeof(FleetComponent), "SensorLogic_Ground")] private static void FleetComponentSensorLogicGroundFinalizer(PrefabDesc pdesc, FleetDescState __state) { RestoreFleetDesc(__state); } [HarmonyPrefix] [HarmonyPatch(typeof(FleetComponent), "SensorLogic_Space")] private static void FleetComponentSensorLogicSpacePrefix(ref CraftData craft, PrefabDesc pdesc, ref FleetDescState __state) { BoostFleetDescForMechaFleet(ref craft, pdesc, ref __state); } [HarmonyFinalizer] [HarmonyPatch(typeof(FleetComponent), "SensorLogic_Space")] private static void FleetComponentSensorLogicSpaceFinalizer(PrefabDesc pdesc, FleetDescState __state) { RestoreFleetDesc(__state); } [HarmonyPrefix] [HarmonyPatch(typeof(FleetComponent), "ActiveEnemyUnits_Ground")] private static void FleetComponentActiveEnemyUnitsGroundPrefix(FleetComponent __instance, PlanetFactory factory, PrefabDesc pdesc, ref FleetDescState __state) { //IL_0015: 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_0035: Unknown result type (might be due to invalid IL or missing references) __state = default(FleetDescState); if (factory?.craftPool != null && __instance.craftId > 0 && __instance.craftId < factory.craftPool.Length) { BoostFleetDescForMechaFleet(ref factory.craftPool[__instance.craftId], pdesc, ref __state); } } [HarmonyFinalizer] [HarmonyPatch(typeof(FleetComponent), "ActiveEnemyUnits_Ground")] private static void FleetComponentActiveEnemyUnitsGroundFinalizer(PrefabDesc pdesc, FleetDescState __state) { RestoreFleetDesc(__state); } [HarmonyPrefix] [HarmonyPatch(typeof(FleetComponent), "ActiveEnemyUnits_Space")] private static void FleetComponentActiveEnemyUnitsSpacePrefix(FleetComponent __instance, SpaceSector sector, PrefabDesc pdesc, ref FleetDescState __state) { //IL_0015: 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_0035: Unknown result type (might be due to invalid IL or missing references) __state = default(FleetDescState); if (sector?.craftPool != null && __instance.craftId > 0 && __instance.craftId < sector.craftPool.Length) { BoostFleetDescForMechaFleet(ref sector.craftPool[__instance.craftId], pdesc, ref __state); } } [HarmonyFinalizer] [HarmonyPatch(typeof(FleetComponent), "ActiveEnemyUnits_Space")] private static void FleetComponentActiveEnemyUnitsSpaceFinalizer(PrefabDesc pdesc, FleetDescState __state) { RestoreFleetDesc(__state); } [HarmonyPrefix] [HarmonyPatch(typeof(UnitComponent), "PostGameTick_Ground")] private static void UnitComponentPostGameTickGroundPrefix(PlanetFactory factory, ref CraftData craft, ref FleetDescState __state) { BoostFighterFleetDesc(ref craft, factory?.craftPool, ref __state); } [HarmonyFinalizer] [HarmonyPatch(typeof(UnitComponent), "PostGameTick_Ground")] private static void UnitComponentPostGameTickGroundFinalizer(FleetDescState __state) { RestoreFleetDesc(__state); } [HarmonyPrefix] [HarmonyPatch(typeof(UnitComponent), "PostGameTick_Space")] private static void UnitComponentPostGameTickSpacePrefix(SpaceSector sector, ref CraftData craft, ref FleetDescState __state) { BoostFighterFleetDesc(ref craft, sector?.craftPool, ref __state); } [HarmonyFinalizer] [HarmonyPatch(typeof(UnitComponent), "PostGameTick_Space")] private static void UnitComponentPostGameTickSpaceFinalizer(FleetDescState __state) { RestoreFleetDesc(__state); } [HarmonyPrefix] [HarmonyPatch(typeof(UnitComponent), "RunBehavior_Engage_AttackLaser_Ground")] private static void UnitComponentAttackLaserGroundPrefix(PlanetFactory factory, ref CraftData craft, ref CombatUpgradeData combatUpgradeData, ref FighterBehaviorState __state) { BoostFighterBehavior(ref craft, factory?.craftPool, ref combatUpgradeData, ref __state); } [HarmonyFinalizer] [HarmonyPatch(typeof(UnitComponent), "RunBehavior_Engage_AttackLaser_Ground")] private static void UnitComponentAttackLaserGroundFinalizer(ref CombatUpgradeData combatUpgradeData, FighterBehaviorState __state) { RestoreFighterBehavior(ref combatUpgradeData, __state); } [HarmonyPrefix] [HarmonyPatch(typeof(UnitComponent), "RunBehavior_Engage_AttackPlasma_Ground")] private static void UnitComponentAttackPlasmaGroundPrefix(PlanetFactory factory, ref CraftData craft, ref CombatUpgradeData combatUpgradeData, ref FighterBehaviorState __state) { BoostFighterBehavior(ref craft, factory?.craftPool, ref combatUpgradeData, ref __state); } [HarmonyFinalizer] [HarmonyPatch(typeof(UnitComponent), "RunBehavior_Engage_AttackPlasma_Ground")] private static void UnitComponentAttackPlasmaGroundFinalizer(ref CombatUpgradeData combatUpgradeData, FighterBehaviorState __state) { RestoreFighterBehavior(ref combatUpgradeData, __state); } [HarmonyPrefix] [HarmonyPatch(typeof(UnitComponent), "RunBehavior_Engage_DefenseShield_Ground")] private static void UnitComponentDefenseShieldGroundPrefix(PlanetFactory factory, ref CraftData craft, ref CombatUpgradeData combatUpgradeData, ref FighterBehaviorState __state) { BoostFighterBehavior(ref craft, factory?.craftPool, ref combatUpgradeData, ref __state); } [HarmonyFinalizer] [HarmonyPatch(typeof(UnitComponent), "RunBehavior_Engage_DefenseShield_Ground")] private static void UnitComponentDefenseShieldGroundFinalizer(ref CombatUpgradeData combatUpgradeData, FighterBehaviorState __state) { RestoreFighterBehavior(ref combatUpgradeData, __state); } [HarmonyPrefix] [HarmonyPatch(typeof(UnitComponent), "RunBehavior_Engage_SAttackLaser_Large")] private static void UnitComponentSAttackLaserLargePrefix(SpaceSector sector, ref CraftData craft, ref CombatUpgradeData combatUpgradeData, ref FighterBehaviorState __state) { BoostFighterBehavior(ref craft, sector?.craftPool, ref combatUpgradeData, ref __state); } [HarmonyFinalizer] [HarmonyPatch(typeof(UnitComponent), "RunBehavior_Engage_SAttackLaser_Large")] private static void UnitComponentSAttackLaserLargeFinalizer(ref CombatUpgradeData combatUpgradeData, FighterBehaviorState __state) { RestoreFighterBehavior(ref combatUpgradeData, __state); } [HarmonyPrefix] [HarmonyPatch(typeof(UnitComponent), "RunBehavior_Engage_SAttackPlasma_Small")] private static void UnitComponentSAttackPlasmaSmallPrefix(SpaceSector sector, ref CraftData craft, ref CombatUpgradeData combatUpgradeData, ref FighterBehaviorState __state) { BoostFighterBehavior(ref craft, sector?.craftPool, ref combatUpgradeData, ref __state); } [HarmonyFinalizer] [HarmonyPatch(typeof(UnitComponent), "RunBehavior_Engage_SAttackPlasma_Small")] private static void UnitComponentSAttackPlasmaSmallFinalizer(ref CombatUpgradeData combatUpgradeData, FighterBehaviorState __state) { RestoreFighterBehavior(ref combatUpgradeData, __state); } }