using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.UI;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Embedded]
[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
internal sealed class RefSafetyRulesAttribute : Attribute
{
public readonly int Version;
public RefSafetyRulesAttribute(int P_0)
{
Version = P_0;
}
}
}
internal static class PluginInfo
{
public const string PLUGIN_GUID = "com.yummi.dsp.collectordeployer";
public const string PLUGIN_NAME = "CollectorDeployer";
public const string PLUGIN_VERSION = "1.1.0";
}
namespace CollectorDeployer
{
internal static class CollectorDeploy
{
private enum PlanetStatus
{
Ok,
NoPower,
TooSmall,
TooMany
}
private struct ExistingCollector
{
public int objId;
public int protoId;
public Vector3 pos;
public bool recoverable;
public bool isEntity;
}
private sealed class PlanetPlan
{
public PlanetData planet;
public PlanetFactory factory;
public bool isLocal;
public readonly List<Vector3> missingTargets = new List<Vector3>();
public readonly List<ExistingCollector> dismantle = new List<ExistingCollector>();
public int existingCount;
public int keptCount;
public int recoverableCount;
public int NeededCount => missingTargets.Count;
public bool IsDone
{
get
{
if (NeededCount == 0)
{
return dismantle.Count == 0;
}
return false;
}
}
}
private sealed class Batch
{
public Player player;
public ItemProto item;
public int packageCount;
public readonly List<PlanetPlan> plans = new List<PlanetPlan>();
public int doneCount;
public int tooManyCount;
public int unusableCount;
public int NeededCount => plans.Sum((PlanetPlan p) => p.NeededCount);
public int RecoverableCount => plans.Sum((PlanetPlan p) => p.recoverableCount);
public int DismantleCount => plans.Sum((PlanetPlan p) => p.dismantle.Count);
public int AvailableCount => packageCount + RecoverableCount;
public int ReservedFromPackage => Math.Min(packageCount, NeededCount);
}
[Serializable]
[CompilerGenerated]
private sealed class <>c
{
public static readonly <>c <>9 = new <>c();
public static Response <>9__12_0;
public static Func<KeyValuePair<int, int>, string> <>9__26_0;
internal void <Confirm>b__12_0()
{
_dialogOpen = false;
}
internal string <FormatItems>b__26_0(KeyValuePair<int, int> kv)
{
return $"{ItemName(kv.Key)} ×{kv.Value}";
}
}
public const int CollectorCount = 40;
private const int OrbitalCollectorItemId = 2105;
private const int SandItemId = 1099;
private const float CollectorMinSqrDistance = 14297f;
private const float MatchSqrDistance = 1f;
private static bool _dialogOpen;
public static void RequestLocal()
{
if (_dialogOpen)
{
return;
}
Batch batch = MakeLocalBatch();
if (batch != null)
{
Dictionary<int, int> dictionary = PredictOverflow(batch);
if (dictionary.Count == 0)
{
Execute(batch);
return;
}
string message = Lang.T("背包空间不足,拆除旧的轨道采集器后以下物品会掉落:\n" + FormatItems(dictionary) + "\n\n是否继续?", "Not enough inventory space. Removing the old orbital collectors will drop:\n" + FormatItems(dictionary) + "\n\nContinue?");
Confirm(Lang.TipTitle, message, MakeLocalBatch);
}
}
public static void RequestGalaxy()
{
if (_dialogOpen)
{
return;
}
Batch batch = MakeGalaxyBatch();
if (batch != null)
{
Dictionary<int, int> dictionary = PredictOverflow(batch);
string text = Lang.T($"将在 {batch.plans.Count} 颗气态巨星上部署轨道采集器:新建 {batch.NeededCount} 个,拆除 {batch.DismantleCount} 个不在格点上的。", $"Orbital collectors will be deployed on {batch.plans.Count} gas giant(s): {batch.NeededCount} built, {batch.DismantleCount} off-grid removed.");
List<string> list = new List<string>();
if (batch.doneCount > 0)
{
list.Add(Lang.T($"已部署完毕 {batch.doneCount} 颗", $"{batch.doneCount} already done"));
}
if (batch.tooManyCount > 0)
{
list.Add(Lang.T($"采集器超过 {40} 个,跳过 {batch.tooManyCount} 颗", $"{batch.tooManyCount} skipped (more than {40} collectors)"));
}
if (batch.unusableCount > 0)
{
list.Add(Lang.T($"无法使用采集器,跳过 {batch.unusableCount} 颗", $"{batch.unusableCount} skipped (collectors can't work there)"));
}
if (list.Count > 0)
{
text = text + "\n" + string.Join(Lang.T(";", "; "), list);
}
if (dictionary.Count > 0)
{
text += Lang.T("\n\n背包空间不足,以下物品会掉落:\n" + FormatItems(dictionary), "\n\nNot enough inventory space. These items will drop:\n" + FormatItems(dictionary));
}
text += Lang.T("\n\n是否继续?", "\n\nContinue?");
Confirm(Lang.GalaxyTipTitle, text, MakeGalaxyBatch);
}
}
private static void Confirm(string title, string message, Func<Batch> rebuild)
{
//IL_0050: Unknown result type (might be due to invalid IL or missing references)
//IL_005a: Expected O, but got Unknown
//IL_003e: Unknown result type (might be due to invalid IL or missing references)
//IL_0043: Unknown result type (might be due to invalid IL or missing references)
//IL_0049: Expected O, but got Unknown
_dialogOpen = true;
string text = Localization.Translate("否");
string text2 = Localization.Translate("是");
object obj = <>c.<>9__12_0;
if (obj == null)
{
Response val = delegate
{
_dialogOpen = false;
};
<>c.<>9__12_0 = val;
obj = (object)val;
}
UIMessageBox.Show(title, message, text, text2, 1, (Response)obj, (Response)delegate
{
_dialogOpen = false;
Batch batch = rebuild();
if (batch != null)
{
Execute(batch);
}
});
}
private static Batch MakeLocalBatch()
{
//IL_0017: Unknown result type (might be due to invalid IL or missing references)
//IL_001d: Invalid comparison between Unknown and I4
if (!TryGetContext(out var player, out var item))
{
return null;
}
PlanetData localPlanet = GameMain.localPlanet;
if (localPlanet == null || (int)localPlanet.type != 5)
{
UIRealtimeTip.Popup(Lang.T("只能在气态巨星上使用", "Only available on gas giants"), true, 0);
return null;
}
if (player.factory == null || player.factory.planet != localPlanet)
{
UIRealtimeTip.Popup(Lang.T("星球数据尚未加载", "Planet data is not loaded yet"), true, 0);
return null;
}
PlanetStatus status;
PlanetPlan planetPlan = PlanPlanet(player, localPlanet, item, out status);
switch (status)
{
case PlanetStatus.NoPower:
UIRealtimeTip.Popup(Lang.T("该星球的资源不足以驱动轨道采集器", "This planet cannot power orbital collectors"), true, 0);
return null;
case PlanetStatus.TooSmall:
UIRealtimeTip.Popup(Lang.T($"星球太小,赤道上放不下 {40} 个轨道采集器", $"Planet is too small to fit {40} orbital collectors on the equator"), true, 0);
return null;
case PlanetStatus.TooMany:
UIRealtimeTip.Popup(Lang.T($"本星球已有 {planetPlan.existingCount} 个轨道采集器,超过 {40} 个,不进行部署", $"This planet already has {planetPlan.existingCount} orbital collectors (more than {40}); nothing deployed"), true, 0);
return null;
default:
{
if (planetPlan.IsDone)
{
UIRealtimeTip.Popup(Lang.T($"赤道上已部署 {40} 个轨道采集器", $"{40} orbital collectors are already deployed on the equator"), false, 0);
return null;
}
Batch batch = new Batch
{
player = player,
item = item,
packageCount = player.package.GetItemCount(((Proto)item).ID)
};
batch.plans.Add(planetPlan);
if (!CheckEnough(batch))
{
return null;
}
return batch;
}
}
}
private static Batch MakeGalaxyBatch()
{
//IL_0189: Unknown result type (might be due to invalid IL or missing references)
//IL_018e: 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_00a0: Invalid comparison between Unknown and I4
if (!TryGetContext(out var player, out var item))
{
return null;
}
GalaxyData galaxy = GameMain.galaxy;
if (galaxy?.stars == null)
{
return null;
}
Batch batch = new Batch
{
player = player,
item = item,
packageCount = player.package.GetItemCount(((Proto)item).ID)
};
StarData[] stars = galaxy.stars;
foreach (StarData val in stars)
{
if (val?.planets == null)
{
continue;
}
PlanetData[] planets = val.planets;
foreach (PlanetData val2 in planets)
{
if (val2 == null || (int)val2.type != 5)
{
continue;
}
PlanetStatus status;
PlanetPlan planetPlan = PlanPlanet(player, val2, item, out status);
switch (status)
{
case PlanetStatus.TooMany:
batch.tooManyCount++;
break;
default:
batch.unusableCount++;
break;
case PlanetStatus.Ok:
if (planetPlan.IsDone)
{
batch.doneCount++;
}
else
{
batch.plans.Add(planetPlan);
}
break;
}
}
}
if (batch.plans.Count == 0)
{
UIRealtimeTip.Popup((batch.doneCount > 0) ? Lang.T($"全银河 {batch.doneCount} 颗气态巨星均已部署完毕", $"All {batch.doneCount} gas giants in the galaxy are already deployed") : Lang.T("没有可以部署的气态巨星", "No gas giant to deploy on"), false, 0);
return null;
}
VectorLF3 playerPos = player.uPosition;
batch.plans.Sort(delegate(PlanetPlan a, PlanetPlan b)
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
//IL_0011: Unknown result type (might be due to invalid IL or missing references)
//IL_0016: Unknown result type (might be due to invalid IL or missing references)
//IL_0027: 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_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)
VectorLF3 val3 = a.planet.uPosition - playerPos;
double sqrMagnitude = ((VectorLF3)(ref val3)).sqrMagnitude;
val3 = b.planet.uPosition - playerPos;
return sqrMagnitude.CompareTo(((VectorLF3)(ref val3)).sqrMagnitude);
});
if (!CheckEnough(batch))
{
return null;
}
return batch;
}
private static bool TryGetContext(out Player player, out ItemProto item)
{
player = GameMain.mainPlayer;
item = ((ProtoSet<ItemProto>)(object)LDB.items).Select(2105);
Player obj = player;
if (((obj != null) ? obj.package : null) == null || GameMain.data == null)
{
UIRealtimeTip.Popup(Lang.T("游戏数据尚未加载", "Game data is not loaded yet"), true, 0);
return false;
}
if (item?.prefabDesc == null || !item.prefabDesc.isCollectStation)
{
UIRealtimeTip.Popup(Lang.T("找不到轨道采集器数据", "Orbital collector data not found"), true, 0);
return false;
}
return true;
}
private static bool CheckEnough(Batch batch)
{
if (batch.AvailableCount >= batch.NeededCount)
{
return true;
}
int recoverableCount = batch.RecoverableCount;
UIRealtimeTip.Popup((recoverableCount > 0) ? Lang.T($"轨道采集器不足:需要 {batch.NeededCount} 个,背包 {batch.packageCount} 个 + 拆除返还 {recoverableCount} 个", $"Not enough orbital collectors: need {batch.NeededCount}, have {batch.packageCount} in inventory + {recoverableCount} from removal") : Lang.T($"轨道采集器不足:需要 {batch.NeededCount} 个,背包中只有 {batch.packageCount} 个", $"Not enough orbital collectors: need {batch.NeededCount}, only {batch.packageCount} in inventory"), true, 0);
return false;
}
private static PlanetPlan PlanPlanet(Player player, PlanetData planet, ItemProto item, out PlanetStatus status)
{
//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
//IL_012e: Unknown result type (might be due to invalid IL or missing references)
PlanetFactory factory = planet.factory;
PlanetPlan planetPlan = new PlanetPlan
{
planet = planet,
factory = factory,
isLocal = (factory != null && factory == player.factory)
};
if (!CanCollectorWork(planet, item.prefabDesc))
{
status = PlanetStatus.NoPower;
return planetPlan;
}
List<ExistingCollector> list = ((factory != null) ? FindExistingCollectors(factory) : new List<ExistingCollector>());
planetPlan.existingCount = list.Count;
if (list.Count > 40)
{
status = PlanetStatus.TooMany;
return planetPlan;
}
List<Vector3> list2 = ChooseTargets(planet, list);
if (!TargetsAreFarEnough(list2))
{
status = PlanetStatus.TooSmall;
return planetPlan;
}
bool[] array = new bool[list2.Count];
foreach (ExistingCollector item2 in list)
{
int num = (item2.isEntity ? FindUnclaimedMatch(list2, array, item2.pos) : (-1));
if (num >= 0)
{
array[num] = true;
planetPlan.keptCount++;
continue;
}
planetPlan.dismantle.Add(item2);
if (item2.recoverable)
{
planetPlan.recoverableCount++;
}
}
for (int i = 0; i < list2.Count; i++)
{
if (!array[i])
{
planetPlan.missingTargets.Add(list2[i]);
}
}
status = PlanetStatus.Ok;
return planetPlan;
}
private static void Execute(Batch batch)
{
//IL_01ca: Unknown result type (might be due to invalid IL or missing references)
//IL_0146: Unknown result type (might be due to invalid IL or missing references)
//IL_014b: Unknown result type (might be due to invalid IL or missing references)
//IL_0157: Unknown result type (might be due to invalid IL or missing references)
Player player = batch.player;
ItemProto item = batch.item;
int num = TakeCollectors(player, ((Proto)item).ID, batch.ReservedFromPackage);
int num2 = 0;
foreach (PlanetPlan plan in batch.plans)
{
foreach (ExistingCollector item2 in plan.dismantle)
{
if (Dismantle(player, plan, item2))
{
num2++;
}
}
}
int neededCount = batch.NeededCount;
num += TakeCollectors(player, ((Proto)item).ID, neededCount - num);
int num3 = 0;
int num4 = 0;
foreach (PlanetPlan plan2 in batch.plans)
{
if (plan2.NeededCount == 0)
{
num4++;
continue;
}
if (num <= 0)
{
break;
}
PlanetFactory val = plan2.factory ?? CreateFactory(plan2.planet);
if (val == null)
{
ManualLogSource log = CollectorDeployerPlugin.Log;
if (log != null)
{
log.LogWarning((object)("Could not create a factory for " + plan2.planet.displayName));
}
continue;
}
foreach (Vector3 missingTarget in plan2.missingTargets)
{
if (num <= 0)
{
break;
}
if (BuildCollector(player, val, item, missingTarget))
{
num--;
num3++;
}
}
num4++;
}
if (num > 0)
{
player.TryAddItemToPackage(((Proto)item).ID, num, 0, true, 0, false);
}
if (num3 > 0 || num2 > 0)
{
VFAudio.Create("ui-click-2", (Transform)null, Vector3.zero, true, 7, -1, -1L);
}
int num5 = neededCount - num3;
if (num5 > 0)
{
UIRealtimeTip.Popup(Lang.T($"轨道采集器不足:已新建 {num3} 个,还差 {num5} 个", $"Not enough orbital collectors: built {num3}, {num5} missing"), true, 0);
}
else if (batch.plans.Count == 1)
{
UIRealtimeTip.Popup(Lang.T($"已部署 {40} 个轨道采集器", $"{40} orbital collectors deployed"), false, 0);
}
else
{
UIRealtimeTip.Popup(Lang.T($"已在 {num4} 颗气态巨星上部署轨道采集器,新建 {num3} 个", $"Deployed on {num4} gas giants, {num3} orbital collectors built"), false, 0);
}
ManualLogSource log2 = CollectorDeployerPlugin.Log;
if (log2 != null)
{
log2.LogInfo((object)$"Deploy: {batch.plans.Count} planet(s), built {num3}, dismantled {num2}, missing {Math.Max(0, num5)}");
}
}
private static int TakeCollectors(Player player, int itemId, int count)
{
if (count <= 0)
{
return 0;
}
int num = default(int);
player.package.TakeTailItems(ref itemId, ref count, ref num, false);
return count;
}
private static PlanetFactory CreateFactory(PlanetData planet)
{
GameData data = GameMain.data;
if (data.factoryCount >= data.factories.Length)
{
return null;
}
PlanetFactory orCreateFactory = data.GetOrCreateFactory(planet);
data.galaxy.astrosFactory[planet.id] = orCreateFactory;
return orCreateFactory;
}
private static bool BuildCollector(Player player, PlanetFactory factory, ItemProto item, Vector3 pos)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_000b: 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_003f: 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_0047: Unknown result type (might be due to invalid IL or missing references)
//IL_0048: Unknown result type (might be due to invalid IL or missing references)
//IL_004f: Unknown result type (might be due to invalid IL or missing references)
//IL_0050: Unknown result type (might be due to invalid IL or missing references)
//IL_0057: 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_0066: Unknown result type (might be due to invalid IL or missing references)
//IL_008c: Unknown result type (might be due to invalid IL or missing references)
Quaternion val = Maths.SphericalRotation(pos, 0f);
PrebuildData val2 = new PrebuildData
{
isDestroyed = false,
protoId = (short)((Proto)item).ID,
modelIndex = (short)item.prefabDesc.modelIndex,
pos = pos,
pos2 = pos,
rot = val,
rot2 = val
};
((PrebuildData)(ref val2)).InitParametersArray(0);
int num = factory.AddPrebuildDataWithComponents(val2);
if (num <= 0)
{
ManualLogSource log = CollectorDeployerPlugin.Log;
if (log != null)
{
log.LogWarning((object)$"AddPrebuildDataWithComponents failed on {factory.planet.displayName} at {pos}");
}
return false;
}
if (factory.planet.factoryLoaded)
{
factory.BuildFinally(player, num, true, true);
}
else
{
factory.BuildFinally(player, num, false, false);
}
return true;
}
private static bool Dismantle(Player player, PlanetPlan plan, ExistingCollector collector)
{
if (plan.isLocal)
{
return player.controller.actionBuild.DoDismantleObject(collector.objId);
}
PlanetFactory factory = plan.factory;
if (collector.recoverable)
{
ReturnItem(player, collector.protoId, 1, 0);
}
if (collector.isEntity && TryGetStation(factory, collector.objId, out var station))
{
for (int i = 0; i < station.storage.Length; i++)
{
ReturnItem(player, station.storage[i].itemId, station.storage[i].count, station.storage[i].inc);
station.storage[i].count = 0;
station.storage[i].inc = 0;
}
ReturnItem(player, 5001, station.idleDroneCount, 0);
ReturnItem(player, 5002, station.idleShipCount, 0);
ReturnItem(player, 1210, station.warperCount, 0);
station.idleDroneCount = 0;
station.idleShipCount = 0;
station.warperCount = 0;
}
int protoId = collector.protoId;
factory.DismantleFinally(player, collector.objId, ref protoId);
return true;
}
private static void ReturnItem(Player player, int itemId, int count, int inc)
{
if (itemId > 0 && count > 0)
{
int num = player.TryAddItemToPackage(itemId, count, inc, true, 0, false);
UIItemup.Up(itemId, num);
}
}
private static bool TryGetStation(PlanetFactory factory, int entityId, out StationComponent station)
{
station = null;
int stationId = factory.entityPool[entityId].stationId;
if (stationId <= 0 || stationId >= factory.transport.stationCursor)
{
return false;
}
station = factory.transport.stationPool[stationId];
if (station != null && station.id == stationId)
{
return station.storage != null;
}
return false;
}
private static Dictionary<int, int> PredictOverflow(Batch batch)
{
//IL_0030: 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_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_0046: Expected O, but got Unknown
//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
Dictionary<int, int> overflow = new Dictionary<int, int>();
if (batch.DismantleCount == 0)
{
return overflow;
}
Player player = batch.player;
StorageComponent package = player.package;
StorageComponent sim = new StorageComponent(package.size)
{
type = package.type
};
Array.Copy(package.grids, sim.grids, package.size);
int iD = ((Proto)batch.item).ID;
int reservedFromPackage = batch.ReservedFromPackage;
if (reservedFromPackage > 0)
{
int num = default(int);
sim.TakeTailItems(ref iD, ref reservedFromPackage, ref num, false);
}
Dictionary<int, int> deliveryFree = new Dictionary<int, int>();
DeliveryPackage deliveryPackage = player.deliveryPackage;
if (deliveryPackage != null && deliveryPackage.unlocked)
{
for (int i = 0; i < deliveryPackage.gridLength; i++)
{
int itemId = deliveryPackage.grids[i].itemId;
if (itemId > 0 && !deliveryFree.ContainsKey(itemId))
{
deliveryFree[itemId] = Math.Max(0, ((GRID)(ref deliveryPackage.grids[i])).stackSizeModified - deliveryPackage.grids[i].count);
}
}
}
foreach (PlanetPlan plan in batch.plans)
{
foreach (ExistingCollector item in plan.dismantle)
{
if (item.recoverable)
{
Add(item.protoId, 1);
}
if (item.isEntity && TryGetStation(plan.factory, item.objId, out var station))
{
StationStore[] storage = station.storage;
foreach (StationStore val in storage)
{
Add(val.itemId, val.count);
}
Add(5001, station.idleDroneCount);
Add(5002, station.idleShipCount);
Add(1210, station.warperCount);
}
}
}
return overflow;
void Add(int num2, int count)
{
if (num2 > 0 && count > 0 && num2 != 1099)
{
int num4 = default(int);
int num3 = count - sim.AddItemStacked(num2, count, 0, ref num4);
if (num3 > 0 && deliveryFree.TryGetValue(num2, out var value) && value > 0)
{
int num5 = Math.Min(value, num3);
deliveryFree[num2] = value - num5;
num3 -= num5;
}
if (num3 > 0)
{
overflow[num2] = (overflow.TryGetValue(num2, out var value2) ? value2 : 0) + num3;
}
}
}
}
private static string FormatItems(Dictionary<int, int> items)
{
return string.Join(Lang.T("、", ", "), items.Select((KeyValuePair<int, int> kv) => $"{ItemName(kv.Key)} ×{kv.Value}"));
}
private static string ItemName(int itemId)
{
ItemProto val = ((ProtoSet<ItemProto>)(object)LDB.items).Select(itemId);
if (val == null)
{
return itemId.ToString();
}
if (!string.IsNullOrEmpty(((Proto)val).name))
{
return ((Proto)val).name;
}
return Localization.Translate(((Proto)val).Name);
}
private static bool CanCollectorWork(PlanetData planet, PrefabDesc desc)
{
if (planet.gasItems == null || planet.gasItems.Length == 0)
{
return false;
}
double num = (double)desc.stationCollectSpeed * planet.gasTotalHeat;
if (num == 0.0)
{
return false;
}
return 1.0 - (double)desc.workEnergyPerTick / (num * (1.0 / 60.0)) > 0.0;
}
private static List<ExistingCollector> FindExistingCollectors(PlanetFactory factory)
{
//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_00f3: Unknown result type (might be due to invalid IL or missing references)
//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
List<ExistingCollector> list = new List<ExistingCollector>();
EntityData[] entityPool = factory.entityPool;
for (int i = 1; i < factory.entityCursor; i++)
{
if (entityPool[i].id == i && IsCollectorProto(entityPool[i].protoId))
{
list.Add(new ExistingCollector
{
objId = i,
protoId = entityPool[i].protoId,
pos = entityPool[i].pos,
recoverable = true,
isEntity = true
});
}
}
PrebuildData[] prebuildPool = factory.prebuildPool;
for (int j = 1; j < factory.prebuildCursor; j++)
{
if (prebuildPool[j].id == j && IsCollectorProto(prebuildPool[j].protoId))
{
list.Add(new ExistingCollector
{
objId = -j,
protoId = prebuildPool[j].protoId,
pos = prebuildPool[j].pos,
recoverable = (prebuildPool[j].itemRequired == 0),
isEntity = false
});
}
}
return list;
}
private static bool IsCollectorProto(int protoId)
{
ItemProto val = ((ProtoSet<ItemProto>)(object)LDB.items).Select(protoId);
if (val?.prefabDesc != null)
{
return val.prefabDesc.isCollectStation;
}
return false;
}
private static List<Vector3> ChooseTargets(PlanetData planet, List<ExistingCollector> existing)
{
PlanetGrid val = planet.aux?.mainGrid;
int num = val?.segment ?? ((int)(planet.radius / 4f + 0.1f) * 4);
int num2 = PlanetGrid.DetermineLongitudeSegmentCount(0, num) * 5;
bool flag = num2 > 0 && num2 % 40 == 0;
int num3 = ((!flag) ? 1 : (num2 / 40));
List<Vector3> result = null;
int num4 = -1;
for (int i = 0; i < num3; i++)
{
List<Vector3> list = ComputeTargets(planet, val, num2, flag, i);
int num5 = CountMatches(list, existing);
if (num5 > num4)
{
result = list;
num4 = num5;
}
}
return result;
}
private static List<Vector3> ComputeTargets(PlanetData planet, PlanetGrid grid, int gridPoints, bool alignedToGrid, int phase)
{
//IL_007c: 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_0081: Unknown result type (might be due to invalid IL or missing references)
//IL_0092: 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)
float num = planet.realRadius + 0.2f + planet.realRadius * 0.025f;
int num2 = (alignedToGrid ? (gridPoints / 40) : 0);
List<Vector3> list = new List<Vector3>(40);
for (int i = 0; i < 40; i++)
{
float num3 = (alignedToGrid ? ((float)(phase + i * num2) * ((float)Math.PI * 2f) / (float)gridPoints) : ((float)i * ((float)Math.PI * 2f) / 40f));
Vector3 val = (Vector3)((grid != null) ? grid.SnapTo(num3, 0f) : new Vector3(Mathf.Sin(num3), 0f, 0f - Mathf.Cos(num3)));
val.y = 0f;
list.Add(((Vector3)(ref val)).normalized * num);
}
return list;
}
private static int CountMatches(List<Vector3> targets, List<ExistingCollector> existing)
{
//IL_002a: Unknown result type (might be due to invalid IL or missing references)
bool[] array = new bool[targets.Count];
int num = 0;
foreach (ExistingCollector item in existing)
{
if (item.isEntity)
{
int num2 = FindUnclaimedMatch(targets, array, item.pos);
if (num2 >= 0)
{
array[num2] = true;
num++;
}
}
}
return num;
}
private static int FindUnclaimedMatch(List<Vector3> targets, bool[] claimed, Vector3 pos)
{
//IL_000b: 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_0011: Unknown result type (might be due to invalid IL or missing references)
//IL_0016: Unknown result type (might be due to invalid IL or missing references)
for (int i = 0; i < targets.Count; i++)
{
if (!claimed[i])
{
Vector3 val = targets[i] - pos;
if (((Vector3)(ref val)).sqrMagnitude < 1f)
{
return i;
}
}
}
return -1;
}
private static bool TargetsAreFarEnough(List<Vector3> targets)
{
//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_0017: 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_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)
for (int i = 0; i < targets.Count; i++)
{
Vector3 val = targets[(i + 1) % targets.Count];
Vector3 val2 = targets[i] - val;
if (((Vector3)(ref val2)).sqrMagnitude < 14297f)
{
return false;
}
}
return true;
}
}
[BepInPlugin("com.yummi.dsp.collectordeployer", "轨道采集器一键部署 (Collector Deployer)", "1.1.0")]
public class CollectorDeployerPlugin : BaseUnityPlugin
{
public const string PLUGIN_GUID = "com.yummi.dsp.collectordeployer";
public const string PLUGIN_NAME = "轨道采集器一键部署 (Collector Deployer)";
public const string PLUGIN_VERSION = "1.1.0";
private static readonly Harmony Harmony = new Harmony("com.yummi.dsp.collectordeployer");
internal static ManualLogSource Log;
internal static ConfigEntry<bool> EnableGalaxyDeploy;
private void Awake()
{
Log = ((BaseUnityPlugin)this).Logger;
EnableGalaxyDeploy = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EnableGalaxyDeploy", false, "Show a second button that deploys 40 orbital collectors on every gas giant in the galaxy, including ones you have never visited.\n显示第二个按钮,在全银河所有气态巨星(包括没去过的)上各部署 40 个轨道采集器。");
Harmony.PatchAll(typeof(UIFunctionPanelPatch));
Log.LogInfo((object)"轨道采集器一键部署 (Collector Deployer) v1.1.0 已加载");
}
private void OnDestroy()
{
UIFunctionPanelPatch.DestroyButtons();
Harmony.UnpatchSelf();
}
}
internal static class Lang
{
public static bool IsChinese
{
get
{
int currentLanguageLCID = Localization.CurrentLanguageLCID;
if (currentLanguageLCID != 2052)
{
return currentLanguageLCID == 1028;
}
return true;
}
}
public static string ButtonLabel => T("一键部署\n轨道采集器", "Deploy Orbital\nCollectors");
public static string TipTitle => T("一键部署轨道采集器", "Deploy Orbital Collectors");
public static string TipText => T($"在赤道上按格点均匀部署 {40} 个轨道采集器,不在格点上的会被拆除重建。", $"Deploys {40} orbital collectors evenly on the equator grid; off-grid ones are rebuilt.");
public static string GalaxyButtonLabel => T("一键部署\n全银河", "Deploy in\nWhole Galaxy");
public static string GalaxyTipTitle => T("全银河部署轨道采集器", "Deploy Orbital Collectors in the Whole Galaxy");
public static string GalaxyTipText => T($"在全银河所有气态巨星(包括没去过的)的赤道上各部署 {40} 个轨道采集器,执行前会显示汇总。", $"Deploys {40} orbital collectors on the equator of every gas giant in the galaxy, including unvisited ones. A summary is shown first.");
public static string T(string zh, string en)
{
if (!IsChinese)
{
return en;
}
return zh;
}
}
[HarmonyPatch(typeof(UIFunctionPanel))]
public static class UIFunctionPanelPatch
{
private sealed class DeployButton
{
public UIButton button;
public RectTransform rect;
public RectTransform widthRect;
public Text[] texts;
public int labelLcid = -1;
public Func<string> label;
public Func<string> tipTitle;
public Func<string> tipText;
}
private const float Gap = 8f;
private const int CollectorItemId = 2105;
private static DeployButton _local;
private static DeployButton _galaxy;
private static bool _createFailed;
private static readonly Vector3[] Corners = (Vector3[])(object)new Vector3[4];
[HarmonyPostfix]
[HarmonyPatch("_OnUpdate")]
public static void OnUpdate_Postfix(UIFunctionPanel __instance)
{
UIButton extractButton = __instance.extractButton;
if ((Object)(object)extractButton == (Object)null)
{
return;
}
if (_local == null || _galaxy == null)
{
if (_createFailed)
{
return;
}
CreateButtons(__instance);
if (_local == null || _galaxy == null)
{
return;
}
}
bool activeSelf = ((Component)extractButton).gameObject.activeSelf;
bool flag = activeSelf && CollectorDeployerPlugin.EnableGalaxyDeploy.Value;
SetActive(_local, activeSelf);
SetActive(_galaxy, flag);
if (activeSelf)
{
float width = SyncSizeAndGetWidth(__instance, _local);
RefreshLabel(_local);
int slot = 1;
if (flag)
{
SyncSizeAndGetWidth(__instance, _galaxy);
RefreshLabel(_galaxy);
Place(__instance, _galaxy, width, slot++);
}
Place(__instance, _local, width, slot);
}
}
internal static void DestroyButtons()
{
if ((Object)(object)_local?.button != (Object)null)
{
Object.Destroy((Object)(object)((Component)_local.button).gameObject);
}
if ((Object)(object)_galaxy?.button != (Object)null)
{
Object.Destroy((Object)(object)((Component)_galaxy.button).gameObject);
}
_local = null;
_galaxy = null;
}
private static void CreateButtons(UIFunctionPanel panel)
{
try
{
_local = CreateButton(panel, "collector-deployer-button", CollectorDeploy.RequestLocal, () => Lang.ButtonLabel, () => Lang.TipTitle, () => Lang.TipText);
_galaxy = CreateButton(panel, "collector-deployer-galaxy-button", CollectorDeploy.RequestGalaxy, () => Lang.GalaxyButtonLabel, () => Lang.GalaxyTipTitle, () => Lang.GalaxyTipText);
ManualLogSource log = CollectorDeployerPlugin.Log;
if (log != null)
{
log.LogDebug((object)("一键部署按钮已创建:\n" + DumpHierarchy(((Component)_local.button).transform, 0)));
}
}
catch (Exception arg)
{
_createFailed = true;
ManualLogSource log2 = CollectorDeployerPlugin.Log;
if (log2 != null)
{
log2.LogError((object)$"创建按钮失败: {arg}");
}
DestroyButtons();
}
}
private static DeployButton CreateButton(UIFunctionPanel panel, string name, Action onClick, Func<string> label, Func<string> tipTitle, Func<string> tipText)
{
//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
//IL_00f9: Expected O, but got Unknown
//IL_010c: Unknown result type (might be due to invalid IL or missing references)
//IL_0116: Expected O, but got Unknown
UIButton extractButton = panel.extractButton;
GameObject val = Object.Instantiate<GameObject>(((Component)extractButton).gameObject, ((Component)extractButton).transform.parent, false);
((Object)val).name = name;
Localizer[] componentsInChildren = val.GetComponentsInChildren<Localizer>(true);
for (int i = 0; i < componentsInChildren.Length; i++)
{
Object.Destroy((Object)(object)componentsInChildren[i]);
}
EventTrigger[] componentsInChildren2 = val.GetComponentsInChildren<EventTrigger>(true);
for (int i = 0; i < componentsInChildren2.Length; i++)
{
Object.Destroy((Object)(object)componentsInChildren2[i]);
}
DeployButton deployButton = new DeployButton
{
button = val.GetComponent<UIButton>(),
rect = val.GetComponent<RectTransform>(),
label = label,
tipTitle = tipTitle,
tipText = tipText
};
UIButton button = deployButton.button;
button.eventReceiver = null;
button.highlighted = false;
button.tips.itemId = 0;
if ((Object)(object)button.button != (Object)null)
{
button.button.onClick = new ButtonClickedEvent();
((UnityEvent)button.button.onClick).AddListener((UnityAction)delegate
{
onClick();
});
}
else
{
button.onClick += delegate
{
onClick();
};
}
ref RectTransform widthRect = ref deployButton.widthRect;
Transform obj = FindCounterpart(((Component)extractButton).transform, (Transform)(object)panel.extractButtonTrans, val.transform);
widthRect = (RectTransform)(((object)((obj is RectTransform) ? obj : null)) ?? ((object)deployButton.rect));
if ((Object)(object)panel.extractProgressImage != (Object)null)
{
Transform val2 = FindCounterpart(((Component)extractButton).transform, ((Component)panel.extractProgressImage).transform, val.transform);
if (val2 != null)
{
Image component = ((Component)val2).GetComponent<Image>();
if (component != null)
{
component.fillAmount = 0f;
((Behaviour)component).enabled = false;
}
}
}
deployButton.texts = val.GetComponentsInChildren<Text>(true);
SetIcon(val);
val.SetActive(false);
return deployButton;
}
private static void SetActive(DeployButton b, bool active)
{
if (((Component)b.button).gameObject.activeSelf != active)
{
((Component)b.button).gameObject.SetActive(active);
}
}
private static void RefreshLabel(DeployButton b)
{
int currentLanguageLCID = Localization.CurrentLanguageLCID;
if (currentLanguageLCID == b.labelLcid)
{
return;
}
b.labelLcid = currentLanguageLCID;
string text = b.label();
Text[] texts = b.texts;
if (texts != null && texts.Length != 0)
{
string[] array = text.Split(new char[1] { '\n' });
if (texts.Length >= array.Length && array.Length > 1)
{
for (int i = 0; i < texts.Length; i++)
{
texts[i].text = ((i < array.Length) ? array[i] : "");
}
}
else
{
texts[0].text = text;
for (int j = 1; j < texts.Length; j++)
{
texts[j].text = "";
}
}
}
b.button.tips.tipTitle = b.tipTitle();
b.button.tips.tipText = b.tipText();
}
private static float SyncSizeAndGetWidth(UIFunctionPanel panel, DeployButton b)
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
//IL_0011: Expected O, but got Unknown
//IL_0030: Unknown result type (might be due to invalid IL or missing references)
//IL_0077: Unknown result type (might be due to invalid IL or missing references)
//IL_007c: Unknown result type (might be due to invalid IL or missing references)
//IL_008d: Unknown result type (might be due to invalid IL or missing references)
//IL_0092: Unknown result type (might be due to invalid IL or missing references)
//IL_0054: Unknown result type (might be due to invalid IL or missing references)
RectTransform val = (RectTransform)((Component)panel.extractButton).transform;
RectTransform val2 = (((Object)(object)panel.extractButtonTrans != (Object)null) ? panel.extractButtonTrans : val);
b.rect.sizeDelta = val.sizeDelta;
if ((Object)(object)b.widthRect != (Object)(object)b.rect)
{
b.widthRect.sizeDelta = val2.sizeDelta;
}
Transform parent = ((Transform)val).parent;
val2.GetWorldCorners(Corners);
return parent.InverseTransformPoint(Corners[2]).x - parent.InverseTransformPoint(Corners[0]).x;
}
private static void Place(UIFunctionPanel panel, DeployButton b, float width, int slot)
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
//IL_0011: Expected O, but got Unknown
//IL_0018: Unknown result type (might be due to invalid IL or missing references)
//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)
RectTransform val = (RectTransform)((Component)panel.extractButton).transform;
b.rect.anchoredPosition = val.anchoredPosition - new Vector2((width + 8f) * (float)slot, 0f);
}
private static void SetIcon(GameObject go)
{
ItemProto val = ((ProtoSet<ItemProto>)(object)LDB.items).Select(2105);
if ((Object)(object)((val != null) ? val.iconSprite : null) == (Object)null)
{
return;
}
Image[] componentsInChildren = go.GetComponentsInChildren<Image>(true);
foreach (Image val2 in componentsInChildren)
{
if (((Object)val2).name.ToLowerInvariant().Contains("icon"))
{
val2.sprite = val.iconSprite;
}
}
}
private static Transform FindCounterpart(Transform srcRoot, Transform srcTarget, Transform cloneRoot)
{
if ((Object)(object)srcTarget == (Object)null)
{
return null;
}
if ((Object)(object)srcTarget == (Object)(object)srcRoot)
{
return cloneRoot;
}
if (!srcTarget.IsChildOf(srcRoot))
{
return null;
}
List<int> list = new List<int>();
Transform val = srcTarget;
while ((Object)(object)val != (Object)(object)srcRoot)
{
list.Add(val.GetSiblingIndex());
val = val.parent;
}
Transform val2 = cloneRoot;
for (int num = list.Count - 1; num >= 0; num--)
{
if (list[num] >= val2.childCount)
{
return null;
}
val2 = val2.GetChild(list[num]);
}
return val2;
}
private static string DumpHierarchy(Transform t, int depth)
{
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.Append(' ', depth * 2).Append(((Object)t).name);
Component[] components = ((Component)t).GetComponents<Component>();
foreach (Component val in components)
{
stringBuilder.Append(" [").Append(((object)val).GetType().Name).Append(']');
}
stringBuilder.Append('\n');
for (int j = 0; j < t.childCount; j++)
{
stringBuilder.Append(DumpHierarchy(t.GetChild(j), depth + 1));
}
return stringBuilder.ToString();
}
}
}