using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("DSPBlueprintTools")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.3.4.0")]
[assembly: AssemblyInformationalVersion("1.3.4")]
[assembly: AssemblyProduct("DSPBlueprintTools")]
[assembly: AssemblyTitle("DSPBlueprintTools")]
[assembly: AssemblyVersion("1.3.4.0")]
namespace DSPBlueprintTools;
[BepInPlugin("dsp.byboy.blueprinttools", "DSPBlueprintTools", "1.3.4")]
public class BlueprintToolsPlugin : BaseUnityPlugin
{
public const string GUID = "dsp.byboy.blueprinttools";
public const string NAME = "DSPBlueprintTools";
public const string VERSION = "1.3.4";
private const int MaxBlueprintBuildings = 15000;
private const int BeltItemId = 2001;
private ConfigEntry<string> _hotkeyEntry;
private ConfigEntry<float> _maxBeltLengthEntry;
private ConfigEntry<bool> _autoBeltLatEntry;
private KeyCode _mainKey = (KeyCode)52;
private KeyCode[] _modifierKeys = (KeyCode[])(object)new KeyCode[1] { (KeyCode)308 };
private bool _showWindow;
private Rect _winRect = new Rect(120f, 100f, 430f, 560f);
private Vector2 _scroll;
private string _status = "按快捷键打开/关闭本窗口";
private BlueprintData _bp;
private string _bpDesc = "(未载入蓝图)";
private string _beltStat = "";
private string _ox = "0.0000";
private string _oy = "0.0000";
private string _oz = "0.0000";
private string _offCount = "1";
private string _layers = "2";
private string _layerHeight = "10.0000";
private string _sx = "1.0000";
private string _sy = "1.0000";
private string _sz = "1.0000";
private string _rotDeg = "0";
private string _replaceFrom = "";
private string _replaceTo = "";
private UIBlueprintInspector _inspector;
private float _nextInjectTry;
private bool _readBtnCreated;
private FieldInfo _fiCopyBtnTrans;
private FieldInfo _fiCopyBtnText;
private FieldInfo _fiPasteTool;
private bool _uiRefsResolved;
private static bool IsBelt(BlueprintBuilding b)
{
if (b.itemId == 2001)
{
return true;
}
try
{
ModelProto val = ((ProtoSet<ModelProto>)(object)LDB.models).Select((int)b.modelIndex);
return val != null && val.prefabDesc != null && val.prefabDesc.isBelt;
}
catch
{
return false;
}
}
private void Awake()
{
_hotkeyEntry = ((BaseUnityPlugin)this).Config.Bind<string>("通用", "快捷键", "LeftAlt + Alpha4", "打开/关闭蓝图工具窗口的快捷键。格式:修饰键 + 主键,用 + 分隔。键名使用 UnityEngine.KeyCode 枚举名,例如:LeftAlt + Alpha4、LeftControl + F8、None + F9(无修饰键)。");
_hotkeyEntry.SettingChanged += delegate
{
ParseHotkey();
};
ParseHotkey();
_maxBeltLengthEntry = ((BaseUnityPlugin)this).Config.Bind<float>("传送带", "单段最大长度", 1.8f, "传送带合并最长化时允许的单段最大长度(小数点后 4 位)。实测原版可放置上限随纬度变化:赤道约 1.8,极地约 1.6,超过则无法摆放。默认 1.8。");
_autoBeltLatEntry = ((BaseUnityPlugin)this).Config.Bind<bool>("传送带", "按纬度自动适配上限", true, "开启后按蓝图区域纬度自动收紧上限(赤道 1.8 → 极地 1.6,线性过渡),关闭则始终使用上面配置的固定上限。");
_status = "快捷键:" + _hotkeyEntry.Value;
}
private void ParseHotkey()
{
//IL_0007: 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_0074: Unknown result type (might be due to invalid IL or missing references)
//IL_0075: 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_005c: Unknown result type (might be due to invalid IL or missing references)
//IL_0056: Unknown result type (might be due to invalid IL or missing references)
//IL_0058: Unknown result type (might be due to invalid IL or missing references)
List<KeyCode> list = new List<KeyCode>();
KeyCode val = (KeyCode)0;
string[] array = _hotkeyEntry.Value.Split('+');
for (int i = 0; i < array.Length; i++)
{
string text = array[i].Trim();
if (text.Length != 0 && !string.Equals(text, "None", StringComparison.OrdinalIgnoreCase) && Enum.TryParse<KeyCode>(text, ignoreCase: true, out KeyCode result))
{
if (i == array.Length - 1)
{
val = result;
}
else
{
list.Add(result);
}
}
}
if ((int)val == 0)
{
val = (KeyCode)52;
}
_mainKey = val;
_modifierKeys = list.ToArray();
}
private static bool ParseF4(string text, out float v)
{
if (float.TryParse(text, NumberStyles.Float, CultureInfo.InvariantCulture, out v))
{
v = (float)Math.Round(v, 4);
return true;
}
v = 0f;
return false;
}
private void Update()
{
//IL_0029: Unknown result type (might be due to invalid IL or missing references)
bool flag = true;
KeyCode[] modifierKeys = _modifierKeys;
for (int i = 0; i < modifierKeys.Length; i++)
{
if (!Input.GetKey(modifierKeys[i]))
{
flag = false;
break;
}
}
if (flag && Input.GetKeyDown(_mainKey))
{
_showWindow = !_showWindow;
}
if (!_readBtnCreated && Time.unscaledTime >= _nextInjectTry)
{
_nextInjectTry = Time.unscaledTime + 2f;
EnsureInspectorReadButton();
}
}
private void OnGUI()
{
//IL_0010: 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_0030: Expected O, but got Unknown
//IL_002b: Unknown result type (might be due to invalid IL or missing references)
//IL_0030: Unknown result type (might be due to invalid IL or missing references)
if (_showWindow)
{
_winRect = GUILayout.Window(17072, _winRect, new WindowFunction(DrawWindow), "蓝图工具 DSPBlueprintTools (v1.3.4)", Array.Empty<GUILayoutOption>());
}
}
private void EnsureInspectorReadButton()
{
//IL_014b: Unknown result type (might be due to invalid IL or missing references)
//IL_0150: Unknown result type (might be due to invalid IL or missing references)
//IL_0162: Unknown result type (might be due to invalid IL or missing references)
//IL_016b: Unknown result type (might be due to invalid IL or missing references)
//IL_0177: Unknown result type (might be due to invalid IL or missing references)
//IL_0183: Unknown result type (might be due to invalid IL or missing references)
//IL_018f: Unknown result type (might be due to invalid IL or missing references)
//IL_019b: 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_01b6: Unknown result type (might be due to invalid IL or missing references)
//IL_01bb: Unknown result type (might be due to invalid IL or missing references)
//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
//IL_01fd: Unknown result type (might be due to invalid IL or missing references)
//IL_0286: Unknown result type (might be due to invalid IL or missing references)
//IL_0290: Expected O, but got Unknown
//IL_029c: Unknown result type (might be due to invalid IL or missing references)
//IL_02a6: Expected O, but got Unknown
//IL_0243: 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_0265: Unknown result type (might be due to invalid IL or missing references)
//IL_0276: Unknown result type (might be due to invalid IL or missing references)
if (!_uiRefsResolved)
{
_fiCopyBtnTrans = typeof(UIBlueprintInspector).GetField("copyBtnTrans", BindingFlags.Instance | BindingFlags.NonPublic);
_fiCopyBtnText = typeof(UIBlueprintInspector).GetField("copyBtnText", BindingFlags.Instance | BindingFlags.NonPublic);
_fiPasteTool = typeof(UIBlueprintInspector).GetField("pasteBuildTool", BindingFlags.Instance | BindingFlags.NonPublic);
_uiRefsResolved = true;
}
if (_fiCopyBtnTrans == null || _fiCopyBtnText == null)
{
return;
}
try
{
_inspector = Object.FindObjectOfType<UIBlueprintInspector>();
}
catch
{
_inspector = null;
}
if ((Object)(object)_inspector == (Object)null)
{
return;
}
object? value = _fiCopyBtnTrans.GetValue(_inspector);
RectTransform val = (RectTransform)((value is RectTransform) ? value : null);
object? value2 = _fiCopyBtnText.GetValue(_inspector);
Text val2 = (Text)((value2 is Text) ? value2 : null);
if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null || !((Component)_inspector).gameObject.activeInHierarchy)
{
return;
}
Button component = ((Component)val).GetComponent<Button>();
Image component2 = ((Component)val).GetComponent<Image>();
if (!((Object)(object)component == (Object)null) && !((Object)(object)component2 == (Object)null))
{
GameObject val3 = new GameObject("DSPBlueprintTools_ReadBtn", new Type[3]
{
typeof(RectTransform),
typeof(Image),
typeof(Button)
});
val3.transform.SetParent(((Transform)val).parent, false);
RectTransform component3 = val3.GetComponent<RectTransform>();
component3.anchorMin = val.anchorMin;
component3.anchorMax = val.anchorMax;
component3.pivot = val.pivot;
component3.sizeDelta = val.sizeDelta;
component3.anchoredPosition = val.anchoredPosition - new Vector2(val.sizeDelta.x + 6f, 0f);
Image component4 = val3.GetComponent<Image>();
component4.sprite = component2.sprite;
component4.type = component2.type;
((Graphic)component4).color = new Color(0.65f, 0.92f, 1f, ((Graphic)component2).color.a);
GameObject obj2 = Object.Instantiate<GameObject>(((Component)val2).gameObject, (Transform)(object)component3, false);
((Object)obj2).name = "Text";
Text component5 = obj2.GetComponent<Text>();
if ((Object)(object)component5 != (Object)null)
{
component5.text = "读取";
((Graphic)component5).rectTransform.anchorMin = Vector2.zero;
((Graphic)component5).rectTransform.anchorMax = Vector2.one;
((Graphic)component5).rectTransform.offsetMin = Vector2.zero;
((Graphic)component5).rectTransform.offsetMax = Vector2.zero;
}
Button component6 = val3.GetComponent<Button>();
component6.onClick = new ButtonClickedEvent();
((UnityEvent)component6.onClick).AddListener((UnityAction)delegate
{
ReadFromClipboard();
_showWindow = true;
});
_readBtnCreated = true;
}
}
private void DrawWindow(int id)
{
//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
//IL_0380: Unknown result type (might be due to invalid IL or missing references)
GUILayout.BeginVertical(Array.Empty<GUILayoutOption>());
GUILayout.Label(_bpDesc, GUI.skin.box, Array.Empty<GUILayoutOption>());
GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
if (GUILayout.Button("从剪贴板读取蓝图", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(26f) }))
{
ReadFromClipboard();
}
if (GUILayout.Button("写回剪贴板", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(26f) }))
{
WriteToClipboard();
}
if (GUILayout.Button("应用/预览", (GUILayoutOption[])(object)new GUILayoutOption[2]
{
GUILayout.Height(26f),
GUILayout.Width(80f)
}))
{
ApplyToPasteTool();
}
GUILayout.EndHorizontal();
_scroll = GUILayout.BeginScrollView(_scroll, Array.Empty<GUILayoutOption>());
GUILayout.Label("── 1. 坐标偏移(小数点后 4 位)──", GUI.skin.box, Array.Empty<GUILayoutOption>());
DrawGridRow("X 偏移", ref _ox, "Y 偏移", ref _oy);
DrawGridRow("Z 偏移(高度)", ref _oz, "重复数量", ref _offCount);
GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
if (GUILayout.Button("偏移(净偏移 = 偏移量 × 数量)", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(24f) }))
{
DoOffset();
}
GUILayout.EndHorizontal();
GUILayout.Space(6f);
GUILayout.Label("── 2. 垂直叠加(层高精确到小数点后 4 位)──", GUI.skin.box, Array.Empty<GUILayoutOption>());
DrawGridRow("叠加层数", ref _layers, "每层高度", ref _layerHeight);
GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
if (GUILayout.Button("垂直叠加建筑层数", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(24f) }))
{
DoStack();
}
GUILayout.EndHorizontal();
GUILayout.Space(6f);
GUILayout.Label("── 3. 线性变换(批量设置建筑模型)──", GUI.skin.box, Array.Empty<GUILayoutOption>());
DrawGridRow("X 缩放", ref _sx, "Y 缩放", ref _sy);
DrawGridRow("Z 缩放", ref _sz, "旋转(度)", ref _rotDeg);
GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
if (GUILayout.Button("应用缩放/旋转", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(24f) }))
{
DoLinearTransform();
}
GUILayout.EndHorizontal();
GUILayout.Space(4f);
DrawGridRow("原建筑ID", ref _replaceFrom, "替换为ID", ref _replaceTo);
GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
if (GUILayout.Button("批量替换建筑型号", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(24f) }))
{
DoReplace();
}
GUILayout.FlexibleSpace();
GUILayout.EndHorizontal();
GUILayout.Space(6f);
GUILayout.Label("── 4. 传送带合并最长化(省带子)──", GUI.skin.box, Array.Empty<GUILayoutOption>());
GUILayout.Label(string.IsNullOrEmpty(_beltStat) ? "读取蓝图后自动探测传送带长度(合并以此为参考)" : _beltStat, Array.Empty<GUILayoutOption>());
GUILayout.Label("合并上限按纬度自动适配(赤道 1.8 / 极地 1.6,端点 0.5 格步进,配置文件可调)", Array.Empty<GUILayoutOption>());
GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
if (GUILayout.Button("传送带最长化", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(24f) }))
{
DoBeltMerge();
}
GUILayout.EndHorizontal();
GUILayout.Space(6f);
GUILayout.Label("提示:处理结果自动写回游戏剪贴板,可在蓝图粘贴界面直接使用;\"应用/预览\"会直接替换当前蓝图粘贴工具中的蓝图。", GUI.skin.label, Array.Empty<GUILayoutOption>());
GUILayout.EndScrollView();
GUILayout.Label(_status, Array.Empty<GUILayoutOption>());
GUILayout.EndVertical();
GUI.DragWindow(new Rect(0f, 0f, 10000f, 24f));
}
private static void DrawGridRow(string l1, ref string v1, string l2, ref string v2)
{
GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
GUILayout.Label(l1, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(80f) });
v1 = GUILayout.TextField(v1, Array.Empty<GUILayoutOption>());
GUILayout.Label(l2, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(80f) });
v2 = GUILayout.TextField(v2, Array.Empty<GUILayoutOption>());
GUILayout.EndHorizontal();
}
private unsafe void ReadFromClipboard()
{
//IL_002b: Unknown result type (might be due to invalid IL or missing references)
//IL_0030: Unknown result type (might be due to invalid IL or missing references)
//IL_0031: Unknown result type (might be due to invalid IL or missing references)
try
{
string systemCopyBuffer = GUIUtility.systemCopyBuffer;
if (string.IsNullOrEmpty(systemCopyBuffer))
{
_status = "剪贴板为空";
return;
}
BlueprintData val = BlueprintData.CreateNew();
BlueprintDataIOError val2 = val.FromBase64String(systemCopyBuffer.Trim());
if ((int)val2 != 0 || val.buildings == null)
{
_status = "读取失败:" + ((object)(*(BlueprintDataIOError*)(&val2))/*cast due to .constrained prefix*/).ToString();
_bp = null;
_bpDesc = "(未载入蓝图)";
}
else
{
_bp = val;
_bpDesc = $"已载入:{val.shortDesc} | 建筑 {val.buildings.Length} 个";
AnalyzeBelts();
_status = "从剪贴板读取成功";
}
}
catch (Exception ex)
{
_status = "读取异常:" + ex.Message;
}
}
private void WriteToClipboard()
{
if (_bp == null)
{
_status = "没有蓝图可写回";
return;
}
try
{
_bp.CheckBuildingData();
GUIUtility.systemCopyBuffer = _bp.ToBase64String();
_status = $"已写回剪贴板(建筑 {_bp.buildings.Length} 个)";
}
catch (Exception ex)
{
_status = "写回异常:" + ex.Message;
}
}
private void DoOffset()
{
if (!RequireBlueprint())
{
return;
}
if (!ParseF4(_ox, out var v) | !ParseF4(_oy, out var v2) | !ParseF4(_oz, out var v3) | !int.TryParse(_offCount, out var result))
{
_status = "输入格式错误(数值需为合法数字,数量需为整数)";
return;
}
if (result < 1)
{
result = 1;
}
try
{
BlueprintData val = _bp.Clone();
BlueprintBuilding[] buildings = val.buildings;
foreach (BlueprintBuilding obj in buildings)
{
obj.localOffset_x = R4(obj.localOffset_x + v * (float)result);
obj.localOffset_y = R4(obj.localOffset_y + v2 * (float)result);
obj.localOffset_z = R4(obj.localOffset_z + v3 * (float)result);
obj.localOffset_x2 = R4(obj.localOffset_x2 + v * (float)result);
obj.localOffset_y2 = R4(obj.localOffset_y2 + v2 * (float)result);
obj.localOffset_z2 = R4(obj.localOffset_z2 + v3 * (float)result);
}
Commit(val, $"坐标偏移完成:({v:F4}, {v2:F4}, {v3:F4}) × {result}");
}
catch (Exception ex)
{
_status = "偏移异常:" + ex.Message;
}
}
private void DoStack()
{
if (!RequireBlueprint())
{
return;
}
if (!int.TryParse(_layers, out var result) | !ParseF4(_layerHeight, out var v))
{
_status = "输入格式错误(层数需为整数,层高需为数字)";
return;
}
if (result < 1)
{
result = 1;
}
try
{
int num = _bp.buildings.Length;
if ((long)num * (long)result > 15000)
{
_status = $"叠加后建筑数 {num * result} 超过上限 {15000}";
return;
}
BlueprintData val = _bp.Clone();
List<BlueprintBuilding> list = new List<BlueprintBuilding>(val.buildings);
for (int i = 1; i < result; i++)
{
BlueprintData val2 = _bp.Clone();
BlueprintBuilding[] buildings = val2.buildings;
foreach (BlueprintBuilding obj in buildings)
{
obj.localOffset_z = R4(obj.localOffset_z + v * (float)i);
obj.localOffset_z2 = R4(obj.localOffset_z2 + v * (float)i);
}
list.AddRange(val2.buildings);
}
BlueprintBuilding[] array = list.ToArray();
for (int k = 0; k < array.Length; k++)
{
array[k].index = k;
}
val.buildings = array;
Commit(val, $"垂直叠加完成:{result} 层 × 层高 {v:F4},共 {array.Length} 个建筑");
}
catch (Exception ex)
{
_status = "叠加异常:" + ex.Message;
}
}
private void DoLinearTransform()
{
if (!RequireBlueprint())
{
return;
}
if (!ParseF4(_sx, out var v) | !ParseF4(_sy, out var v2) | !ParseF4(_sz, out var v3) | !float.TryParse(_rotDeg, NumberStyles.Float, CultureInfo.InvariantCulture, out var result))
{
_status = "输入格式错误";
return;
}
try
{
BlueprintData val = _bp.Clone();
double num = (double)result * Math.PI / 180.0;
double num2 = Math.Cos(num);
double num3 = Math.Sin(num);
BlueprintBuilding[] buildings = val.buildings;
foreach (BlueprintBuilding val2 in buildings)
{
float num4 = (float)Math.Round(val2.localOffset_x * v, 4);
float num5 = (float)Math.Round(val2.localOffset_y * v2, 4);
float localOffset_z = (float)Math.Round(val2.localOffset_z * v3, 4);
float num6 = (float)Math.Round(val2.localOffset_x2 * v, 4);
float num7 = (float)Math.Round(val2.localOffset_y2 * v2, 4);
float localOffset_z2 = (float)Math.Round(val2.localOffset_z2 * v3, 4);
if (Math.Abs(result) > 0.0001f)
{
float num8 = (float)Math.Round((double)num4 * num2 + (double)num5 * num3, 4);
float num9 = (float)Math.Round((double)(0f - num4) * num3 + (double)num5 * num2, 4);
num4 = num8;
num5 = num9;
float num10 = (float)Math.Round((double)num6 * num2 + (double)num7 * num3, 4);
float num11 = (float)Math.Round((double)(0f - num6) * num3 + (double)num7 * num2, 4);
num6 = num10;
num7 = num11;
val2.yaw = (float)Math.Round(val2.yaw + result, 4);
}
val2.localOffset_x = num4;
val2.localOffset_y = num5;
val2.localOffset_z = localOffset_z;
val2.localOffset_x2 = num6;
val2.localOffset_y2 = num7;
val2.localOffset_z2 = localOffset_z2;
}
Commit(val, $"线性变换完成:缩放({v:F4}, {v2:F4}, {v3:F4}),旋转 {result:F4}°");
}
catch (Exception ex)
{
_status = "变换异常:" + ex.Message;
}
}
private void DoReplace()
{
if (!RequireBlueprint())
{
return;
}
if (!short.TryParse(_replaceFrom.Trim(), out var result) || !short.TryParse(_replaceTo.Trim(), out var result2))
{
_status = "输入格式错误(建筑 ID 需为整数,如 2001 分拣器)";
return;
}
try
{
BlueprintData val = _bp.Clone();
int num = 0;
BlueprintBuilding[] buildings = val.buildings;
foreach (BlueprintBuilding val2 in buildings)
{
if (val2.itemId == result)
{
val2.itemId = result2;
val2.modelIndex = (short)((ProtoSet<ItemProto>)(object)LDB.items).Select((int)result2).ModelIndex;
num++;
}
}
Commit(val, $"批量替换完成:{num} 个建筑从 ID {result} 替换为 {result2}");
}
catch (Exception ex)
{
_status = "替换异常:" + ex.Message;
}
}
private void DoBeltMerge()
{
//IL_012c: 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)
if (!RequireBlueprint())
{
return;
}
try
{
float num = (float)Math.Round(_maxBeltLengthEntry.Value, 4);
if (num < 1f)
{
num = 1f;
}
BlueprintData val = _bp.Clone();
List<BlueprintBuilding> list = new List<BlueprintBuilding>();
List<BlueprintBuilding> list2 = new List<BlueprintBuilding>();
BlueprintBuilding[] buildings = val.buildings;
foreach (BlueprintBuilding val2 in buildings)
{
if (IsBelt(val2))
{
list2.Add(val2);
}
else
{
list.Add(val2);
}
}
if (list2.Count == 0)
{
_status = "蓝图中没有传送带( itemId=2001 )";
return;
}
HashSet<BlueprintBuilding> hashSet = new HashSet<BlueprintBuilding>();
List<BlueprintBuilding> list3 = new List<BlueprintBuilding>();
float latitudeRadPerGrid = BlueprintUtils.GetLatitudeRadPerGrid(200);
Dictionary<int, float> dictionary = new Dictionary<int, float>();
if (val.areas != null)
{
BlueprintArea[] areas = val.areas;
foreach (BlueprintArea val3 in areas)
{
dictionary[val3.index] = (float)val3.tropicAnchor * latitudeRadPerGrid;
}
}
float num2 = 0f;
foreach (BlueprintBuilding item in list2)
{
float num3 = Vector3.Distance(new Vector3(item.localOffset_x, item.localOffset_y, item.localOffset_z), new Vector3(item.localOffset_x2, item.localOffset_y2, item.localOffset_z2));
if (num3 > num2)
{
num2 = num3;
}
}
bool flag = num2 > 1.05f;
Dictionary<long, BlueprintBuilding> dictionary2 = new Dictionary<long, BlueprintBuilding>();
foreach (BlueprintBuilding item2 in list2)
{
if (!(BeltLen(item2) >= 0.0001f))
{
dictionary2[BeltCellKey(item2)] = item2;
}
}
foreach (BlueprintBuilding item3 in list2)
{
if (!hashSet.Contains(item3))
{
float num4 = ComputeBeltLimit(item3, dictionary, latitudeRadPerGrid, 2.3022f, 200, 200f);
if (!_autoBeltLatEntry.Value)
{
num4 = num;
}
if (flag)
{
num4 = Math.Min(num4, num2);
}
MergeBeltChain(item3, list2, dictionary2, hashSet, num4, list3);
}
}
BlueprintBuilding[] array = (BlueprintBuilding[])(object)new BlueprintBuilding[list.Count + list3.Count];
list.CopyTo(array, 0);
list3.CopyTo(array, list.Count);
for (int j = 0; j < array.Length; j++)
{
array[j].index = j;
}
val.buildings = array;
int num5 = list2.Count - list3.Count;
Commit(val, $"传送带最长化完成:{list2.Count} 段 → {list3.Count} 段,省下 {num5} 段带子" + (flag ? $"(按探测上限 {num2:F4})" : "(按纬度/高度自适应)"));
}
catch (Exception ex)
{
_status = "传送带合并异常:" + ex.Message;
}
}
private float ComputeBeltLimit(BlueprintBuilding b, Dictionary<int, float> areaLatRad, float latRadPerGrid, float maxWorldLen, int segmentCnt, float planetRadius)
{
try
{
float num = b.localOffset_x2 - b.localOffset_x;
float num2 = b.localOffset_y2 - b.localOffset_y;
float num3 = (float)Math.Sqrt(num * num + num2 * num2);
if (num3 < 0.0001f)
{
return 1.8f;
}
areaLatRad.TryGetValue(b.areaIndex, out var value);
value += b.localOffset_y * latRadPerGrid;
value = Mathf.Clamp(value, -MathF.PI / 2f, MathF.PI / 2f);
float num4 = 0.2f + 1.3333333f * Math.Max(0f, b.localOffset_z);
float num5 = planetRadius + num4;
float num6 = num5 * latRadPerGrid;
float num7 = num5 * BlueprintUtils.GetLongitudeRadPerGrid(value, segmentCnt);
float num8 = num / num3;
float num9 = num2 / num3;
float num10 = (float)Math.Sqrt(num8 * num8 * num7 * num7 + num9 * num9 * num6 * num6);
if (num10 < 0.0001f)
{
return 1.8f;
}
float num11 = maxWorldLen / num10;
if (float.IsNaN(num11) || num11 < 1f)
{
num11 = 1f;
}
return (float)Math.Round(num11, 4);
}
catch
{
return 1.8f;
}
}
private void MergeBeltChain(BlueprintBuilding start, List<BlueprintBuilding> belts, Dictionary<long, BlueprintBuilding> byPos, HashSet<BlueprintBuilding> used, float maxLen, List<BlueprintBuilding> output)
{
//IL_0113: Unknown result type (might be due to invalid IL or missing references)
//IL_0118: Unknown result type (might be due to invalid IL or missing references)
//IL_011a: Unknown result type (might be due to invalid IL or missing references)
//IL_011f: Unknown result type (might be due to invalid IL or missing references)
//IL_0120: Unknown result type (might be due to invalid IL or missing references)
//IL_0125: Unknown result type (might be due to invalid IL or missing references)
//IL_005d: Unknown result type (might be due to invalid IL or missing references)
//IL_0064: Unknown result type (might be due to invalid IL or missing references)
//IL_0069: Unknown result type (might be due to invalid IL or missing references)
//IL_006e: Unknown result type (might be due to invalid IL or missing references)
//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
//IL_01de: Unknown result type (might be due to invalid IL or missing references)
//IL_01e8: Unknown result type (might be due to invalid IL or missing references)
//IL_01ed: Unknown result type (might be due to invalid IL or missing references)
//IL_0233: Unknown result type (might be due to invalid IL or missing references)
//IL_0238: Unknown result type (might be due to invalid IL or missing references)
//IL_0245: Unknown result type (might be due to invalid IL or missing references)
//IL_0246: Unknown result type (might be due to invalid IL or missing references)
//IL_024c: Unknown result type (might be due to invalid IL or missing references)
//IL_0262: Unknown result type (might be due to invalid IL or missing references)
//IL_0263: Unknown result type (might be due to invalid IL or missing references)
//IL_0269: Unknown result type (might be due to invalid IL or missing references)
//IL_027f: Unknown result type (might be due to invalid IL or missing references)
//IL_0280: Unknown result type (might be due to invalid IL or missing references)
//IL_0286: Unknown result type (might be due to invalid IL or missing references)
//IL_029c: Unknown result type (might be due to invalid IL or missing references)
//IL_029d: Unknown result type (might be due to invalid IL or missing references)
//IL_02a3: Unknown result type (might be due to invalid IL or missing references)
//IL_02bc: Unknown result type (might be due to invalid IL or missing references)
//IL_02bd: Unknown result type (might be due to invalid IL or missing references)
//IL_02c3: Unknown result type (might be due to invalid IL or missing references)
//IL_02dc: Unknown result type (might be due to invalid IL or missing references)
//IL_02dd: Unknown result type (might be due to invalid IL or missing references)
//IL_02e3: Unknown result type (might be due to invalid IL or missing references)
//IL_02fc: Unknown result type (might be due to invalid IL or missing references)
//IL_0309: Unknown result type (might be due to invalid IL or missing references)
//IL_0316: Unknown result type (might be due to invalid IL or missing references)
//IL_0323: Unknown result type (might be due to invalid IL or missing references)
//IL_0330: Unknown result type (might be due to invalid IL or missing references)
//IL_033d: Unknown result type (might be due to invalid IL or missing references)
//IL_034f: Expected O, but got Unknown
bool flag = BeltLen(start) < 0.0001f;
List<BlueprintBuilding> list;
if (flag)
{
list = BuildPerCellRun(start, byPos, used);
}
else
{
list = new List<BlueprintBuilding> { start };
used.Add(start);
BlueprintBuilding val = start;
Vector3 val2;
while (true)
{
BlueprintBuilding outputObj = val.outputObj;
if (outputObj == null || !IsBelt(outputObj) || used.Contains(outputObj))
{
break;
}
val2 = P(outputObj) - P2(val);
if (((Vector3)(ref val2)).sqrMagnitude > 0.0004f)
{
break;
}
list.Add(outputObj);
used.Add(outputObj);
val = outputObj;
}
val = start;
while (true)
{
BlueprintBuilding inputObj = val.inputObj;
if (inputObj == null || !IsBelt(inputObj) || used.Contains(inputObj))
{
break;
}
val2 = P(val) - P2(inputObj);
if (((Vector3)(ref val2)).sqrMagnitude > 0.0004f)
{
break;
}
list.Insert(0, inputObj);
used.Add(inputObj);
val = inputObj;
}
}
if (flag)
{
List<BlueprintBuilding> chain = BuildPerCellRun(start, byPos, used);
MergePerCellChain(chain, maxLen, output);
return;
}
Vector3 val3 = P(start);
Vector3 val4 = P2(start) - val3;
float num = 0f;
foreach (BlueprintBuilding item in list)
{
num += BeltLen(item);
}
if (((Vector3)(ref val4)).sqrMagnitude < 1E-08f || num <= maxLen)
{
output.AddRange(list);
return;
}
int num2 = (int)Math.Round((double)num / 0.5);
int num3 = (int)Math.Floor((double)maxLen / 0.5);
if (num3 < 1 || num2 < 2)
{
output.AddRange(list);
return;
}
int num4 = (int)Math.Ceiling((double)num2 / (double)num3);
int num5 = num2 / num4;
int num6 = num2 % num4;
Vector3 val5 = ((Vector3)(ref val4)).normalized * 0.5f;
List<BlueprintBuilding> list2 = new List<BlueprintBuilding>();
int num7 = 0;
for (int i = 0; i < num4; i++)
{
int num8 = num5 + ((i < num6) ? 1 : 0);
BlueprintBuilding val6 = list[Math.Min((int)((double)num7 / (double)num2 * (double)list.Count), list.Count - 1)];
list2.Add(new BlueprintBuilding
{
areaIndex = val6.areaIndex,
localOffset_x = R4(val3.x + val5.x * (float)num7),
localOffset_y = R4(val3.y + val5.y * (float)num7),
localOffset_z = R4(val3.z + val5.z * (float)num7),
localOffset_x2 = R4(val3.x + val5.x * (float)(num7 + num8)),
localOffset_y2 = R4(val3.y + val5.y * (float)(num7 + num8)),
localOffset_z2 = R4(val3.z + val5.z * (float)(num7 + num8)),
pitch = val6.pitch,
yaw = val6.yaw,
tilt = val6.tilt,
itemId = val6.itemId,
modelIndex = val6.modelIndex,
filterId = val6.filterId
});
num7 += num8;
}
Rechain(list2, list);
output.AddRange(list2);
}
private void MergePerCellChain(List<BlueprintBuilding> chain, float maxLen, List<BlueprintBuilding> output)
{
//IL_001a: Unknown result type (might be due to invalid IL or missing references)
//IL_0026: Unknown result type (might be due to invalid IL or missing references)
//IL_002b: Unknown result type (might be due to invalid IL or missing references)
//IL_0030: Unknown result type (might be due to invalid IL or missing references)
//IL_0086: Unknown result type (might be due to invalid IL or missing references)
//IL_008b: Unknown result type (might be due to invalid IL or missing references)
//IL_004f: Unknown result type (might be due to invalid IL or missing references)
//IL_005b: Unknown result type (might be due to invalid IL or missing references)
//IL_0060: Unknown result type (might be due to invalid IL or missing references)
//IL_0065: Unknown result type (might be due to invalid IL or missing references)
//IL_01eb: Unknown result type (might be due to invalid IL or missing references)
//IL_01f0: Unknown result type (might be due to invalid IL or missing references)
//IL_01f4: Unknown result type (might be due to invalid IL or missing references)
//IL_01f9: Unknown result type (might be due to invalid IL or missing references)
//IL_01fe: Unknown result type (might be due to invalid IL or missing references)
//IL_0202: Unknown result type (might be due to invalid IL or missing references)
//IL_020b: Unknown result type (might be due to invalid IL or missing references)
int count = chain.Count;
if (count < 3)
{
output.AddRange(chain);
return;
}
Vector3 val = P(chain[1]) - P(chain[0]);
if (((Vector3)(ref val)).sqrMagnitude < 1E-06f && chain.Count > 2)
{
val = P(chain[2]) - P(chain[1]);
}
if (((Vector3)(ref val)).sqrMagnitude < 1E-06f)
{
output.AddRange(chain);
return;
}
float magnitude = ((Vector3)(ref val)).magnitude;
Vector3 normalized = ((Vector3)(ref val)).normalized;
HashSet<int> hashSet = new HashSet<int>
{
0,
count - 1
};
HashSet<BlueprintBuilding> hashSet2 = new HashSet<BlueprintBuilding>(chain);
for (int i = 0; i < count; i++)
{
BlueprintBuilding val2 = chain[i];
if ((val2.inputObj != null && !hashSet2.Contains(val2.inputObj)) || (val2.outputObj != null && !hashSet2.Contains(val2.outputObj)))
{
hashSet.Add(i);
}
}
List<int> list = hashSet.OrderBy((int x) => x).ToList();
List<BlueprintBuilding> list2 = new List<BlueprintBuilding>();
for (int num = 0; num < list.Count - 1; num++)
{
int num2 = list[num];
double num3 = (float)(list[num + 1] - num2) * magnitude;
list2.Add(chain[num2]);
if (!(num3 <= (double)maxLen))
{
double num4 = Math.Max(0.5, Math.Floor(Math.Min(maxLen, num3) * 2.0) / 2.0);
double num5 = Math.Ceiling(num3 / num4);
double num6 = num3 / num5;
for (int num7 = 1; num7 < (int)num5; num7++)
{
double num8 = num6 * (double)num7;
BlueprintBuilding val3 = CloneBelt(chain[num2 + (int)Math.Round(num8 / (double)magnitude)]);
Vector3 v = P(chain[num2]) + normalized * (float)num8;
SetP(val3, v);
SetP2(val3, v);
list2.Add(val3);
}
}
}
list2.Add(chain[count - 1]);
Rechain(list2, chain);
output.AddRange(list2);
}
private List<BlueprintBuilding> BuildPerCellRun(BlueprintBuilding start, Dictionary<long, BlueprintBuilding> byPos, HashSet<BlueprintBuilding> used)
{
List<BlueprintBuilding> list = new List<BlueprintBuilding> { start };
used.Add(start);
float z = start.localOffset_z;
float yaw = start.yaw;
int[][] array = new int[8][]
{
new int[2] { 1, 0 },
new int[2] { -1, 0 },
new int[2] { 0, 1 },
new int[2] { 0, -1 },
new int[2] { 1, 1 },
new int[2] { 1, -1 },
new int[2] { -1, 1 },
new int[2] { -1, -1 }
};
foreach (int[] array2 in array)
{
if (Neighbor(start, array2[0], array2[1]) == null)
{
continue;
}
BlueprintBuilding b = start;
while (true)
{
BlueprintBuilding val = Neighbor(b, array2[0], array2[1]);
if (val == null)
{
break;
}
list.Add(val);
used.Add(val);
b = val;
}
b = start;
while (true)
{
BlueprintBuilding val2 = Neighbor(b, -array2[0], -array2[1]);
if (val2 == null)
{
break;
}
list.Insert(0, val2);
used.Add(val2);
b = val2;
}
break;
}
return list;
BlueprintBuilding Neighbor(BlueprintBuilding val3, int dx, int dy)
{
long key = BeltCellKeyOf(Mathf.RoundToInt(val3.localOffset_x * 2f) + dx, Mathf.RoundToInt(val3.localOffset_y * 2f) + dy, z);
if (!byPos.TryGetValue(key, out var value) || used.Contains(value) || value.yaw != yaw)
{
return null;
}
return value;
}
}
private static long BeltCellKey(BlueprintBuilding b)
{
return BeltCellKeyOf(Mathf.RoundToInt(b.localOffset_x * 2f), Mathf.RoundToInt(b.localOffset_y * 2f), b.localOffset_z);
}
private static long BeltCellKeyOf(int x2, int y2, float z)
{
int num = (int)Mathf.Round(z * 0.75f);
return ((long)(x2 + 40000) << 42) | ((long)(y2 + 40000) << 20) | (uint)(num + 5000);
}
private static void Rechain(List<BlueprintBuilding> kept, List<BlueprintBuilding> chain)
{
if (kept.Count != 0)
{
for (int i = 0; i < kept.Count; i++)
{
kept[i].outputObj = ((i + 1 < kept.Count) ? kept[i + 1] : chain[chain.Count - 1].outputObj);
kept[i].inputObj = ((i > 0) ? kept[i - 1] : chain[0].inputObj);
}
}
}
private static Vector3 P(BlueprintBuilding b)
{
//IL_0012: Unknown result type (might be due to invalid IL or missing references)
return new Vector3(b.localOffset_x, b.localOffset_y, b.localOffset_z);
}
private static Vector3 P2(BlueprintBuilding b)
{
//IL_0012: Unknown result type (might be due to invalid IL or missing references)
return new Vector3(b.localOffset_x2, b.localOffset_y2, b.localOffset_z2);
}
private static void SetP(BlueprintBuilding b, Vector3 v)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0012: Unknown result type (might be due to invalid IL or missing references)
//IL_0023: Unknown result type (might be due to invalid IL or missing references)
b.localOffset_x = R4(v.x);
b.localOffset_y = R4(v.y);
b.localOffset_z = R4(v.z);
}
private static void SetP2(BlueprintBuilding b, Vector3 v)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0012: Unknown result type (might be due to invalid IL or missing references)
//IL_0023: Unknown result type (might be due to invalid IL or missing references)
b.localOffset_x2 = R4(v.x);
b.localOffset_y2 = R4(v.y);
b.localOffset_z2 = R4(v.z);
}
private static float BeltLen(BlueprintBuilding b)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
return Vector3.Distance(P(b), P2(b));
}
private static float CellDist(BlueprintBuilding a, BlueprintBuilding b)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
return Vector3.Distance(P(a), P(b));
}
private static float CellDistOf(BlueprintBuilding a, BlueprintBuilding b)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
return Vector3.Distance(P(a), P(b));
}
private static BlueprintBuilding CloneBelt(BlueprintBuilding src)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
//IL_0011: 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_0029: 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_0041: Unknown result type (might be due to invalid IL or missing references)
//IL_004d: Unknown result type (might be due to invalid IL or missing references)
//IL_0059: Unknown result type (might be due to invalid IL or missing references)
//IL_0066: Expected O, but got Unknown
return new BlueprintBuilding
{
areaIndex = src.areaIndex,
pitch = src.pitch,
yaw = src.yaw,
tilt = src.tilt,
itemId = src.itemId,
modelIndex = src.modelIndex,
filterId = src.filterId,
parameters = src.parameters
};
}
private void Commit(BlueprintData bp, string message)
{
bp.CheckBuildingData();
_bp = bp;
_bpDesc = $"当前蓝图 | 建筑 {bp.buildings.Length} 个";
AnalyzeBelts();
GUIUtility.systemCopyBuffer = bp.ToBase64String();
_status = message + ";已写回剪贴板";
}
private void AnalyzeBelts()
{
//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
_beltStat = "";
if (_bp?.buildings == null)
{
return;
}
int num = 0;
int num2 = 0;
float num3 = float.MaxValue;
float num4 = 0f;
Dictionary<int, int> dictionary = new Dictionary<int, int>();
BlueprintBuilding[] buildings = _bp.buildings;
foreach (BlueprintBuilding val in buildings)
{
if (!dictionary.ContainsKey(val.itemId))
{
dictionary[val.itemId] = 0;
}
dictionary[val.itemId]++;
if (IsBelt(val))
{
num++;
float num5 = Vector3.Distance(new Vector3(val.localOffset_x, val.localOffset_y, val.localOffset_z), new Vector3(val.localOffset_x2, val.localOffset_y2, val.localOffset_z2));
if (num5 < 0.0001f)
{
num2++;
}
if (num5 < num3)
{
num3 = num5;
}
if (num5 > num4)
{
num4 = num5;
}
}
}
if (num > 0)
{
_beltStat = ((num2 == num) ? $"探测到传送带 {num} 段(逐格存储,方向由朝向决定)" : $"探测到传送带 {num} 段,长度 {num3:F4} ~ {num4:F4}(其中首尾重合 {num2} 段)");
}
else
{
IEnumerable<string> values = from p in dictionary
orderby p.Key
select p.Key + "×" + p.Value;
_beltStat = "未探测到传送带;蓝图物品ID分布: " + string.Join(", ", values);
}
}
private void ApplyToPasteTool()
{
if (!RequireBlueprint())
{
return;
}
try
{
UIBlueprintInspector val = (((Object)(object)_inspector != (Object)null) ? _inspector : Object.FindObjectOfType<UIBlueprintInspector>());
if ((Object)(object)val == (Object)null || _fiPasteTool == null)
{
_status = "未找到蓝图粘贴工具(请先打开蓝图界面)";
return;
}
object? value = _fiPasteTool.GetValue(val);
BuildTool_BlueprintPaste val2 = (BuildTool_BlueprintPaste)((value is BuildTool_BlueprintPaste) ? value : null);
if (val2 == null)
{
_status = "粘贴工具不可用";
return;
}
BlueprintData val3 = _bp.Clone();
val3.CheckBuildingData();
val2.blueprint = val3;
try
{
val2.ForceDetermineBP();
}
catch
{
}
try
{
val2.RefreshBlueprintUI();
}
catch
{
}
_status = $"已替换粘贴工具中的蓝图(建筑 {val3.buildings.Length} 个)";
}
catch (Exception ex)
{
_status = "应用异常:" + ex.Message;
}
}
private bool RequireBlueprint()
{
if (_bp != null && _bp.buildings != null)
{
return true;
}
_status = "请先从剪贴板读取蓝图";
return false;
}
private static float R4(float v)
{
return (float)Math.Round(v, 4);
}
}