using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using UnityEngine;
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: CompilationRelaxations(8)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace DarkFogDirector;
[BepInPlugin("dsp.darkfog.director", "Dark Fog Expansion Director", "0.4.1")]
public sealed class DarkFogDirectorPlugin : BaseUnityPlugin
{
public const string PluginGuid = "dsp.darkfog.director";
public const string PluginName = "Dark Fog Expansion Director";
public const string PluginVersion = "0.4.1";
internal static DarkFogDirectorPlugin Instance;
internal static ManualLogSource Log;
internal static ConfigEntry<KeyboardShortcut> ReloadKey;
internal static ConfigEntry<KeyboardShortcut> DumpKey;
internal static ConfigEntry<int> ForceCooldownTicks;
internal static ConfigEntry<bool> Verbose;
internal static string OrdersPath;
internal static string DumpPath;
private Harmony _harmony;
private void Awake()
{
//IL_002c: 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_00f0: Unknown result type (might be due to invalid IL or missing references)
//IL_00fa: Expected O, but got Unknown
Instance = this;
Log = ((BaseUnityPlugin)this).Logger;
ReloadKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Hotkeys", "Reload", new KeyboardShortcut((KeyCode)291, (KeyCode[])(object)new KeyCode[0]), "重新载入指令文件。");
DumpKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Hotkeys", "Dump", new KeyboardShortcut((KeyCode)290, (KeyCode[])(object)new KeyCode[0]), "把当前星系/巢穴清单写入日志与文件,方便编写指令。");
ForceCooldownTicks = ((BaseUnityPlugin)this).Config.Bind<int>("Behaviour", "ForceLaunchCooldownTicks", 1800, "同一巢穴两次「强制起飞」之间的最小间隔(游戏 tick,60 tick ≈ 1 秒)。");
Verbose = ((BaseUnityPlugin)this).Config.Bind<bool>("Behaviour", "VerboseLog", false, "每次改写目标时输出详细日志。");
OrdersPath = Path.Combine(Paths.ConfigPath, "DarkFogDirector.orders.txt");
DumpPath = Path.Combine(Paths.ConfigPath, "DarkFogDirector.dump.txt");
Director.Rules.Load(OrdersPath);
_harmony = new Harmony("dsp.darkfog.director");
try
{
_harmony.PatchAll(typeof(DarkFogDirectorPlugin).Assembly);
LogInfo("Harmony 补丁已应用:Dark Fog Expansion Director 0.4.1");
}
catch (Exception ex)
{
LogError("Harmony 补丁失败:" + ex);
}
}
private void OnDestroy()
{
if (_harmony != null)
{
try
{
_harmony.UnpatchSelf();
}
catch
{
}
}
}
private void Update()
{
//IL_0013: Unknown result type (might be due to invalid IL or missing references)
//IL_0018: Unknown result type (might be due to invalid IL or missing references)
//IL_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)
try
{
if (Input.GetKeyDown((KeyCode)92))
{
DirectorPanel.Toggle();
}
KeyboardShortcut value = ReloadKey.Value;
if (((KeyboardShortcut)(ref value)).IsDown())
{
Director.Rules.Load(OrdersPath);
LogInfo("指令已重新载入。");
}
KeyboardShortcut value2 = DumpKey.Value;
if (((KeyboardShortcut)(ref value2)).IsDown())
{
DumpNow();
}
}
catch (Exception ex)
{
LogError("热键处理失败:" + ex.Message);
}
}
private void OnGUI()
{
DirectorPanel.OnGUI();
}
private static void DumpNow()
{
string text;
try
{
SpaceSector sector = GameMain.data?.spaceSector;
text = Director.BuildDump(sector);
}
catch (Exception ex)
{
text = "读取现场失败:" + ex.Message;
}
LogInfo("\n" + text);
try
{
File.WriteAllText(DumpPath, text, Encoding.UTF8);
LogInfo("清单已写入:" + DumpPath);
}
catch (Exception ex2)
{
LogWarn("写出清单失败:" + ex2.Message);
}
}
internal static void LogInfo(string msg)
{
if (Log != null)
{
Log.LogInfo((object)msg);
}
}
internal static void LogWarn(string msg)
{
if (Log != null)
{
Log.LogWarning((object)msg);
}
}
internal static void LogError(string msg)
{
if (Log != null)
{
Log.LogError((object)msg);
}
}
internal static void LogDebug(string msg)
{
if (Log != null && Verbose != null && Verbose.Value)
{
Log.LogInfo((object)msg);
}
}
}
[HarmonyPatch(typeof(DFTinderComponent), "GenerateSortedStarIndices")]
internal static class Patch_GenerateSortedStarIndices
{
[HarmonyPostfix]
internal static void Postfix(ref DFTinderComponent __instance, SpaceSector sector)
{
try
{
Director.OnStarIndicesGenerated(ref __instance, sector);
}
catch (Exception ex)
{
DarkFogDirectorPlugin.LogError("定向补丁异常(已忽略本次):" + ex);
}
}
}
[HarmonyPatch(typeof(DFTinderComponent), "PrepareDispatchLogic")]
internal static class Patch_PrepareDispatchLogic
{
[HarmonyPrefix]
internal static bool Prefix(ref DFTinderComponent __instance, EnemyDFHiveSystem hive)
{
try
{
if (LaunchOrders.TryConsume(ref __instance, hive))
{
return false;
}
int cooldownTicks = ((DarkFogDirectorPlugin.ForceCooldownTicks != null) ? DarkFogDirectorPlugin.ForceCooldownTicks.Value : 1800);
return !Director.TryForceLaunch(ref __instance, hive, cooldownTicks);
}
catch (Exception ex)
{
DarkFogDirectorPlugin.LogError("强制起飞补丁异常(已交还原版):" + ex);
return true;
}
}
}
internal static class Director
{
internal const int AstroBase = 1000000;
internal const int OrbitsPerStar = 8;
internal static readonly RuleBook Rules = new RuleBook();
private static readonly Dictionary<int, int> ForceClock = new Dictionary<int, int>();
internal static int ToStarIndex(int hiveAstroId)
{
return (hiveAstroId - 1000000 - 1) / 8;
}
internal static int ToOrbit(int hiveAstroId)
{
return (hiveAstroId - 1000000 - 1) % 8;
}
internal static int ToAstroId(int starIndex, int orbit)
{
return 1000000 + starIndex * 8 + orbit + 1;
}
internal static void OnStarIndicesGenerated(ref DFTinderComponent tinder, SpaceSector sector)
{
if (sector == null || sector.galaxy == null || tinder.originHiveAstroId <= 0)
{
return;
}
EnemyDFHiveSystem hiveByAstroId = sector.GetHiveByAstroId(tinder.originHiveAstroId);
if (hiveByAstroId != null && hiveByAstroId.starData != null)
{
Rules.EnsureResolved(sector.galaxy);
Rule rule = Rules.Match(hiveByAstroId.starData.index, hiveByAstroId.hiveOrbitIndex);
if (rule != null)
{
ApplyTarget(ref tinder, sector, hiveByAstroId, rule);
}
}
}
private static void ApplyTarget(ref DFTinderComponent tinder, SpaceSector sector, EnemyDFHiveSystem origin, Rule rule)
{
int targetStar = rule.TargetStar;
StarData[] stars = sector.galaxy.stars;
if (targetStar < 0 || targetStar >= stars.Length)
{
DarkFogDirectorPlugin.LogWarn("规则目标星系越界,已忽略:" + rule);
return;
}
int[] starBlankOrbitCount = tinder.starBlankOrbitCount;
int[] sortedStarIndices = tinder.sortedStarIndices;
int[] starValues = tinder.starValues;
if (starBlankOrbitCount == null || sortedStarIndices == null || starValues == null || sortedStarIndices.Length != starValues.Length || targetStar >= starBlankOrbitCount.Length)
{
return;
}
int num = sortedStarIndices.Length;
if (num == 0)
{
return;
}
if (starBlankOrbitCount[targetStar] <= 0)
{
DarkFogDirectorPlugin.LogInfo($"目标星系 {Describe(sector, targetStar)} 已无空余巢穴轨道,本次沿用原版目标。");
return;
}
sortedStarIndices[0] = targetStar;
starValues[0] = 200000;
for (int i = 1; i < num; i++)
{
starValues[i] = starValues[i - 1] + 1;
}
DarkFogDirectorPlugin.LogDebug($"火种 {tinder.id}:源巢穴 {origin.hiveAstroId}(星系 {origin.starData.index} 轨道 {origin.hiveOrbitIndex})-> 目标 {Describe(sector, targetStar)}");
}
internal static bool TryForceLaunch(ref DFTinderComponent tinder, EnemyDFHiveSystem hive, int cooldownTicks)
{
if (hive == null || hive.sector == null || hive.sector.galaxy == null)
{
return false;
}
if (hive.starData == null)
{
return false;
}
Rules.EnsureResolved(hive.sector.galaxy);
Rule rule = Rules.Match(hive.starData.index, hive.hiveOrbitIndex);
if (rule == null || !rule.Force)
{
return false;
}
DataPool<DFTinderComponent> tinders = hive.tinders;
if (tinders == null || tinders.buffer == null)
{
return false;
}
int num = -1;
for (int i = 1; i < tinders.cursor; i++)
{
if (tinders.buffer[i].id == tinder.id)
{
num = i;
break;
}
}
if (num < 0)
{
return false;
}
if (!IsTinderLoaded(hive, num))
{
return false;
}
if (ForceClock.TryGetValue(hive.hiveAstroId, out var value) && hive.ticks - value < cooldownTicks)
{
return false;
}
int num2 = EnsureHiveInStar(hive.sector, rule.TargetStar);
if (num2 <= 0)
{
return false;
}
((DFTinderComponent)(ref tinders.buffer[num])).DispatchFromHive(hive.sector, num2);
ForceClock[hive.hiveAstroId] = hive.ticks;
DarkFogDirectorPlugin.LogInfo($"强制发射:巢穴 {hive.hiveAstroId} -> {Describe(hive.sector, rule.TargetStar)}(目标 astroId {num2})");
return true;
}
private static bool IsTinderLoaded(EnemyDFHiveSystem hive, int slot)
{
//IL_0048: 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)
int builderId = hive.tinders.buffer[slot].builderId;
if (builderId <= 0)
{
return false;
}
DataPool<EnemyBuilderComponent> builders = hive.builders;
if (builders == null || builders.buffer == null)
{
return false;
}
if (builderId >= builders.cursor)
{
return false;
}
EnemyBuilderComponent val = builders.buffer[builderId];
if (val.matter >= val.maxMatter)
{
return val.energy >= val.maxEnergy;
}
return false;
}
internal static int EnsureHiveInStar(SpaceSector sector, int starIndex)
{
if (sector == null || sector.galaxy == null)
{
return -1;
}
if (starIndex < 0 || starIndex >= sector.galaxy.stars.Length)
{
return -1;
}
EnemyDFHiveSystem val = sector.dfHives[starIndex];
if (val != null)
{
EnemyDFHiveSystem val2 = val;
EnemyDFHiveSystem val3 = val;
while (val2 != null)
{
val3 = val2;
val2 = val2.nextSibling;
}
return val3.hiveAstroId;
}
return sector.TryCreateNewHive(sector.galaxy.stars[starIndex])?.hiveAstroId ?? (-1);
}
internal static string Describe(SpaceSector sector, int starIndex)
{
if (sector == null || sector.galaxy == null)
{
return "#" + starIndex;
}
StarData[] stars = sector.galaxy.stars;
if (starIndex < 0 || starIndex >= stars.Length)
{
return "#" + starIndex;
}
StarData val = stars[starIndex];
string arg = (string.IsNullOrEmpty(val.displayName) ? val.name : val.displayName);
return $"{arg}(#{starIndex})";
}
internal static string BuildDump(SpaceSector sector)
{
//IL_0095: Unknown result type (might be due to invalid IL or missing references)
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.AppendLine("# DarkFogDirector 现场快照");
if (sector == null || sector.galaxy == null)
{
stringBuilder.AppendLine("(未进入游戏,无法读取星图)");
return stringBuilder.ToString();
}
StarData[] stars = sector.galaxy.stars;
stringBuilder.AppendLine("# 星系清单:索引 | 名称 | 类型 | 已建巢穴数");
for (int i = 0; i < stars.Length; i++)
{
int num = 0;
for (EnemyDFHiveSystem val = sector.dfHives[i]; val != null; val = val.nextSibling)
{
num++;
}
stringBuilder.AppendLine($"{i} | {stars[i].displayName} | {stars[i].type} | {num}");
}
stringBuilder.AppendLine();
stringBuilder.AppendLine("# 巢穴清单:astroId | 星系索引 | 轨道 | 已实体化");
for (int j = 0; j < sector.dfHives.Length; j++)
{
for (EnemyDFHiveSystem val2 = sector.dfHives[j]; val2 != null; val2 = val2.nextSibling)
{
stringBuilder.AppendLine($"{val2.hiveAstroId} | {j} | {val2.hiveOrbitIndex} | {val2.realized}");
}
}
stringBuilder.AppendLine();
stringBuilder.AppendLine("# 规则写法: 源 => 目标 源可为 星系索引 / 星系名 / 星系索引:轨道");
stringBuilder.AppendLine("# 目标后加 ! 表示允许强制起飞");
return stringBuilder.ToString();
}
}
internal sealed class LaunchOrder
{
public int SourceHiveAstroId;
public int TargetStar;
}
internal static class LaunchOrders
{
private delegate bool TinderVisitor(int slot, DFTinderComponent tinder);
internal const int OrbitsPerStar = 8;
internal const int TinderIdleStage = 254;
internal const int TinderSailingStage = 0;
private static readonly Dictionary<int, LaunchOrder> _pending = new Dictionary<int, LaunchOrder>();
internal static int PendingCount => _pending.Count;
internal static bool HasPending(int hiveAstroId)
{
return _pending.ContainsKey(hiveAstroId);
}
internal static string CancelPending(int hiveAstroId)
{
if (!_pending.Remove(hiveAstroId))
{
return L.T("cancel_none");
}
return L.T("cancel_ok");
}
internal static int OrbitCapacity(StarData star)
{
//IL_0011: Unknown result type (might be due to invalid IL or missing references)
//IL_0017: Invalid comparison between Unknown and I4
//IL_001a: Unknown result type (might be due to invalid IL or missing references)
//IL_0020: Invalid comparison between Unknown and I4
if (star == null)
{
return 0;
}
int num = star.maxHiveCount;
if (num <= 0)
{
num = (((int)star.type == 4 || (int)star.type == 3) ? 6 : 3);
}
if (num > 8)
{
num = 8;
}
return num;
}
internal static int HiveCountInStar(SpaceSector sector, int starIndex)
{
if (sector == null || sector.dfHives == null)
{
return 0;
}
if (starIndex < 0 || starIndex >= sector.dfHives.Length)
{
return 0;
}
int num = 0;
for (EnemyDFHiveSystem val = sector.dfHives[starIndex]; val != null; val = val.nextSibling)
{
num++;
}
return num;
}
internal static int FreeOrbits(SpaceSector sector, int starIndex)
{
if (sector == null || sector.galaxy == null)
{
return 0;
}
StarData[] stars = sector.galaxy.stars;
if (starIndex < 0 || starIndex >= stars.Length)
{
return 0;
}
int num = OrbitCapacity(stars[starIndex]) - HiveCountInStar(sector, starIndex);
if (num >= 0)
{
return num;
}
return 0;
}
internal static int CountTinders(EnemyDFHiveSystem hive)
{
int n = 0;
EachTinder(hive, delegate
{
n++;
return true;
});
return n;
}
internal static int CountReadyTinders(EnemyDFHiveSystem hive)
{
int n = 0;
EachTinder(hive, delegate(int slot, DFTinderComponent t)
{
if (t.stage == 254 && t.targetHiveAstroId == 0 && t.direction == 0)
{
n++;
}
return true;
});
return n;
}
private static void EachTinder(EnemyDFHiveSystem hive, TinderVisitor visit)
{
//IL_0046: Unknown result type (might be due to invalid IL or missing references)
//IL_004b: 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)
if (hive == null || hive.tinders == null || hive.tinders.buffer == null)
{
return;
}
DFTinderComponent[] buffer = hive.tinders.buffer;
int num = hive.tinders.cursor;
if (num > buffer.Length)
{
num = buffer.Length;
}
for (int i = 1; i < num; i++)
{
DFTinderComponent tinder = buffer[i];
if (tinder.id == i && !visit(i, tinder))
{
break;
}
}
}
private static int FindIdleSlot(EnemyDFHiveSystem hive)
{
//IL_0047: 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)
if (hive == null || hive.tinders == null || hive.tinders.buffer == null)
{
return -1;
}
DFTinderComponent[] buffer = hive.tinders.buffer;
int num = hive.tinders.cursor;
if (num > buffer.Length)
{
num = buffer.Length;
}
for (int i = 1; i < num; i++)
{
DFTinderComponent val = buffer[i];
if (val.id == i && val.stage == 254 && val.targetHiveAstroId == 0 && val.direction == 0)
{
return i;
}
}
return -1;
}
private static int FindSlot(EnemyDFHiveSystem hive, int tinderId)
{
if (hive == null || hive.tinders == null || hive.tinders.buffer == null)
{
return -1;
}
DFTinderComponent[] buffer = hive.tinders.buffer;
int num = hive.tinders.cursor;
if (num > buffer.Length)
{
num = buffer.Length;
}
for (int i = 1; i < num; i++)
{
if (buffer[i].id == tinderId)
{
return i;
}
}
return -1;
}
internal static bool FillResources(EnemyDFHiveSystem hive, int builderId)
{
//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_009a: 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)
DataPool<EnemyBuilderComponent> val = hive?.builders;
if (val == null || val.buffer == null)
{
return false;
}
if (builderId <= 0 || builderId >= val.cursor || builderId >= val.buffer.Length)
{
return false;
}
EnemyBuilderComponent val2 = val.buffer[builderId];
if (val2.maxMatter > 0)
{
val2.matter = val2.maxMatter;
}
if (val2.maxEnergy > 0)
{
val2.energy = val2.maxEnergy;
}
if (val2.spMax > 0)
{
val2.sp = val2.spMax;
}
val.buffer[builderId] = val2;
return true;
}
internal static string RequestLaunch(SpaceSector sector, int hiveAstroId, int targetStar)
{
if (sector == null || sector.galaxy == null)
{
return L.T("lg_not_in_game");
}
EnemyDFHiveSystem hiveByAstroId = sector.GetHiveByAstroId(hiveAstroId);
if (hiveByAstroId == null)
{
return L.T("lg_hive_gone");
}
if (FreeOrbits(sector, targetStar) <= 0)
{
return L.T("lg_cap_full", Director.Describe(sector, targetStar));
}
int num = FindIdleSlot(hiveByAstroId);
if (num >= 0)
{
return DispatchSlot(sector, hiveByAstroId, num, targetStar, L.T("how_filled"));
}
int num2 = SpawnTinderNow(hiveByAstroId);
if (num2 >= 0)
{
return DispatchSlot(sector, hiveByAstroId, num2, targetStar, L.T("how_spawned"));
}
DarkFogDirectorPlugin.LogWarn($"hive {hiveByAstroId.hiveAstroId}: cannot launch now (realized={hiveByAstroId.realized} tinderDocks={((hiveByAstroId.tinderDocks != null) ? hiveByAstroId.tinderDocks.Length : (-1))} tinders.cursor={((hiveByAstroId.tinders != null) ? hiveByAstroId.tinders.cursor : (-1))} proto={8119})");
LaunchOrder launchOrder = new LaunchOrder();
launchOrder.SourceHiveAstroId = hiveAstroId;
launchOrder.TargetStar = targetStar;
_pending[hiveAstroId] = launchOrder;
return L.T("lg_pending", DescribeHive(hiveByAstroId), Director.Describe(sector, targetStar));
}
internal static bool TryConsume(ref DFTinderComponent tinder, EnemyDFHiveSystem hive)
{
if (_pending.Count == 0)
{
return false;
}
if (hive == null || hive.sector == null)
{
return false;
}
if (!_pending.TryGetValue(hive.hiveAstroId, out var value))
{
return false;
}
int num = FindSlot(hive, tinder.id);
if (num < 0)
{
return false;
}
int num2 = CreateHiveInStar(hive.sector, value.TargetStar);
if (num2 <= 0)
{
_pending.Remove(hive.hiveAstroId);
DarkFogDirectorPlugin.LogWarn($"queued order dropped: target star {Director.Describe(hive.sector, value.TargetStar)} is at its hive cap.");
return false;
}
FillResources(hive, hive.tinders.buffer[num].builderId);
((DFTinderComponent)(ref hive.tinders.buffer[num])).DispatchFromHive(hive.sector, num2);
_pending.Remove(hive.hiveAstroId);
DarkFogDirectorPlugin.LogInfo($"queued order executed: hive {hive.hiveAstroId} -> {Director.Describe(hive.sector, value.TargetStar)} (astroId {num2})");
return true;
}
private static string DispatchSlot(SpaceSector sector, EnemyDFHiveSystem hive, int slot, int targetStar, string how)
{
if (slot < 0)
{
return L.T("lg_none");
}
int num = CreateHiveInStar(sector, targetStar);
if (num <= 0)
{
return L.T("lg_create_fail");
}
FillResources(hive, hive.tinders.buffer[slot].builderId);
((DFTinderComponent)(ref hive.tinders.buffer[slot])).DispatchFromHive(sector, num);
return L.T("lg_launched", how, DescribeHive(hive), Director.Describe(sector, targetStar));
}
internal static int SpawnTinderNow(EnemyDFHiveSystem hive)
{
if (hive == null)
{
return -1;
}
DFDock[] tinderDocks = hive.tinderDocks;
if (tinderDocks == null || tinderDocks.Length == 0)
{
return -1;
}
try
{
hive.AddTinderDeferred(0);
hive.ExecuteDeferredEnemyChange();
}
catch (Exception ex)
{
DarkFogDirectorPlugin.LogWarn("spawning tinder on demand failed: " + ex.Message);
return -1;
}
return FindIdleSlot(hive);
}
private static int CreateHiveInStar(SpaceSector sector, int starIndex)
{
if (sector == null || sector.galaxy == null)
{
return -1;
}
StarData[] stars = sector.galaxy.stars;
if (starIndex < 0 || starIndex >= stars.Length)
{
return -1;
}
return sector.TryCreateNewHive(stars[starIndex])?.hiveAstroId ?? (-1);
}
internal static string DescribeHive(EnemyDFHiveSystem hive)
{
if (hive == null)
{
return "?";
}
string text = ((hive.starData == null) ? "?" : (string.IsNullOrEmpty(hive.starData.displayName) ? hive.starData.name : hive.starData.displayName));
return L.T("hive_desc", text, hive.hiveOrbitIndex);
}
internal static string StageName(DFTinderComponent t)
{
if (t.stage == 254)
{
return L.T("stage_docked");
}
if (t.stage == -1)
{
return L.T("stage_takeoff");
}
if (t.stage == 0)
{
return L.T("stage_sailing");
}
return L.T("stage_other", t.stage);
}
}
internal static class L
{
internal const int LangZh = 0;
internal const int LangEn = 1;
internal const int LangFr = 2;
internal const int LangDe = 3;
internal const int LangJa = 4;
private static int _index = 1;
private static int _detectedFor = int.MinValue;
private static Dictionary<string, string[]> _table;
internal static int Index
{
get
{
Refresh();
return _index;
}
}
internal static void Refresh()
{
int num = 0;
try
{
num = Localization.CurrentLanguageLCID;
}
catch (Exception)
{
num = 0;
}
if (num == _detectedFor)
{
return;
}
_detectedFor = num;
try
{
switch (num)
{
case 2052:
_index = 0;
break;
case 1036:
_index = 2;
break;
case 1031:
_index = 3;
break;
case 1041:
_index = 4;
break;
default:
_index = 1;
break;
}
}
catch (Exception)
{
_index = 1;
}
}
internal static string T(string key)
{
Refresh();
if (_table == null)
{
BuildTable();
}
if (_table.TryGetValue(key, out var value))
{
if (_index >= 0 && _index < value.Length)
{
return value[_index];
}
if (value.Length > 1)
{
return value[1];
}
}
return key;
}
internal static string T(string key, params object[] args)
{
return string.Format(T(key), args);
}
private static void Add(string key, string zh, string en, string fr, string de, string ja)
{
_table[key] = new string[5] { zh, en, fr, de, ja };
}
private static void BuildTable()
{
_table = new Dictionary<string, string[]>(StringComparer.Ordinal);
Add("title", "黑雾扩张指挥", "Dark Fog Director", "Directeur du Brouillard Sombre", "Dunkelnebel-Direktor", "ダークフォグ拡張指令");
Add("tab_launch", "发射指挥", "Launch", "Lancer", "Abschuss", "発射");
Add("tab_tinders", "火种管理", "Tinders", "Embrands", "Zündkörper", "種火");
Add("header", "按 {0} 键开关 巢穴 {1} 可扩张星系 {2} 火种 {3} 待发 {4}", "Press {0} to toggle Hives {1} Targets {2} Tinders {3} Queued {4}", "Touche {0} : ouvrir/fermer Ruches {1} Cibles {2} Embrands {3} En attente {4}", "Taste {0} : ein/aus Nester {1} Ziele {2} Zündkörper {3} Wartend {4}", "{0} キーで開閉 巣 {1} 拡張先 {2} 種火 {3} 待機 {4}");
Add("src_header", "起点巢穴(已有巢穴)", "Source hive (existing)", "Ruche d'origine (existante)", "Quellnest (vorhanden)", "発射元の巣(既存)");
Add("src_empty", "(星图上还没有黑雾巢穴)", "(No Dark Fog hives in this cluster yet)", "(Aucune ruche dans cet amas)", "(Noch keine Nester in diesem Haufen)", "(この星団に巣はまだない)");
Add("hive_row", "{0} #{1} · 轨道 {2} 火种 {3} / 空闲 {4}", "{0} #{1} · orbit {2} tinders {3} / idle {4}", "{0} #{1} · orbite {2} embrands {3} / libres {4}", "{0} #{1} · Bahn {2} Zündkörper {3} / frei {4}", "{0} #{1} · 軌道 {2} 種火 {3} / 待機 {4}");
Add("pending_tag", "待发", "queued", "en attente", "wartend", "待機");
Add("dst_header", "目标星系(未达巢穴上限;巢穴由游戏自动选轨道)", "Target system (below hive cap; the game picks the orbit)", "Système cible (sous la limite ; le jeu choisit l'orbite)", "Zielsystem (unter dem Nestlimit; Spiel wählt die Bahn)", "目標星系(上限未満・軌道はゲームが選択)");
Add("dst_empty", "(没有可扩张的星系)", "(No system can be expanded to)", "(Aucun système disponible)", "(Kein System verfügbar)", "(拡張可能な星系がない)");
Add("star_row", "{0} #{1} 巢穴 {2}/{3}", "{0} #{1} hives {2}/{3}", "{0} #{1} ruches {2}/{3}", "{0} #{1} Nester {2}/{3}", "{0} #{1} 巣 {2}/{3}");
Add("btn_launch", "发 射", "LAUNCH", "LANCER", "START", "発射");
Add("btn_refresh", "刷新", "Refresh", "Rafraîchir", "Aktualisieren", "更新");
Add("btn_cancel", "取消待发", "Cancel queue", "Annuler l'attente", "Wartend abbrechen", "待機解除");
Add("btn_close", "关闭", "Close", "Fermer", "Schließen", "閉じる");
Add("tinder_header", "全图火种", "All tinders in this cluster", "Tous les embrands", "Alle Zündkörper", "星団内の種火");
Add("tinder_empty", "(当前没有任何火种)", "(No tinders at the moment)", "(Aucun embrand)", "(Keine Zündkörper)", "(種火はない)");
Add("tinder_row", "{0} → {1} [{2}] 速度 {3:0} m/s", "{0} → {1} [{2}] speed {3:0} m/s", "{0} → {1} [{2}] vitesse {3:0} m/s", "{0} → {1} [{2}] Tempo {3:0} m/s", "{0} → {1} [{2}] 速度 {3:0} m/s");
Add("speed_label", "飞行速度 (m/s):", "Flight speed (m/s):", "Vitesse (m/s) :", "Flugtempo (m/s):", "飛行速度 (m/s):");
Add("btn_apply", "应用", "Apply", "Appliquer", "Anwenden", "適用");
Add("btn_restore", "恢复原版", "Restore vanilla", "Rétablir d'origine", "Original wiederherstellen", "元に戻す");
Add("speed_state", "原版上限约 {0:0} m/s;当前{1}", "vanilla cap ~{0:0} m/s; currently {1}", "plafond d'origine ~{0:0} m/s ; actuellement {1}", "Original-Limit ~{0:0} m/s; aktuell {1}", "元の上限 約 {0:0} m/s;現在 {1}");
Add("speed_override", "接管 {0:0}", "overridden at {0:0}", "forcée à {0:0}", "überschrieben mit {0:0}", "{0:0} に固定");
Add("speed_off", "未接管", "not overridden", "non forcée", "nicht überschrieben", "固定なし");
Add("st_default", "选择起点巢穴与目标星系,然后点「发射」。", "Pick a source hive and a target system, then press LAUNCH.", "Choisissez une ruche et un système, puis LANCR.", "Quellnest und Zielsystem wählen, dann START.", "発射元の巣と目標星系を選び、発射を押してください。");
Add("st_not_in_game", "未进入游戏(读不到星图)。", "Not in a game (cluster not loaded).", "Pas en partie (amas non chargé).", "Kein Spielstand (Haufen nicht geladen).", "ゲーム内ではありません(星団未読込)。");
Add("st_pick_hive", "请先选择一个起点巢穴。", "Select a source hive first.", "Sélectionnez d'abord une ruche.", "Zuerst ein Quellnest wählen.", "先に発射元の巣を選んでください。");
Add("st_pick_star", "请先选择一个目标星系。", "Select a target system first.", "Sélectionnez d'abord un système.", "Zuerst ein Zielsystem wählen.", "先に目標星系を選んでください。");
Add("st_refreshed", "列表已刷新。", "List refreshed.", "Liste actualisée.", "Liste aktualisiert.", "一覧を更新しました。");
Add("st_speed_bad", "速度格式不对,请输入数字(单位 m/s)。", "Invalid speed, please enter a number (m/s).", "Vitesse invalide, entrez un nombre (m/s).", "Ungültiges Tempo, bitte eine Zahl eingeben (m/s).", "速度の形式が正しくありません(m/s の数値)。");
Add("st_speed_positive", "速度必须大于 0;要停止接管请点「恢复原版」。", "Speed must be > 0; use Restore vanilla to stop.", "La vitesse doit être > 0 ; utilisez Rétablir pour arrêter.", "Tempo muss > 0 sein; zum Beenden Original wiederherstellen.", "速度は 0 より大きい必要があります(解除は「元に戻す」)。");
Add("st_speed_applied", "已接管飞行速度 {0:0} m/s,立即生效 {1} 个火种。", "Flight speed overridden to {0:0} m/s, applied to {1} tinder(s).", "Vitesse forcée à {0:0} m/s, appliquée à {1} embrand(s).", "Flugtempo auf {0:0} m/s gesetzt, auf {1} Zündkörper angewandt.", "飛行速度を {0:0} m/s に固定、{1} 個に適用しました。");
Add("st_restored", "已停止接管,速度回到原版闭环调速。", "Override cleared, back to the vanilla speed controller.", "Contrôle rendu au régulateur d'origine.", "Überschreibung aufgehoben, Originalregler aktiv.", "固定を解除し、元の速度制御に戻しました。");
Add("btn_apply_one", "应用到选中", "Apply to selected", "Appliquer à la sélection", "Auf Auswahl anwenden", "選択に適用");
Add("btn_apply_all", "应用到全部", "Apply to all", "Appliquer à tous", "Auf alle anwenden", "すべてに適用");
Add("st_pick_tinder", "请先在列表中选中一颗火种。", "Select a tinder in the list first.", "Sélectionnez d'abord un embrand.", "Zuerst einen Zündkörper auswählen.", "先に一覧から種火を選んでください。");
Add("st_speed_one", "已把该火种速度设为 {0:0} m/s,立即生效 {1} 颗。", "Speed set to {0:0} m/s for that tinder, applied to {1}.", "Vitesse de cet embrand fixée à {0:0} m/s ({1} appliqué).", "Tempo dieses Zündkörpers auf {0:0} m/s gesetzt ({1} angewandt).", "この種火の速度を {0:0} m/s に設定({1} 件適用)。");
Add("lg_not_in_game", "未进入游戏,无法下达指令。", "Not in a game, cannot issue an order.", "Pas en partie, ordre impossible.", "Kein Spielstand, Befehl unmöglich.", "ゲーム内ではないため命令できません。");
Add("lg_hive_gone", "起点巢穴已不存在(可能已被摧毁),请刷新列表。", "Source hive no longer exists (destroyed?). Refresh the list.", "La ruche n'existe plus (détruite ?). Actualisez la liste.", "Quellnest existiert nicht mehr (zerstört?). Liste aktualisieren.", "発射元の巣が存在しません(破壊済み?)。一覧を更新してください。");
Add("lg_cap_full", "目标星系 {0} 已达巢穴上限,请换一个。", "Target system {0} is at its hive cap, pick another.", "Le système {0} a atteint sa limite de ruches.", "Zielsystem {0} hat das Nestlimit erreicht.", "目標星系 {0} は巣の上限に達しています。");
Add("lg_launched", "已发射({0}):{1} → {2}", "Launched ({0}): {1} → {2}", "Lancé ({0}) : {1} → {2}", "Gestartet ({0}): {1} → {2}", "発射しました({0}):{1} → {2}");
Add("how_filled", "资源已补满", "resources topped up", "ressources remplies", "Ressourcen aufgefüllt", "資源を補充");
Add("how_spawned", "现造火种并补满资源", "new tinder built", "embrand créé", "Zündkörper neu gebaut", "種火を新造");
Add("lg_create_fail", "在目标星系创建巢穴失败(可能已达上限)。", "Failed to create a hive in the target system (cap reached?).", "Échec de création de la ruche cible (limite atteinte ?).", "Nest im Zielsystem konnte nicht erstellt werden (Limit?).", "目標星系に巣を作成できませんでした(上限?)。");
Add("lg_pending", "该巢穴暂无空闲火种,已登记待发:{0} → {1}", "No idle tinder in this hive; queued: {0} → {1}", "Aucun embrand libre ; mis en attente : {0} → {1}", "Kein freier Zündkörper; in Warteschlange: {0} → {1}", "空き種火がないため待機に登録:{0} → {1}");
Add("lg_none", "没有可用火种。", "No usable tinder.", "Aucun embrand utilisable.", "Kein nutzbarer Zündkörper.", "使用できる種火がありません。");
Add("cancel_ok", "已取消待发指令。", "Queued order cancelled.", "Commande annulée.", "Wartender Befehl abgebrochen.", "待機命令を解除しました。");
Add("cancel_none", "该巢穴没有待发指令。", "This hive has no queued order.", "Aucune commande en attente.", "Kein wartender Befehl.", "待機命令はありません。");
Add("stage_docked", "在港待发", "docked", "à quai", "angedockt", "ドック待機");
Add("stage_takeoff", "起飞中", "launching", "décollage", "startet", "発進中");
Add("stage_sailing", "飞行中", "in flight", "en vol", "im Flug", "航行中");
Add("stage_other", "状态 {0}", "stage {0}", "état {0}", "Status {0}", "状態 {0}");
Add("hive_desc", "{0} 轨道 {1}", "{0} orbit {1}", "{0} orbite {1}", "{0} Bahn {1}", "{0} 軌道 {1}");
}
}
internal static class DirectorPanel
{
private struct HiveRow
{
public int HiveAstroId;
public int StarIndex;
public string StarName;
public int Orbit;
public int Tinders;
public int Ready;
public bool Pending;
}
private struct StarRow
{
public int StarIndex;
public string Name;
public int Hives;
public int Capacity;
}
private const float PanelWidth = 920f;
private const float PanelHeight = 620f;
private const float ColumnWidth = 440f;
private const float ListHeight = 400f;
private const float RowHeight = 24f;
internal static bool Visible;
private static readonly List<HiveRow> _hives = new List<HiveRow>();
private static readonly List<StarRow> _stars = new List<StarRow>();
private static readonly List<TinderRow> _tinders = new List<TinderRow>();
private static GUIStyle _title;
private static GUIStyle _label;
private static GUIStyle _row;
private static GUIStyle _rowSel;
private static GUIStyle _button;
private static GUIStyle _tabOn;
private static GUIStyle _tabOff;
private static GUIStyle _statusStyle;
private static GUIStyle _small;
private static GUIStyle _field;
private static Font _font;
private static int _fontLang = -1;
private static Texture2D _panelTex;
private static Texture2D _rowTex;
private static Texture2D _selTex;
private static Texture2D _btnTex;
private static bool _stylesReady;
private static Vector2 _srcScroll;
private static Vector2 _dstScroll;
private static Vector2 _tinderScroll;
private static float _nextRefresh;
private static string _status;
private static int _selHive = -1;
private static int _selStar = -1;
private static long _selTinder = 0L;
private static int _tab;
private static string _speedText = "1200";
internal static void Toggle()
{
Visible = !Visible;
if (Visible)
{
L.Refresh();
Refresh();
_nextRefresh = Time.realtimeSinceStartup + 2f;
}
}
private static Texture2D Solid(Color c)
{
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
//IL_0008: Expected O, but got Unknown
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
Texture2D val = new Texture2D(1, 1);
val.SetPixel(0, 0, c);
val.Apply();
((Object)val).hideFlags = (HideFlags)61;
return val;
}
private static Font BuildFont(int lang)
{
string[] array = lang switch
{
4 => new string[5] { "Yu Gothic UI", "Meiryo", "MS Gothic", "Microsoft YaHei", "Arial" },
0 => new string[4] { "Microsoft YaHei", "SimHei", "Noto Sans CJK SC", "Arial" },
_ => new string[3] { "Segoe UI", "Microsoft YaHei", "Arial" },
};
try
{
return Font.CreateDynamicFontFromOSFont(array, 15);
}
catch (Exception)
{
return null;
}
}
private static void EnsureStyles()
{
//IL_005a: 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_00a0: 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_00d2: Unknown result type (might be due to invalid IL or missing references)
//IL_00dc: Expected O, but got Unknown
//IL_010c: Unknown result type (might be due to invalid IL or missing references)
//IL_0121: Unknown result type (might be due to invalid IL or missing references)
//IL_012b: Expected O, but got Unknown
//IL_012b: Unknown result type (might be due to invalid IL or missing references)
//IL_0135: Expected O, but got Unknown
//IL_015a: Unknown result type (might be due to invalid IL or missing references)
//IL_016e: Unknown result type (might be due to invalid IL or missing references)
//IL_0178: Expected O, but got Unknown
//IL_017d: Unknown result type (might be due to invalid IL or missing references)
//IL_0187: Expected O, but got Unknown
//IL_01ac: Unknown result type (might be due to invalid IL or missing references)
//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
//IL_01c0: Expected O, but got Unknown
//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
//IL_01eb: Expected O, but got Unknown
//IL_0240: Unknown result type (might be due to invalid IL or missing references)
//IL_0254: Unknown result type (might be due to invalid IL or missing references)
//IL_0268: Unknown result type (might be due to invalid IL or missing references)
//IL_0277: Unknown result type (might be due to invalid IL or missing references)
//IL_0281: Expected O, but got Unknown
//IL_02ae: Unknown result type (might be due to invalid IL or missing references)
//IL_02b8: Unknown result type (might be due to invalid IL or missing references)
//IL_02c2: Expected O, but got Unknown
//IL_032a: Unknown result type (might be due to invalid IL or missing references)
//IL_034d: Unknown result type (might be due to invalid IL or missing references)
//IL_0370: Unknown result type (might be due to invalid IL or missing references)
//IL_037f: Unknown result type (might be due to invalid IL or missing references)
//IL_0389: Expected O, but got Unknown
//IL_03b6: Unknown result type (might be due to invalid IL or missing references)
//IL_03c5: Unknown result type (might be due to invalid IL or missing references)
//IL_03cf: Expected O, but got Unknown
//IL_03f3: Unknown result type (might be due to invalid IL or missing references)
//IL_0407: Unknown result type (might be due to invalid IL or missing references)
//IL_0411: Expected O, but got Unknown
//IL_042d: Unknown result type (might be due to invalid IL or missing references)
//IL_0437: Expected O, but got Unknown
//IL_0467: Unknown result type (might be due to invalid IL or missing references)
int index = L.Index;
if (!_stylesReady || _fontLang != index)
{
if ((Object)(object)_font == (Object)null || _fontLang != index)
{
_font = BuildFont(index);
_fontLang = index;
}
if (!_stylesReady)
{
_panelTex = Solid(new Color(0.07f, 0.08f, 0.11f, 0.96f));
_rowTex = Solid(new Color(0.16f, 0.18f, 0.24f, 0.95f));
_selTex = Solid(new Color(0.95f, 0.55f, 0.16f, 0.95f));
_btnTex = Solid(new Color(0.24f, 0.28f, 0.38f, 1f));
_title = new GUIStyle();
_title.fontSize = 20;
_title.fontStyle = (FontStyle)1;
_title.normal.textColor = new Color(0.95f, 0.96f, 1f);
_title.padding = new RectOffset(12, 12, 8, 8);
_label = new GUIStyle();
_label.fontSize = 14;
_label.normal.textColor = new Color(0.75f, 0.79f, 0.88f);
_label.padding = new RectOffset(10, 6, 4, 4);
_small = new GUIStyle(_label);
_small.fontSize = 12;
_small.normal.textColor = new Color(0.62f, 0.66f, 0.76f);
_row = new GUIStyle();
_row.fontSize = 14;
_row.alignment = (TextAnchor)3;
_row.padding = new RectOffset(10, 6, 3, 3);
_row.normal.background = _rowTex;
_row.hover.background = _btnTex;
_row.active.background = _selTex;
_row.normal.textColor = new Color(0.88f, 0.91f, 0.97f);
_row.hover.textColor = Color.white;
_row.active.textColor = Color.white;
_rowSel = new GUIStyle(_row);
_rowSel.normal.background = _selTex;
_rowSel.normal.textColor = new Color(0.1f, 0.08f, 0.05f);
_button = new GUIStyle();
_button.fontSize = 15;
_button.fontStyle = (FontStyle)1;
_button.alignment = (TextAnchor)4;
_button.normal.background = _btnTex;
_button.hover.background = _selTex;
_button.active.background = _selTex;
_button.normal.textColor = Color.white;
_button.hover.textColor = new Color(0.1f, 0.08f, 0.05f);
_button.active.textColor = new Color(0.1f, 0.08f, 0.05f);
_tabOn = new GUIStyle(_button);
_tabOn.normal.background = _selTex;
_tabOn.normal.textColor = new Color(0.1f, 0.08f, 0.05f);
_tabOff = new GUIStyle(_button);
_tabOff.fontStyle = (FontStyle)0;
_tabOff.normal.textColor = new Color(0.72f, 0.76f, 0.86f);
_field = new GUIStyle(GUI.skin.textField);
_field.fontSize = 14;
_field.alignment = (TextAnchor)3;
_statusStyle = new GUIStyle(_label);
_statusStyle.fontSize = 13;
_statusStyle.wordWrap = false;
_statusStyle.normal.textColor = new Color(0.98f, 0.78f, 0.42f);
_stylesReady = true;
}
_title.font = _font;
_label.font = _font;
_small.font = _font;
_row.font = _font;
_rowSel.font = _font;
_button.font = _font;
_tabOn.font = _font;
_tabOff.font = _font;
_field.font = _font;
_statusStyle.font = _font;
if (_status == null)
{
_status = L.T("st_default");
}
}
}
private static string StarName(StarData s)
{
if (s == null)
{
return "?";
}
if (!string.IsNullOrEmpty(s.displayName))
{
return s.displayName;
}
return s.name;
}
internal static void Refresh()
{
_hives.Clear();
_stars.Clear();
SpaceSector val = GameMain.data?.spaceSector;
if (val == null || val.galaxy == null)
{
_status = L.T("st_not_in_game");
return;
}
StarData[] stars = val.galaxy.stars;
for (int i = 0; i < stars.Length; i++)
{
int num = 0;
for (EnemyDFHiveSystem val2 = val.dfHives[i]; val2 != null; val2 = val2.nextSibling)
{
num++;
HiveRow item = new HiveRow
{
HiveAstroId = val2.hiveAstroId,
StarIndex = i,
StarName = StarName(stars[i]),
Orbit = val2.hiveOrbitIndex,
Tinders = LaunchOrders.CountTinders(val2),
Ready = LaunchOrders.CountReadyTinders(val2),
Pending = LaunchOrders.HasPending(val2.hiveAstroId)
};
_hives.Add(item);
}
int num2 = LaunchOrders.OrbitCapacity(stars[i]);
if (num2 > 0 && num < num2)
{
StarRow item2 = new StarRow
{
StarIndex = i,
Name = StarName(stars[i]),
Hives = num,
Capacity = num2
};
_stars.Add(item2);
}
}
TinderSpeed.Collect(val, _tinders);
bool flag = false;
foreach (HiveRow hive in _hives)
{
if (hive.HiveAstroId == _selHive)
{
flag = true;
break;
}
}
if (!flag)
{
_selHive = -1;
}
bool flag2 = false;
foreach (StarRow star in _stars)
{
if (star.StarIndex == _selStar)
{
flag2 = true;
break;
}
}
if (!flag2)
{
_selStar = -1;
}
bool flag3 = false;
foreach (TinderRow tinder in _tinders)
{
if (TinderSpeed.Key(tinder.HiveAstroId, tinder.TinderId) == _selTinder)
{
flag3 = true;
break;
}
}
if (!flag3)
{
_selTinder = 0L;
}
}
private static SpaceSector Sector()
{
return GameMain.data?.spaceSector;
}
private static TinderRow SelectedTinder()
{
foreach (TinderRow tinder in _tinders)
{
if (TinderSpeed.Key(tinder.HiveAstroId, tinder.TinderId) == _selTinder)
{
return tinder;
}
}
return default(TinderRow);
}
private static bool ParseSpeed(out float value)
{
return float.TryParse(_speedText.Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out value);
}
private static void DoLaunch()
{
SpaceSector val = Sector();
if (val == null)
{
_status = L.T("st_not_in_game");
return;
}
if (_selHive < 0)
{
_status = L.T("st_pick_hive");
return;
}
if (_selStar < 0)
{
_status = L.T("st_pick_star");
return;
}
_status = LaunchOrders.RequestLaunch(val, _selHive, _selStar);
Refresh();
}
private static void ApplySpeedToSelected()
{
if (!ParseSpeed(out var value))
{
_status = L.T("st_speed_bad");
return;
}
if (value <= 0f)
{
_status = L.T("st_speed_positive");
return;
}
if (_selTinder == 0)
{
_status = L.T("st_pick_tinder");
return;
}
TinderRow tinderRow = SelectedTinder();
TinderSpeed.SetTinder(tinderRow.HiveAstroId, tinderRow.TinderId, value);
SpaceSector val = Sector();
int num = ((val != null) ? TinderSpeed.ApplyNow(val) : 0);
_status = L.T("st_speed_one", value, num);
Refresh();
}
private static void ApplySpeedToAll()
{
if (!ParseSpeed(out var value))
{
_status = L.T("st_speed_bad");
return;
}
if (value <= 0f)
{
_status = L.T("st_speed_positive");
return;
}
TinderSpeed.GlobalSpeed = value;
SpaceSector val = Sector();
int num = ((val != null) ? TinderSpeed.ApplyNow(val) : 0);
_status = L.T("st_speed_applied", value, num);
Refresh();
}
internal static void OnGUI()
{
//IL_005f: 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)
if (!Visible)
{
return;
}
try
{
EnsureStyles();
if (Time.realtimeSinceStartup >= _nextRefresh)
{
Refresh();
_nextRefresh = Time.realtimeSinceStartup + 2f;
}
float num = 920f;
float num2 = 620f;
Rect val = default(Rect);
((Rect)(ref val))..ctor(((float)Screen.width - num) * 0.5f, ((float)Screen.height - num2) * 0.5f, num, num2);
GUILayout.BeginArea(val);
GUI.DrawTexture(new Rect(0f, 0f, num, num2), (Texture)(object)_panelTex);
GUILayout.BeginVertical((GUILayoutOption[])(object)new GUILayoutOption[0]);
GUILayout.Label(L.T("title"), _title, (GUILayoutOption[])(object)new GUILayoutOption[0]);
GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]);
if (GUILayout.Button(L.T("tab_launch"), (_tab == 0) ? _tabOn : _tabOff, (GUILayoutOption[])(object)new GUILayoutOption[2]
{
GUILayout.Width(110f),
GUILayout.Height(30f)
}))
{
_tab = 0;
}
if (GUILayout.Button(L.T("tab_tinders"), (_tab == 1) ? _tabOn : _tabOff, (GUILayoutOption[])(object)new GUILayoutOption[2]
{
GUILayout.Width(110f),
GUILayout.Height(30f)
}))
{
_tab = 1;
}
GUILayout.Label(L.T("header", "\\", _hives.Count, _stars.Count, _tinders.Count, LaunchOrders.PendingCount), _small, (GUILayoutOption[])(object)new GUILayoutOption[0]);
GUILayout.EndHorizontal();
GUILayout.Space(4f);
if (_tab == 0)
{
DrawLaunchTab();
}
else
{
DrawTinderTab();
}
GUILayout.Space(6f);
GUILayout.Label(_status, _statusStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]);
GUILayout.EndVertical();
GUILayout.EndArea();
}
catch (Exception ex)
{
DarkFogDirectorPlugin.LogError("panel draw failed: " + ex.Message);
Visible = false;
}
}
private static void DrawLaunchTab()
{
//IL_0042: Unknown result type (might be due to invalid IL or missing references)
//IL_006d: Unknown result type (might be due to invalid IL or missing references)
//IL_0072: Unknown result type (might be due to invalid IL or missing references)
//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
//IL_0204: Unknown result type (might be due to invalid IL or missing references)
//IL_0209: Unknown result type (might be due to invalid IL or missing references)
GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]);
GUILayout.BeginVertical((GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(440f) });
GUILayout.Label(L.T("src_header"), _label, (GUILayoutOption[])(object)new GUILayoutOption[0]);
_srcScroll = GUILayout.BeginScrollView(_srcScroll, (GUILayoutOption[])(object)new GUILayoutOption[2]
{
GUILayout.Width(430f),
GUILayout.Height(400f)
});
if (_hives.Count == 0)
{
GUILayout.Label(L.T("src_empty"), _small, (GUILayoutOption[])(object)new GUILayoutOption[0]);
}
for (int i = 0; i < _hives.Count; i++)
{
HiveRow hiveRow = _hives[i];
string text = L.T("hive_row", hiveRow.StarName, hiveRow.StarIndex, hiveRow.Orbit, hiveRow.Tinders, hiveRow.Ready);
if (hiveRow.Pending)
{
text = text + " [" + L.T("pending_tag") + "]";
}
if (GUILayout.Button(text, (hiveRow.HiveAstroId == _selHive) ? _rowSel : _row, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(24f) }))
{
_selHive = hiveRow.HiveAstroId;
}
}
GUILayout.EndScrollView();
GUILayout.EndVertical();
GUILayout.Space(10f);
GUILayout.BeginVertical((GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(440f) });
GUILayout.Label(L.T("dst_header"), _label, (GUILayoutOption[])(object)new GUILayoutOption[0]);
_dstScroll = GUILayout.BeginScrollView(_dstScroll, (GUILayoutOption[])(object)new GUILayoutOption[2]
{
GUILayout.Width(430f),
GUILayout.Height(400f)
});
if (_stars.Count == 0)
{
GUILayout.Label(L.T("dst_empty"), _small, (GUILayoutOption[])(object)new GUILayoutOption[0]);
}
for (int j = 0; j < _stars.Count; j++)
{
StarRow starRow = _stars[j];
string text2 = L.T("star_row", starRow.Name, starRow.StarIndex, starRow.Hives, starRow.Capacity);
if (GUILayout.Button(text2, (starRow.StarIndex == _selStar) ? _rowSel : _row, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(24f) }))
{
_selStar = starRow.StarIndex;
}
}
GUILayout.EndScrollView();
GUILayout.EndVertical();
GUILayout.EndHorizontal();
GUILayout.Space(8f);
GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]);
if (GUILayout.Button(L.T("btn_launch"), _button, (GUILayoutOption[])(object)new GUILayoutOption[2]
{
GUILayout.Width(130f),
GUILayout.Height(38f)
}))
{
DoLaunch();
}
if (GUILayout.Button(L.T("btn_refresh"), _button, (GUILayoutOption[])(object)new GUILayoutOption[2]
{
GUILayout.Width(95f),
GUILayout.Height(38f)
}))
{
Refresh();
_status = L.T("st_refreshed");
}
if (_selHive >= 0 && LaunchOrders.HasPending(_selHive) && GUILayout.Button(L.T("btn_cancel"), _button, (GUILayoutOption[])(object)new GUILayoutOption[2]
{
GUILayout.Width(120f),
GUILayout.Height(38f)
}))
{
_status = LaunchOrders.CancelPending(_selHive);
Refresh();
}
if (GUILayout.Button(L.T("btn_close"), _button, (GUILayoutOption[])(object)new GUILayoutOption[2]
{
GUILayout.Width(95f),
GUILayout.Height(38f)
}))
{
Visible = false;
}
GUILayout.EndHorizontal();
}
private static void DrawTinderTab()
{
//IL_001a: Unknown result type (might be due to invalid IL or missing references)
//IL_0045: Unknown result type (might be due to invalid IL or missing references)
//IL_004a: Unknown result type (might be due to invalid IL or missing references)
GUILayout.Label(L.T("tinder_header"), _label, (GUILayoutOption[])(object)new GUILayoutOption[0]);
_tinderScroll = GUILayout.BeginScrollView(_tinderScroll, (GUILayoutOption[])(object)new GUILayoutOption[2]
{
GUILayout.Width(880f),
GUILayout.Height(400f)
});
if (_tinders.Count == 0)
{
GUILayout.Label(L.T("tinder_empty"), _small, (GUILayoutOption[])(object)new GUILayoutOption[0]);
}
for (int i = 0; i < _tinders.Count; i++)
{
TinderRow tinderRow = _tinders[i];
long num = TinderSpeed.Key(tinderRow.HiveAstroId, tinderRow.TinderId);
string text = L.T("tinder_row", tinderRow.From, tinderRow.Target, tinderRow.Stage, tinderRow.Speed);
if (tinderRow.Overridden)
{
text += " *";
}
if (GUILayout.Button(text, (num == _selTinder) ? _rowSel : _row, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(24f) }))
{
_selTinder = num;
_speedText = ((int)SelectedTinder().Speed).ToString(CultureInfo.InvariantCulture);
}
}
GUILayout.EndScrollView();
GUILayout.Space(8f);
GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]);
GUILayout.Label(L.T("speed_label"), _label, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(120f) });
_speedText = GUILayout.TextField(_speedText, _field, (GUILayoutOption[])(object)new GUILayoutOption[2]
{
GUILayout.Width(110f),
GUILayout.Height(28f)
});
if (GUILayout.Button(L.T("btn_apply_one"), _button, (GUILayoutOption[])(object)new GUILayoutOption[2]
{
GUILayout.Width(110f),
GUILayout.Height(30f)
}))
{
ApplySpeedToSelected();
}
if (GUILayout.Button(L.T("btn_apply_all"), _button, (GUILayoutOption[])(object)new GUILayoutOption[2]
{
GUILayout.Width(110f),
GUILayout.Height(30f)
}))
{
ApplySpeedToAll();
}
if (GUILayout.Button(L.T("btn_restore"), _button, (GUILayoutOption[])(object)new GUILayoutOption[2]
{
GUILayout.Width(120f),
GUILayout.Height(30f)
}))
{
TinderSpeed.ClearAll();
_status = L.T("st_restored");
Refresh();
}
GUILayout.EndHorizontal();
GUILayout.Space(4f);
GUILayout.Label(string.Format(L.T("speed_state"), 1200f, (TinderSpeed.GlobalSpeed > 0f) ? L.T("speed_override", TinderSpeed.GlobalSpeed) : L.T("speed_off")), _small, (GUILayoutOption[])(object)new GUILayoutOption[0]);
GUILayout.Space(6f);
GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]);
if (GUILayout.Button(L.T("btn_refresh"), _button, (GUILayoutOption[])(object)new GUILayoutOption[2]
{
GUILayout.Width(95f),
GUILayout.Height(34f)
}))
{
Refresh();
_status = L.T("st_refreshed");
}
if (GUILayout.Button(L.T("btn_close"), _button, (GUILayoutOption[])(object)new GUILayoutOption[2]
{
GUILayout.Width(95f),
GUILayout.Height(34f)
}))
{
Visible = false;
}
GUILayout.EndHorizontal();
}
}
internal sealed class Rule
{
public string RawSource;
public string RawTarget;
public bool Force;
public int StarIndex = -1;
public int Orbit = -1;
public int TargetStar = -1;
public override string ToString()
{
return string.Format("{0} => {1}{2}", RawSource, RawTarget, Force ? " !" : string.Empty);
}
}
internal sealed class RuleBook
{
private readonly List<Rule> _rules = new List<Rule>();
private GalaxyData _resolvedFor;
private string _path;
internal string Path => _path;
internal IList<Rule> All => _rules;
internal void Load(string path)
{
_path = path;
_rules.Clear();
_resolvedFor = null;
if (!File.Exists(path))
{
DarkFogDirectorPlugin.LogWarn("指令文件不存在,已按「不干预」运行:" + path);
return;
}
string[] array;
try
{
array = File.ReadAllLines(path, Encoding.UTF8);
}
catch (Exception ex)
{
DarkFogDirectorPlugin.LogWarn("读取指令文件失败:" + ex.Message);
return;
}
int num = 0;
string[] array2 = array;
foreach (string text in array2)
{
num++;
string text2 = text.Trim();
if (text2.Length == 0 || text2.StartsWith("#") || text2.StartsWith("//"))
{
continue;
}
int num2 = text2.IndexOf("=>", StringComparison.Ordinal);
if (num2 < 0)
{
DarkFogDirectorPlugin.LogWarn($"第 {num} 行缺少 =>,已跳过:{text2}");
continue;
}
Rule rule = new Rule();
rule.RawSource = text2.Substring(0, num2).Trim();
string text3 = text2.Substring(num2 + 2).Trim();
if (text3.EndsWith("!"))
{
rule.Force = true;
text3 = text3.Substring(0, text3.Length - 1).Trim();
}
rule.RawTarget = text3;
if (rule.RawSource.Length == 0 || rule.RawTarget.Length == 0)
{
DarkFogDirectorPlugin.LogWarn($"第 {num} 行源或目标为空,已跳过。");
}
else
{
_rules.Add(rule);
}
}
DarkFogDirectorPlugin.LogInfo($"已载入 {_rules.Count} 条扩张指令:{path}");
}
internal void EnsureResolved(GalaxyData galaxy)
{
if (galaxy == null || object.ReferenceEquals(_resolvedFor, galaxy))
{
return;
}
_resolvedFor = galaxy;
foreach (Rule rule in _rules)
{
rule.StarIndex = -1;
rule.Orbit = -1;
rule.TargetStar = -1;
string text = rule.RawSource;
int num = text.LastIndexOf(':');
if (num > 0)
{
string s = text.Substring(num + 1).Trim();
text = text.Substring(0, num).Trim();
if (int.TryParse(s, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result))
{
rule.Orbit = result;
}
}
rule.StarIndex = ResolveStarOrAstro(text, galaxy);
rule.TargetStar = ResolveStarOrAstro(rule.RawTarget, galaxy);
if (rule.StarIndex < 0)
{
DarkFogDirectorPlugin.LogWarn("无法识别源巢穴:" + rule.RawSource);
}
else if (rule.TargetStar < 0)
{
DarkFogDirectorPlugin.LogWarn("无法识别目标星系:" + rule.RawTarget);
}
}
}
private static int ResolveStarOrAstro(string token, GalaxyData galaxy)
{
token = token.Trim();
if (token.Length == 0)
{
return -1;
}
if (int.TryParse(token, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result))
{
if (result >= 0 && result < galaxy.stars.Length)
{
return result;
}
if (result >= 1000000)
{
int num = Director.ToStarIndex(result);
if (num >= 0 && num < galaxy.stars.Length)
{
return num;
}
}
return -1;
}
for (int i = 0; i < galaxy.stars.Length; i++)
{
StarData val = galaxy.stars[i];
if (val != null)
{
if (string.Equals(val.name, token, StringComparison.OrdinalIgnoreCase))
{
return i;
}
if (string.Equals(val.overrideName, token, StringComparison.OrdinalIgnoreCase))
{
return i;
}
if (string.Equals(val.displayName, token, StringComparison.OrdinalIgnoreCase))
{
return i;
}
}
}
return -1;
}
internal Rule Match(int starIndex, int orbit)
{
Rule rule = null;
Rule rule2 = null;
foreach (Rule rule3 in _rules)
{
if (rule3.StarIndex == starIndex && rule3.TargetStar >= 0)
{
if (rule3.Orbit >= 0 && rule3.Orbit == orbit)
{
rule = rule3;
}
else if (rule3.Orbit < 0)
{
rule2 = rule3;
}
}
}
return rule ?? rule2;
}
internal bool HasResolvableRule()
{
foreach (Rule rule in _rules)
{
if (rule.StarIndex >= 0 && rule.TargetStar >= 0)
{
return true;
}
}
return false;
}
}
internal struct TinderRow
{
public int HiveAstroId;
public int TinderId;
public string From;
public string Target;
public string Stage;
public float Speed;
public bool Overridden;
}
internal static class TinderSpeed
{
internal const float VanillaMaxSpeed = 1200f;
internal static float GlobalSpeed;
private static readonly Dictionary<long, float> _perTinder = new Dictionary<long, float>();
internal static int OverrideCount => _perTinder.Count;
internal static long Key(int hiveAstroId, int tinderId)
{
return ((long)hiveAstroId << 32) | (uint)tinderId;
}
internal static void SetTinder(int hiveAstroId, int tinderId, float speed)
{
_perTinder[Key(hiveAstroId, tinderId)] = speed;
}
internal static bool ClearTinder(int hiveAstroId, int tinderId)
{
return _perTinder.Remove(Key(hiveAstroId, tinderId));
}
internal static bool HasTinder(int hiveAstroId, int tinderId)
{
return _perTinder.ContainsKey(Key(hiveAstroId, tinderId));
}
internal static void ClearAll()
{
GlobalSpeed = 0f;
_perTinder.Clear();
}
internal static float Effective(int hiveAstroId, int tinderId)
{
if (_perTinder.TryGetValue(Key(hiveAstroId, tinderId), out var value) && value > 0f)
{
return value;
}
if (!(GlobalSpeed > 0f))
{
return 0f;
}
return GlobalSpeed;
}
internal static int ApplyNow(SpaceSector sector)
{
int num = 0;
if (sector == null || sector.dfHives == null)
{
return 0;
}
for (int i = 0; i < sector.dfHives.Length; i++)
{
for (EnemyDFHiveSystem val = sector.dfHives[i]; val != null; val = val.nextSibling)
{
DataPool<DFTinderComponent> tinders = val.tinders;
if (tinders != null && tinders.buffer != null)
{
int num2 = tinders.cursor;
if (num2 > tinders.buffer.Length)
{
num2 = tinders.buffer.Length;
}
for (int j = 1; j < num2; j++)
{
if (tinders.buffer[j].id == j && tinders.buffer[j].stage == 0 && tinders.buffer[j].targetHiveAstroId != 0)
{
float num3 = Effective(val.hiveAstroId, j);
if (!(num3 <= 0f))
{
tinders.buffer[j].uSpeed = num3;
num++;
}
}
}
}
}
}
return num;
}
internal static void OnSailTick(ref DFTinderComponent tinder, SpaceSector sector)
{
if (sector == null || tinder.originHiveAstroId <= 0)
{
return;
}
if (tinder.stage != 0 && tinder.stage != 254 && tinder.stage != -1)
{
_perTinder.Remove(Key(tinder.originHiveAstroId, tinder.id));
}
else
{
if (tinder.stage != 0 || tinder.targetHiveAstroId == 0)
{
return;
}
float num = Effective(tinder.originHiveAstroId, tinder.id);
if (num <= 0f)
{
return;
}
EnemyDFHiveSystem hiveByAstroId = sector.GetHiveByAstroId(tinder.originHiveAstroId);
if (hiveByAstroId == null)
{
return;
}
DataPool<DFTinderComponent> tinders = hiveByAstroId.tinders;
if (tinders == null || tinders.buffer == null)
{
return;
}
int num2 = tinders.cursor;
if (num2 > tinders.buffer.Length)
{
num2 = tinders.buffer.Length;
}
for (int i = 1; i < num2; i++)
{
if (tinders.buffer[i].id == tinder.id)
{
tinders.buffer[i].uSpeed = num;
break;
}
}
}
}
internal static void Collect(SpaceSector sector, List<TinderRow> into)
{
//IL_006f: 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_00b1: Unknown result type (might be due to invalid IL or missing references)
into.Clear();
if (sector == null || sector.dfHives == null)
{
return;
}
for (int i = 0; i < sector.dfHives.Length; i++)
{
for (EnemyDFHiveSystem val = sector.dfHives[i]; val != null; val = val.nextSibling)
{
DataPool<DFTinderComponent> tinders = val.tinders;
if (tinders != null && tinders.buffer != null)
{
int num = tinders.cursor;
if (num > tinders.buffer.Length)
{
num = tinders.buffer.Length;
}
for (int j = 1; j < num; j++)
{
DFTinderComponent t = tinders.buffer[j];
if (t.id == j)
{
TinderRow item = new TinderRow
{
HiveAstroId = val.hiveAstroId,
TinderId = j,
From = LaunchOrders.DescribeHive(val),
Stage = LaunchOrders.StageName(t),
Speed = t.uSpeed,
Overridden = _perTinder.ContainsKey(Key(val.hiveAstroId, j))
};
if (t.targetHiveAstroId > 0)
{
EnemyDFHiveSystem hiveByAstroId = sector.GetHiveByAstroId(t.targetHiveAstroId);
item.Target = ((hiveByAstroId != null) ? LaunchOrders.DescribeHive(hiveByAstroId) : ("astroId " + t.targetHiveAstroId));
}
else
{
item.Target = "—";
}
into.Add(item);
}
}
}
}
}
}
}
[HarmonyPatch(typeof(DFTinderComponent), "TinderSailLogic")]
internal static class Patch_TinderSailLogic
{
[HarmonyPostfix]
internal static void Postfix(ref DFTinderComponent __instance, SpaceSector sector)
{
try
{
TinderSpeed.OnSailTick(ref __instance, sector);
}
catch (Exception ex)
{
DarkFogDirectorPlugin.LogError("speed override failed (ignored this tick): " + ex.Message);
}
}
}