using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("0.0.0.0")]
namespace DspBlueprintEdit;
internal static class BeltAnalyzer
{
internal class Chain
{
public List<BlueprintBuilding> Belts = new List<BlueprintBuilding>();
public bool HeadConnected;
public bool TailConnected;
public bool IsStraight;
public int Length => Belts.Count;
public bool FullyDangling => !HeadConnected && !TailConnected;
public bool HalfDangling => HeadConnected ^ TailConnected;
}
internal const int BeltMin = 2001;
internal const int BeltMax = 2003;
internal static bool IsBelt(BlueprintBuilding b)
{
return b != null && b.itemId >= 2001 && b.itemId <= 2003;
}
internal static List<Chain> BuildChains(BlueprintData data)
{
List<Chain> list = new List<Chain>();
if (data?.buildings == null)
{
return list;
}
HashSet<BlueprintBuilding> hashSet = new HashSet<BlueprintBuilding>();
BlueprintBuilding[] buildings = data.buildings;
foreach (BlueprintBuilding val in buildings)
{
if (val == null || !IsBelt(val) || hashSet.Contains(val))
{
continue;
}
BlueprintBuilding val2 = val;
while (val2.inputObj != null && IsBelt(val2.inputObj) && !hashSet.Contains(val2.inputObj))
{
val2 = val2.inputObj;
if (val2 == val)
{
break;
}
}
Chain chain = new Chain();
BlueprintBuilding val3 = val2;
float yaw = val2.yaw;
bool isStraight = true;
while (val3 != null && IsBelt(val3) && !chain.Belts.Contains(val3))
{
chain.Belts.Add(val3);
hashSet.Add(val3);
if (Mathf.Abs(Mathf.DeltaAngle(val3.yaw, yaw)) > 2f)
{
isStraight = false;
}
val3 = val3.outputObj;
}
chain.IsStraight = isStraight;
BlueprintBuilding val4 = chain.Belts[0];
BlueprintBuilding val5 = chain.Belts[chain.Belts.Count - 1];
chain.HeadConnected = val4.inputObj != null && !IsBelt(val4.inputObj);
chain.TailConnected = val5.outputObj != null && !IsBelt(val5.outputObj);
list.Add(chain);
}
return list;
}
internal static string StatsText(BlueprintData data, List<Chain> chains)
{
int num = data.buildings.Count(IsBelt);
Chain chain = ((chains.Count > 0) ? chains.OrderByDescending((Chain c) => c.Length).First() : null);
int num2 = chains.Count((Chain c) => c.FullyDangling);
int num3 = chains.Count((Chain c) => c.HalfDangling);
string text = $"传送带总数: {num} 链数: {chains.Count}\n";
text += $"两端悬空链: {num2} 单端悬空链: {num3}\n";
if (chain != null)
{
BlueprintBuilding val = chain.Belts[0];
BlueprintBuilding val2 = chain.Belts[chain.Length - 1];
text = text + $"最长链距离: {chain.Length} 格带 " + $"(起点 {val.localOffset_x:F1},{val.localOffset_z:F1} → 终点 {val2.localOffset_x:F1},{val2.localOffset_z:F1})" + (chain.IsStraight ? " [直线]" : " [弯折]");
}
return text;
}
private static void RemoveBuilding(BlueprintBuilding b, BlueprintData data)
{
BlueprintBuilding[] buildings = data.buildings;
foreach (BlueprintBuilding val in buildings)
{
if (val != null && val != b)
{
if (val.outputObj == b)
{
val.outputObj = null;
}
if (val.inputObj == b)
{
val.inputObj = null;
}
}
}
b.outputObj = null;
b.inputObj = null;
b.index = -1;
}
internal static int RemoveDanglingChains(BlueprintData data, List<Chain> chains)
{
int num = 0;
foreach (Chain chain in chains)
{
if (!chain.FullyDangling)
{
continue;
}
foreach (BlueprintBuilding belt in chain.Belts)
{
RemoveBuilding(belt, data);
num++;
}
}
return num;
}
internal static int TrimHalfDanglingChains(BlueprintData data, List<Chain> chains, int keepCells)
{
if (keepCells < 1)
{
keepCells = 1;
}
int num = 0;
foreach (Chain chain in chains)
{
if (!chain.HalfDangling || chain.Length <= keepCells)
{
continue;
}
List<BlueprintBuilding> list = ((!chain.TailConnected) ? chain.Belts.Skip(keepCells).ToList() : chain.Belts.Take(chain.Length - keepCells).ToList());
foreach (BlueprintBuilding item in list)
{
RemoveBuilding(item, data);
num++;
}
}
return num;
}
}
internal static class BpeEditor
{
internal static UIBlueprintInspector TargetInspector;
private static bool _open;
private static Rect _winRect = new Rect(240f, 120f, 760f, 640f);
private static Vector2 _listScroll;
private static string _status = "";
private static string _undoBase64;
private static string _filterText = "";
private static int _keepCells = 1;
private static bool _showBeltsOnly;
private static BlueprintData Data => ((Object)(object)TargetInspector != (Object)null) ? TargetInspector.blueprint : null;
internal static void Toggle()
{
if (_open)
{
Close();
}
else if ((Object)(object)TargetInspector != (Object)null && TargetInspector.blueprint != null)
{
Open(TargetInspector);
}
}
internal static void Open(UIBlueprintInspector inspector)
{
TargetInspector = inspector;
if (inspector?.blueprint == null || !inspector.blueprint.isValid)
{
_status = "当前没有可编辑的蓝图";
return;
}
_undoBase64 = inspector.blueprint.ToBase64String();
_open = true;
_status = "已载入蓝图(原始内容已备份,可一键撤销)";
}
internal static void Close()
{
_open = false;
}
internal static void DrawGUI()
{
//IL_0038: Unknown result type (might be due to invalid IL or missing references)
//IL_0044: Unknown result type (might be due to invalid IL or missing references)
//IL_0058: Expected O, but got Unknown
//IL_0053: 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 (_open)
{
if (Data == null || !Data.isValid)
{
Close();
}
else
{
_winRect = GUILayout.Window(9527, _winRect, new WindowFunction(WindowFn), "蓝图编辑器 DspBlueprintEdit", Array.Empty<GUILayoutOption>());
}
}
}
private static void WindowFn(int id)
{
//IL_02e0: Unknown result type (might be due to invalid IL or missing references)
//IL_0302: Unknown result type (might be due to invalid IL or missing references)
//IL_0307: Unknown result type (might be due to invalid IL or missing references)
//IL_044e: Unknown result type (might be due to invalid IL or missing references)
//IL_0455: Expected O, but got Unknown
//IL_0462: Unknown result type (might be due to invalid IL or missing references)
//IL_04ef: Unknown result type (might be due to invalid IL or missing references)
//IL_04f6: Expected O, but got Unknown
//IL_04fd: Unknown result type (might be due to invalid IL or missing references)
//IL_0503: Invalid comparison between Unknown and I4
//IL_0588: Unknown result type (might be due to invalid IL or missing references)
BlueprintData data = Data;
if (data == null || data.buildings == null)
{
Close();
return;
}
GUILayout.Label($"名称: {data.shortDesc} 作者: {data.author} 建筑数: {data.buildings.Length}", Array.Empty<GUILayoutOption>());
GUILayout.Label("简介: " + (string.IsNullOrEmpty(data.desc) ? "-" : data.desc), Array.Empty<GUILayoutOption>());
GUILayout.Space(6f);
GUILayout.Label("—— 传送带分析(自动判定最长距离 / 省带子)——", GUI.skin.box, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) });
List<BeltAnalyzer.Chain> chains;
try
{
chains = BeltAnalyzer.BuildChains(data);
}
catch (Exception ex)
{
chains = new List<BeltAnalyzer.Chain>();
GUILayout.Label("链分析失败: " + ex.Message, Array.Empty<GUILayoutOption>());
}
GUILayout.Label(BeltAnalyzer.StatsText(data, chains), Array.Empty<GUILayoutOption>());
GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
if (GUILayout.Button("删除两端悬空的整条带链", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(200f) }))
{
int num = BeltAnalyzer.RemoveDanglingChains(data, chains);
ApplyChanges();
_status = $"已删除 {num} 条悬空传送带";
}
GUILayout.Label("单端悬空链保留格数:", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(110f) });
string s = GUILayout.TextField(_keepCells.ToString(), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(40f) });
int.TryParse(s, out _keepCells);
if (_keepCells < 1)
{
_keepCells = 1;
}
if (GUILayout.Button("截短单端悬空带链(省带子)", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(200f) }))
{
int num2 = BeltAnalyzer.TrimHalfDanglingChains(data, chains, _keepCells);
ApplyChanges();
_status = $"已截短删除 {num2} 条多余传送带";
}
GUILayout.EndHorizontal();
GUILayout.Space(6f);
GUILayout.Label("—— 建筑列表 ——", GUI.skin.box, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) });
GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
GUILayout.Label("过滤:", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(36f) });
_filterText = GUILayout.TextField(_filterText, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(200f) });
_showBeltsOnly = GUILayout.Toggle(_showBeltsOnly, "只看传送带", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(90f) });
if (GUILayout.Button("清除", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(50f) }))
{
_filterText = "";
_showBeltsOnly = false;
}
GUILayout.EndHorizontal();
_listScroll = GUILayout.BeginScrollView(_listScroll, GUI.skin.box, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(260f) });
List<KeyValuePair<string, int>> list = ItemSummary(data);
foreach (KeyValuePair<string, int> item in list)
{
if (string.IsNullOrEmpty(_filterText) || item.Key.IndexOf(_filterText, StringComparison.OrdinalIgnoreCase) >= 0)
{
GUILayout.Label($" {item.Key} ×{item.Value}", Array.Empty<GUILayoutOption>());
}
}
GUILayout.EndScrollView();
GUILayout.Space(6f);
GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
if (GUILayout.Button("应用修改到蓝图", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(130f) }))
{
ApplyChanges();
_status = "修改已应用,记得在蓝图界面点保存/使用";
}
if (GUILayout.Button("导出到剪贴板", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(120f) }))
{
GUIUtility.systemCopyBuffer = data.ToBase64String();
_status = "蓝图 Base64 已复制到剪贴板";
}
if (GUILayout.Button("从剪贴板导入", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(120f) }))
{
string systemCopyBuffer = GUIUtility.systemCopyBuffer;
BlueprintData val = new BlueprintData();
if (!string.IsNullOrEmpty(systemCopyBuffer) && (int)val.FromBase64String(systemCopyBuffer) == 0 && val.isValid)
{
val.time = data.time;
TargetInspector.blueprint = val;
_undoBase64 = data.ToBase64String();
RefreshInspector();
_status = "已从剪贴板导入蓝图";
}
else
{
_status = "剪贴板内容不是有效蓝图";
}
}
if (GUILayout.Button("撤销全部修改", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(120f) }) && _undoBase64 != null)
{
BlueprintData val2 = new BlueprintData();
if ((int)val2.FromBase64String(_undoBase64) == 0)
{
TargetInspector.blueprint = val2;
RefreshInspector();
_status = "已恢复原始蓝图";
}
}
if (GUILayout.Button("关闭", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(60f) }))
{
Close();
}
GUILayout.EndHorizontal();
GUILayout.Space(4f);
GUILayout.Label(_status, Array.Empty<GUILayoutOption>());
GUI.DragWindow(new Rect(0f, 0f, 10000f, 20f));
}
private static List<KeyValuePair<string, int>> ItemSummary(BlueprintData data)
{
Dictionary<string, int> dictionary = new Dictionary<string, int>();
BlueprintBuilding[] buildings = data.buildings;
foreach (BlueprintBuilding val in buildings)
{
if (val != null && (!_showBeltsOnly || BeltAnalyzer.IsBelt(val)))
{
string key = ItemName(val.itemId);
dictionary.TryGetValue(key, out var value);
dictionary[key] = value + 1;
}
}
return dictionary.OrderByDescending((KeyValuePair<string, int> kv) => kv.Value).ToList();
}
private static string ItemName(int itemId)
{
ItemProto val = ((ProtoSet<ItemProto>)(object)LDB.items).Select(itemId);
if (val == null)
{
return $"物品#{itemId}";
}
string text = ((Proto)val).name;
try
{
text = Localization.Translate(text);
}
catch
{
}
return string.IsNullOrEmpty(text) ? $"物品#{itemId}" : text;
}
private static void ApplyChanges()
{
BlueprintData data = Data;
if (data != null)
{
try
{
data.CheckBuildingData();
}
catch (Exception ex)
{
Plugin.L.LogWarning((object)("CheckBuildingData: " + ex.Message));
}
RefreshInspector();
}
}
private static void RefreshInspector()
{
UIBlueprintInspector targetInspector = TargetInspector;
if ((Object)(object)targetInspector == (Object)null)
{
return;
}
try
{
typeof(UIBlueprintInspector).GetMethod("Refresh", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[3]
{
typeof(bool),
typeof(bool),
typeof(bool)
}, null)?.Invoke(targetInspector, new object[3] { false, true, true });
}
catch (Exception ex)
{
Plugin.L.LogWarning((object)("刷新蓝图界面失败: " + ex.Message));
}
}
}
[BepInPlugin("byboy.dspblueprintedit", "DspBlueprintEdit", "0.1.0")]
public class Plugin : BaseUnityPlugin
{
internal static ManualLogSource L;
public static Plugin Instance;
private void Awake()
{
//IL_0017: Unknown result type (might be due to invalid IL or missing references)
L = ((BaseUnityPlugin)this).Logger;
Instance = this;
new Harmony("byboy.dspblueprintedit").PatchAll(Assembly.GetExecutingAssembly());
L.LogInfo((object)"DspBlueprintEdit 已加载:蓝图界面点「修改蓝图」或按 F10 打开编辑器");
}
private void Update()
{
if (Input.GetKeyDown((KeyCode)291) && (Object)(object)BpeEditor.TargetInspector != (Object)null && ((ManualBehaviour)BpeEditor.TargetInspector).active)
{
BpeEditor.Toggle();
}
}
private void OnGUI()
{
BpeEditor.DrawGUI();
}
}
[HarmonyPatch(typeof(UIBlueprintInspector), "_OnOpen")]
internal static class InspectorOpenPatch
{
private static void Postfix(UIBlueprintInspector __instance)
{
try
{
AddEditButton(__instance);
BpeEditor.TargetInspector = __instance;
}
catch (Exception ex)
{
Plugin.L.LogError((object)("注入修改蓝图按钮失败: " + ex));
}
}
internal static void AddEditButton(UIBlueprintInspector inspector)
{
//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_00d7: Unknown result type (might be due to invalid IL or missing references)
//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
//IL_01ab: Expected O, but got Unknown
if ((Object)(object)inspector == (Object)null || (Object)(object)inspector.copyBtnTrans == (Object)null)
{
return;
}
Transform val = ((Transform)inspector.copyBtnTrans).parent.Find("BpeEditBtn");
if ((Object)(object)val != (Object)null)
{
return;
}
GameObject val2 = Object.Instantiate<GameObject>(((Component)inspector.copyBtnTrans).gameObject, ((Transform)inspector.copyBtnTrans).parent);
((Object)val2).name = "BpeEditBtn";
val2.transform.localScale = Vector3.one;
Transform transform = val2.transform;
RectTransform val3 = (RectTransform)(object)((transform is RectTransform) ? transform : null);
val3.anchoredPosition = inspector.copyBtnTrans.anchoredPosition + new Vector2(0f, -38f);
Text[] componentsInChildren = val2.GetComponentsInChildren<Text>(true);
for (int i = 0; i < componentsInChildren.Length; i++)
{
if (((Object)((Component)componentsInChildren[i]).gameObject).name.Contains("text") || ((Object)((Component)componentsInChildren[i]).gameObject).name.Contains("Text") || i == 0)
{
componentsInChildren[i].text = "修改蓝图";
componentsInChildren[i].fontSize = Mathf.Max(componentsInChildren[i].fontSize - 2, 10);
break;
}
}
Button component = val2.GetComponent<Button>();
((UnityEventBase)component.onClick).RemoveAllListeners();
((UnityEvent)component.onClick).AddListener((UnityAction)delegate
{
if (inspector.blueprint != null && inspector.blueprint.isValid)
{
BpeEditor.Open(inspector);
}
});
Plugin.L.LogInfo((object)"已为蓝图界面添加「修改蓝图」按钮");
}
}