diff --git a/CheatEnabler/UIConfigWindow.cs b/CheatEnabler/UIConfigWindow.cs index 043adc3..1832221 100644 --- a/CheatEnabler/UIConfigWindow.cs +++ b/CheatEnabler/UIConfigWindow.cs @@ -237,23 +237,18 @@ public static class UIConfigWindow private static void UpdateButtons() { var data = GameMain.data; - if (data != null) + if (data == null) return; + var resignEnabled = data.account != AccountData.me; + if (_resignGameBtn.gameObject.activeSelf != resignEnabled) { - var resignEnabled = data.account != AccountData.me; - if (_resignGameBtn.gameObject.activeSelf != resignEnabled) - { - _resignGameBtn.gameObject.SetActive(resignEnabled); - } + _resignGameBtn.gameObject.SetActive(resignEnabled); } - - var history = GameMain.history; - if (history != null) + var history = data.history; + if (history == null) return; + var banEnabled = history.hasUsedPropertyBanAchievement; + if (_clearBanBtn.gameObject.activeSelf != banEnabled) { - var banEnabled = history.hasUsedPropertyBanAchievement; - if (_clearBanBtn.gameObject.activeSelf != banEnabled) - { - _clearBanBtn.gameObject.SetActive(banEnabled); - } + _clearBanBtn.gameObject.SetActive(banEnabled); } } } \ No newline at end of file diff --git a/UXAssist/CHANGELOG.md b/UXAssist/CHANGELOG.md index 3734ad9..1f2fa00 100644 --- a/UXAssist/CHANGELOG.md +++ b/UXAssist/CHANGELOG.md @@ -4,6 +4,8 @@ + New feature: `Logistics Control Panel Improvement` - Auto apply filter with item under mouse cursor while opening the panel - Quick-set item filter while right-clicking item icons in storage list on the panel + + New feature: `Dyson Sphere "Auto Fast Build" speed multiplier` + - Note: this only applies to `Dyson Sphere "Auto Fast Build"` in sandbox mode + `Quick build and dismantle stacking labs`: works for storages and tanks now + `Enable game window resize`: Keep window resizable on applying game options. + `Remember window position and size on last exit`: Do not resize window on applying game options if resolution related config entries are not changed. @@ -154,6 +156,8 @@ + 新功能:`物流控制面板改进` - 打开面板时自动将鼠标指向物品设为筛选条件 - 在控制面板物流塔列表中右键点击物品图标快速设置为筛选条件 + + 新功能:`戴森球自动快速建造速度倍率` + - 注意:这仅适用于沙盒模式下的`戴森球自动快速建造`功能 + `快速建造和拆除堆叠研究站`:现在也支持储物仓和储液罐 + `允许调整游戏窗口大小`:在应用游戏选项时保持窗口可调整大小 + `记住上次退出时的窗口位置和大小`:如果分辨率相关的配置项未改变,则在应用游戏选项时不调整窗口大小 diff --git a/UXAssist/DysonSpherePatch.cs b/UXAssist/DysonSpherePatch.cs index 0404510..2658b88 100644 --- a/UXAssist/DysonSpherePatch.cs +++ b/UXAssist/DysonSpherePatch.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Reflection; using System.Reflection.Emit; using BepInEx.Configuration; using HarmonyLib; @@ -12,7 +13,9 @@ public static class DysonSpherePatch public static ConfigEntry OnlyConstructNodesEnabled; public static ConfigEntry AutoConstructMultiplier; private static Harmony _dysonSpherePatch; - + + private static FieldInfo _totalNodeSpInfo, _totalFrameSpInfo, _totalCpInfo; + public static void Init() { I18N.Add("[UXAssist] No node to fill", "[UXAssist] No node to fill", "[UXAssist] 无可建造节点"); @@ -21,6 +24,9 @@ public static class DysonSpherePatch OnlyConstructNodesEnabled.SettingChanged += (_, _) => OnlyConstructNodes.Enable(OnlyConstructNodesEnabled.Value); StopEjectOnNodeComplete.Enable(StopEjectOnNodeCompleteEnabled.Value); OnlyConstructNodes.Enable(OnlyConstructNodesEnabled.Value); + _totalNodeSpInfo = AccessTools.Field(typeof(DysonSphereLayer), "totalNodeSP"); + _totalFrameSpInfo = AccessTools.Field(typeof(DysonSphereLayer), "totalFrameSP"); + _totalCpInfo = AccessTools.Field(typeof(DysonSphereLayer), "totalCP"); } public static void Uninit() @@ -58,158 +64,182 @@ public static class DysonSpherePatch } ds.RemoveLayer(index); } - + + [HarmonyPrefix] + [HarmonyPatch(typeof(DysonSwarm), nameof(DysonSwarm.AutoConstruct))] + private static bool DysonSwarm_AutoConstruct_Prefix(DysonSwarm __instance) + { + return false; + } + + [HarmonyPrefix] [HarmonyPatch(typeof(DysonSphere), nameof(DysonSphere.AutoConstruct))] private static bool DysonSphere_AutoConstruct_Prefix(DysonSphere __instance) { var totalCount = AutoConstructMultiplier.Value * 6; - var totalCount2 = AutoConstructMultiplier.Value * 6; foreach (var dysonSphereLayer in __instance.layersIdBased) { if (dysonSphereLayer == null) continue; - int todoCount; - int[] productRegister; for (var j = dysonSphereLayer.nodePool.Length - 1; j >= 0; j--) { var dysonNode = dysonSphereLayer.nodePool[j]; if (dysonNode == null || dysonNode.id != j) continue; - var count = dysonNode._spReq - dysonNode.spOrdered; - if (count > 0) + lock (dysonNode) { - - if (count > totalCount) - { - count = totalCount; - dysonNode.spOrdered += count; - } - else - { - dysonNode.spOrdered = dysonNode._spReq; - __instance.RemoveAutoNode(dysonNode); - __instance.PickAutoNode(); - } - - todoCount = count; - if (dysonNode.sp < dysonNode.spMax) - { - if (dysonNode.sp + count > dysonNode.spMax) - { - var diff = dysonNode.spMax - dysonNode.sp; - count -= diff; - dysonNode.spOrdered -= diff; - dysonNode._spReq -= diff; - - dysonNode.sp = dysonNode.spMax; - } - else - { - dysonNode.spOrdered -= count; - dysonNode._spReq -= count; - - dysonNode.sp += count; - count = 0; - } - - __instance.UpdateProgress(dysonNode); - } - + var count = dysonNode._spReq - dysonNode.spOrdered; + int todoCount; + int[] productRegister; if (count > 0) { - var frameCount = dysonNode.frames.Count; - var frameIndex = dysonNode.frameTurn % frameCount; - for (var i = frameCount; i > 0; i--) + + if (count > totalCount) { - var dysonFrame = dysonNode.frames[frameIndex]; - var spMax = dysonFrame.spMax >> 1; - if (dysonFrame.nodeA == dysonNode && dysonFrame.spA < spMax) + count = totalCount; + } + + todoCount = count; + if (dysonNode.sp < dysonNode.spMax) + { + int diff; + if (dysonNode.sp + count > dysonNode.spMax) { - if (dysonFrame.spA + count > spMax) - { - var diff = spMax - dysonFrame.spA; - count -= diff; - dysonNode.spOrdered -= diff; - dysonNode._spReq -= diff; + diff = dysonNode.spMax - dysonNode.sp; + count -= diff; + dysonNode._spReq -= diff; - dysonFrame.spA = spMax; - __instance.UpdateProgress(dysonFrame); - } - else - { - dysonNode.spOrdered -= count; - dysonNode._spReq -= count; - - dysonFrame.spA += count; - count = 0; - __instance.UpdateProgress(dysonFrame); - break; - } + dysonNode.sp = dysonNode.spMax; } - - if (dysonFrame.nodeB == dysonNode && dysonFrame.spB < spMax) + else { - if (dysonFrame.spB + count > spMax) - { - var diff = spMax - dysonFrame.spB; - count -= diff; - dysonNode.spOrdered -= diff; - dysonNode._spReq -= diff; + diff = count; + dysonNode._spReq -= diff; - dysonFrame.spB = spMax; - __instance.UpdateProgress(dysonFrame); - } - else - { - dysonNode.spOrdered -= count; - dysonNode._spReq -= count; - - dysonFrame.spB += count; - count = 0; - __instance.UpdateProgress(dysonFrame); - break; - } + dysonNode.sp += diff; + count = 0; } + // Make compatible with DSPOptimizations + if (_totalNodeSpInfo != null) + _totalNodeSpInfo.SetValue(dysonSphereLayer, (long)_totalNodeSpInfo.GetValue(dysonSphereLayer) + diff - 1); + __instance.UpdateProgress(dysonNode); + } - frameIndex = (frameIndex + 1) % frameCount; + if (count > 0) + { + var frameCount = dysonNode.frames.Count; + var frameIndex = dysonNode.frameTurn % frameCount; + for (var i = frameCount; i > 0 && count > 0; i--) + { + var dysonFrame = dysonNode.frames[frameIndex]; + var spMax = dysonFrame.spMax >> 1; + if (dysonFrame.nodeA == dysonNode && dysonFrame.spA < spMax) + { + int diff; + if (dysonFrame.spA + count > spMax) + { + diff = spMax - dysonFrame.spA; + count -= diff; + dysonNode._spReq -= diff; + + dysonFrame.spA = spMax; + } + else + { + diff = count; + dysonNode._spReq -= diff; + + dysonFrame.spA += diff; + count = 0; + } + // Make compatible with DSPOptimizations + if (_totalFrameSpInfo != null) + _totalFrameSpInfo.SetValue(dysonSphereLayer, (long)_totalFrameSpInfo.GetValue(dysonSphereLayer) + diff - 1); + __instance.UpdateProgress(dysonFrame); + } + + if (count > 0 && dysonFrame.nodeB == dysonNode && dysonFrame.spB < spMax) + { + int diff; + if (dysonFrame.spB + count > spMax) + { + diff = spMax - dysonFrame.spB; + count -= diff; + dysonNode._spReq -= diff; + + dysonFrame.spB = spMax; + } + else + { + diff = count; + dysonNode._spReq -= diff; + + dysonFrame.spB += diff; + count = 0; + } + // Make compatible with DSPOptimizations + if (_totalFrameSpInfo != null) + _totalFrameSpInfo.SetValue(dysonSphereLayer, (long)_totalFrameSpInfo.GetValue(dysonSphereLayer) + diff - 1); + __instance.UpdateProgress(dysonFrame); + } + + frameIndex = (frameIndex + 1) % frameCount; + } + dysonNode.frameTurn = frameIndex; + } + if (dysonNode.spOrdered >= dysonNode._spReq) + { + __instance.RemoveAutoNode(dysonNode); + __instance.PickAutoNode(); + } + productRegister = __instance.productRegister; + if (productRegister != null) + { + lock (productRegister) + { + productRegister[11902] += todoCount - count; + } } } - productRegister = __instance.productRegister; - if (productRegister != null) + count = dysonNode._cpReq - dysonNode.cpOrdered; + if (count > 0) { - lock (productRegister) + if (count > totalCount) count = totalCount; + todoCount = count; + var shellCount = dysonNode.shells.Count; + var shellIndex = dysonNode.shellTurn % shellCount; + for (var i = shellCount; i > 0 && count > 0; i--) { - productRegister[11902] += todoCount - count; + var dysonShell = dysonNode.shells[shellIndex]; + lock (dysonShell) + { + var nodeIndex = dysonShell.nodeIndexMap[dysonNode.id]; + var diff = (dysonShell.vertsqOffset[nodeIndex + 1] - dysonShell.vertsqOffset[nodeIndex]) * dysonShell.cpPerVertex - dysonShell.nodecps[nodeIndex]; + if (diff > count) + diff = count; + count -= diff; + dysonNode._cpReq -= diff; + dysonShell.nodecps[nodeIndex] += diff; + dysonShell.nodecps[dysonShell.nodecps.Length - 1] += diff; + // Make compatible with DSPOptimizations + if (_totalCpInfo != null) + { + _totalCpInfo.SetValue(dysonSphereLayer, (long)_totalCpInfo.GetValue(dysonSphereLayer) + diff); + dysonShell.SetMaterialDynamicVars(); + } + } + shellIndex = (shellIndex + 1) % shellCount; } - } - } + dysonNode.shellTurn = shellIndex; - count = dysonNode._cpReq - dysonNode.cpOrdered; - if (count > totalCount2) count = totalCount2; - todoCount = count; - dysonNode.cpOrdered += count; - var shellCount = dysonNode.shells.Count; - var shellIndex = dysonNode.shellTurn % shellCount; - for (var i = shellCount; i > 0 && count > 0; i--) - { - var dysonShell = dysonNode.shells[shellIndex]; - var nodeIndex = dysonShell.nodeIndexMap[dysonNode.id]; - var diff = (dysonShell.vertsqOffset[nodeIndex + 1] - dysonShell.vertsqOffset[nodeIndex]) * dysonShell.cpPerVertex - dysonShell.nodecps[nodeIndex]; - if (diff > count) - diff = count; - count -= diff; - dysonNode.cpOrdered -= diff; - dysonNode._cpReq -= diff; - dysonShell.nodecps[nodeIndex] += diff; - dysonShell.nodecps[dysonShell.nodecps.Length - 1] += diff; - shellIndex = (shellIndex + 1) % shellCount; - } - productRegister = __instance.productRegister; - if (productRegister != null) - { - lock (productRegister) - { - productRegister[11903] += todoCount - count; + productRegister = __instance.productRegister; + if (productRegister != null) + { + lock (productRegister) + { + productRegister[11903] += todoCount - count; + } + } } } } diff --git a/UXAssist/README.md b/UXAssist/README.md index 9f95789..0850956 100644 --- a/UXAssist/README.md +++ b/UXAssist/README.md @@ -76,6 +76,8 @@ - Construct only structure points but frames - Re-initialize Dyson Spheres - Quick dismantle Dyson Shells + - Dyson Sphere "Auto Fast Build" speed multiplier + - Note: this only applies to `Dyson Sphere "Auto Fast Build"` in sandbox mode + Tech - Restore upgrades of `Sorter Cargo Stacking` on panel - Set `Sorter Cargo Stacking` to unresearched state @@ -172,6 +174,8 @@ - 只建造节点不建造框架 - 初始化戴森球 - 快速拆除戴森壳 + - 戴森球自动快速建造速度倍率 + - 注意:这仅适用于沙盒模式下的`戴森球自动快速建造`功能 + 科研 - 在升级面板上恢复`分拣器货物堆叠`的升级 - 将`分拣器货物堆叠`设为未研究状态 diff --git a/UXAssist/UI/MyWindow.cs b/UXAssist/UI/MyWindow.cs index 58ee199..b231a4e 100644 --- a/UXAssist/UI/MyWindow.cs +++ b/UXAssist/UI/MyWindow.cs @@ -1,6 +1,7 @@ using System; using HarmonyLib; using System.Collections.Generic; +using System.Globalization; using BepInEx.Configuration; using UnityEngine; using UnityEngine.Events; @@ -11,7 +12,7 @@ namespace UXAssist.UI; // MyWindow modified from LSTM: https://github.com/hetima/DSP_LSTM/blob/main/LSTM/MyWindowCtl.cs -public class MyWindow: ManualBehaviour +public class MyWindow : ManualBehaviour { private readonly Dictionary, UnityAction>> _inputFields = new(); private readonly Dictionary _buttons = new(); @@ -41,7 +42,7 @@ public class MyWindow: ManualBehaviour } public void Close() => _Close(); - + public void SetTitle(string title) { var txt = gameObject.transform.Find("panel-bg/title-text")?.gameObject.GetComponent(); @@ -110,6 +111,7 @@ public class MyWindow: ManualBehaviour _maxX = Math.Max(_maxX, x + rect.sizeDelta.x); MaxY = Math.Max(MaxY, y + rect.sizeDelta.y); } + return tipsButton; } @@ -132,10 +134,12 @@ public class MyWindow: ManualBehaviour l.stringKey = text; l.translation = text.Translate(); } + if (t != null) { t.text = text.Translate(); } + t.fontSize = fontSize; btn.button.onClick.RemoveAllListeners(); btn.tip = null; @@ -146,6 +150,7 @@ public class MyWindow: ManualBehaviour if (onClick != null) btn.button.onClick.AddListener(onClick); } + _maxX = Math.Max(_maxX, x + rect.sizeDelta.x); MaxY = Math.Max(MaxY, y + rect.sizeDelta.y); return btn; @@ -163,11 +168,13 @@ public class MyWindow: ManualBehaviour img.sprite = panel.buttonDefaultSprite; img.color = new Color(img.color.r, img.color.g, img.color.b, 13f / 255f); } + img = btn.gameObject.transform.Find("frame")?.GetComponent(); if (img != null) { img.color = new Color(img.color.r, img.color.g, img.color.b, 0f); } + var rect = Util.NormalizeRectWithTopLeft(btn, x, y, parent); var t = btn.gameObject.transform.Find("Text")?.GetComponent(); if (t != null) @@ -175,12 +182,14 @@ public class MyWindow: ManualBehaviour t.text = text.Translate(); t.fontSize = fontSize; } + btn.button.onClick.RemoveAllListeners(); _buttons[btn] = onClick; if (EventRegistered && onClick != null) { btn.button.onClick.AddListener(onClick); } + _maxX = Math.Max(_maxX, x + rect.sizeDelta.x); MaxY = Math.Max(MaxY, y + rect.sizeDelta.y); return btn; @@ -203,10 +212,90 @@ public class MyWindow: ManualBehaviour _maxX = Math.Max(_maxX, x + rect.sizeDelta.x); MaxY = Math.Max(MaxY, y + rect.sizeDelta.y); } + return slider; } - public InputField AddInputField(float x, float y, RectTransform parent, string text = "", int fontSize = 16, string objName = "input", UnityAction onChanged = null, UnityAction onEditEnd = null) + public class ValueMapper + { + public virtual int Min => 1; + public virtual int Max => 100; + public virtual int ValueToIndex(T value) => (int)Convert.ChangeType(value, typeof(int), CultureInfo.InvariantCulture); + public virtual T IndexToValue(int index) => (T)Convert.ChangeType(index, typeof(T), CultureInfo.InvariantCulture); + + public virtual string FormatValue(string format, T value) + { + return string.Format($"{{0:{format}}}", value); + } + } + + public MySlider AddSlider(float x, float y, RectTransform parent, ConfigEntry config, ValueMapper valueMapper, string format = "G", float width = 0f) + { + var slider = MySlider.CreateSlider(x, y, parent, OnConfigValueChanged(config), valueMapper.Min, valueMapper.Max, format, width); + slider.SetLabelText(valueMapper.FormatValue(format, config.Value)); + config.SettingChanged += (sender, args) => + { + var index = OnConfigValueChanged(config); + slider.Value = index; + }; + slider.OnValueChanged += () => + { + var index = Mathf.RoundToInt(slider.Value); + config.Value = valueMapper.IndexToValue(index); + slider.SetLabelText(valueMapper.FormatValue(format, config.Value)); + }; + + var rect = slider.rectTrans; + if (rect != null) + { + _maxX = Math.Max(_maxX, x + rect.sizeDelta.x); + MaxY = Math.Max(MaxY, y + rect.sizeDelta.y); + } + + return slider; + + int OnConfigValueChanged(ConfigEntry conf) + { + var index = valueMapper.ValueToIndex(conf.Value); + if (index >= 0) return index; + index = ~index; + index = Math.Max(0, Math.Min(valueMapper.Max, index)); + conf.Value = valueMapper.IndexToValue(index); + return index; + } + } + + private class ArrayMapper : ValueMapper + { + private readonly T[] _values; + + public ArrayMapper(T[] values) + { + Array.Sort(values); + _values = values; + } + + public override int Min => 0; + public override int Max => _values.Length - 1; + + public override int ValueToIndex(T value) + { + return Array.BinarySearch(_values, value); + } + + public override T IndexToValue(int index) + { + return _values[index >= 0 && index < _values.Length ? index : 0]; + } + } + + public MySlider AddSlider(float x, float y, RectTransform parent, ConfigEntry config, T[] valueList, string format = "G", float width = 0f) + { + return AddSlider(x, y, parent, config, new ArrayMapper(valueList), format, width); + } + + public InputField AddInputField(float x, float y, RectTransform parent, string text = "", int fontSize = 16, string objName = "input", UnityAction onChanged = null, + UnityAction onEditEnd = null) { var stationWindow = UIRoot.instance.uiGame.stationWindow; //public InputField nameInput; @@ -228,6 +317,7 @@ public class MyWindow: ManualBehaviour if (onEditEnd != null) inputField.onEndEdit.AddListener(onEditEnd); } + _maxX = Math.Max(_maxX, x + rect.sizeDelta.x); MaxY = Math.Max(MaxY, y + rect.sizeDelta.y); return inputField; @@ -245,12 +335,14 @@ public class MyWindow: ManualBehaviour if (t.Value.Item2 != null) inputField.onEndEdit.AddListener(t.Value.Item2); } + foreach (var t in _buttons) { var btn = t.Key; if (t.Value != null) btn.button.onClick.AddListener(t.Value); } + EventRegistered = true; } @@ -265,6 +357,7 @@ public class MyWindow: ManualBehaviour if (t.Value != null) btn.button.onClick.RemoveListener(t.Value); } + foreach (var t in _inputFields) { var inputField = t.Key; @@ -290,7 +383,7 @@ public class MyWindowWithTabs : MyWindow { return true; } - + private RectTransform AddTabInternal(float y, int index, RectTransform parent, string label) { var tab = new GameObject(); @@ -322,6 +415,7 @@ public class MyWindowWithTabs : MyWindow { btn.onClick += OnTabButtonClick; } + MaxY = Math.Max(MaxY, y + TabHeight); return tabRect; } @@ -358,6 +452,7 @@ public class MyWindowWithTabs : MyWindow t.Item2.onClick += OnTabButtonClick; } } + base._OnRegEvent(); } @@ -370,6 +465,7 @@ public class MyWindowWithTabs : MyWindow t.Item2.onClick -= OnTabButtonClick; } } + base._OnUnregEvent(); } @@ -385,6 +481,7 @@ public class MyWindowWithTabs : MyWindow rectTransform.gameObject.SetActive(false); continue; } + btn.highlighted = true; rectTransform.gameObject.SetActive(true); } @@ -401,13 +498,13 @@ public static class MyWindowManager { _patch ??= Harmony.CreateAndPatchAll(typeof(Patch)); } - + public static void Uninit() { _patch?.UnpatchSelf(); _patch = null; } - + public static T CreateWindow(string name, string title = "") where T : MyWindow { var srcWin = UIRoot.instance.uiGame.tankWindow; @@ -438,16 +535,17 @@ public static class MyWindowManager } } - win.SetTitle(title); + win.SetTitle(title); win._Create(); if (_initialized) { win._Init(win.data); } + Windows.Add(win); return (T)win; } - + public static void DestroyWindow(ManualBehaviour win) { if (win == null) return; @@ -467,7 +565,6 @@ public static class MyWindowManager public static class Patch { - /* //_Create -> _Init [HarmonyPostfix, HarmonyPatch(typeof(UIGame), "_OnCreate")] @@ -484,6 +581,7 @@ public static class MyWindowManager win._Free(); win._Destroy(); } + Windows.Clear(); } @@ -495,6 +593,7 @@ public static class MyWindowManager { win._Init(win.data); } + _initialized = true; } @@ -516,6 +615,7 @@ public static class MyWindowManager { return; } + foreach (var win in Windows) { win._Update(); diff --git a/UXAssist/UIConfigWindow.cs b/UXAssist/UIConfigWindow.cs index 9b64acc..784f621 100644 --- a/UXAssist/UIConfigWindow.cs +++ b/UXAssist/UIConfigWindow.cs @@ -67,6 +67,7 @@ public static class UIConfigWindow I18N.Add("Click to dismantle selected layer", "Click to dismantle selected layer", "点击拆除对应的戴森壳"); I18N.Add("Dismantle selected layer", "Dismantle selected layer", "拆除选中的戴森壳"); I18N.Add("Dismantle selected layer Confirm", "This operation will dismantle selected layer, are you sure?", "此操作将会拆除选中的戴森壳,确定吗?"); + I18N.Add("Auto Fast Build Speed Multiplier", "Auto Fast Build Speed Multiplier", "自动快速建造速度倍率"); I18N.Add("Restore upgrades of \"Sorter Cargo Stacking\" on panel", "Restore upgrades of \"Sorter Cargo Stacking\" on panel", "在升级面板上恢复\"分拣器货物叠加\"的升级"); I18N.Add("Buy out techs with their prerequisites", "Buy out techs with their prerequisites", "购买科技也同时购买所有前置科技"); I18N.Add("Set \"Sorter Cargo Stacking\" to unresearched state", "Set \"Sorter Cargo Stacking\" to unresearched state", "将\"分拣器货物叠加\"设为未研究状态"); @@ -76,6 +77,24 @@ public static class UIConfigWindow MyConfigWindow.OnUpdateUI += UpdateUI; } + private class OcMapper : MyWindow.ValueMapper + { + public override int Min => 0; + public override int Max => 40; + public override string FormatValue(string format, int value) + { + return value == 0 ? "max".Translate() : base.FormatValue(format, value); + } + } + + private class DistanceMapper : MyWindow.ValueMapper + { + public override int Min => 1; + public override int Max => 40; + public override double IndexToValue(int index) => index * 0.5; + public override int ValueToIndex(double value) => Mathf.RoundToInt((float)(value * 2.0)); + } + private static void CreateUI(MyConfigWindow wnd, RectTransform trans) { _windowTrans = trans; @@ -151,19 +170,7 @@ public static class UIConfigWindow y += 30f; wnd.AddText2(x, y, tab2, "Maximum count to build", 15, "text-oc-build-count"); y += 24f; - var ocBuildSlider = wnd.AddSlider(x, y, tab2, PlanetFunctions.OrbitalCollectorMaxBuildCount.Value, 0f, 40f, "G", 200f); - if (PlanetFunctions.OrbitalCollectorMaxBuildCount.Value == 0) - { - ocBuildSlider.SetLabelText("max".Translate()); - } - ocBuildSlider.OnValueChanged += () => - { - PlanetFunctions.OrbitalCollectorMaxBuildCount.Value = Mathf.RoundToInt(ocBuildSlider.Value); - if (PlanetFunctions.OrbitalCollectorMaxBuildCount.Value == 0) - { - ocBuildSlider.SetLabelText("max".Translate()); - } - }; + wnd.AddSlider(x, y, tab2, PlanetFunctions.OrbitalCollectorMaxBuildCount, new OcMapper(), "G", 200f); x = 400f; y += 54f; wnd.AddCheckBox(x, y, tab2, LogisticsPatch.LogisticsCapacityTweaksEnabled, "Enhance control for logistic storage limits"); @@ -201,16 +208,8 @@ public static class UIConfigWindow y += 32f; wnd.AddText2(x, y, tab3, "Distance to use warp", 15, "text-distance-to-warp"); y += 24f; - var distanceToWarp = wnd.AddSlider(x, y, tab3, (float)Math.Round(PlayerPatch.DistanceToWarp.Value * 2.0), 1f, 40f, "0.0", 200f); - if (PlanetFunctions.OrbitalCollectorMaxBuildCount.Value == 0) - { - distanceToWarp.SetLabelText(PlayerPatch.DistanceToWarp.Value.ToString("0.0")); - } - distanceToWarp.OnValueChanged += () => - { - PlayerPatch.DistanceToWarp.Value = Math.Round(distanceToWarp.Value) * 0.5; - distanceToWarp.SetLabelText(PlayerPatch.DistanceToWarp.Value.ToString("0.0")); - }; + + wnd.AddSlider(x, y, tab3, PlayerPatch.DistanceToWarp, new DistanceMapper(), "0.0", 200f); var tab4 = wnd.AddTab(trans, "Dyson Sphere"); x = 0f; @@ -250,6 +249,12 @@ public static class UIConfigWindow x += 40f; } } + + x = 400f; + y += 36f; + wnd.AddText2(x, y, tab4, "Auto Fast Build Speed Multiplier", 15, "text-auto-fast-build-multiplier"); + y += 24f; + wnd.AddSlider(x, y, tab4, DysonSpherePatch.AutoConstructMultiplier, [1, 2, 5, 10, 20, 50, 100], "0", 200f); _dysonTab = tab4; var tab5 = wnd.AddTab(_windowTrans, "Tech/Combat"); diff --git a/UXAssist/UXAssist.cs b/UXAssist/UXAssist.cs index d0c99af..ef036f9 100644 --- a/UXAssist/UXAssist.cs +++ b/UXAssist/UXAssist.cs @@ -129,7 +129,7 @@ public class UXAssist : BaseUnityPlugin, IModCanSave "Stop ejectors when available nodes are all filled up"); DysonSpherePatch.OnlyConstructNodesEnabled = Config.Bind("DysonSphere", "OnlyConstructNodes", false, "Construct only nodes but frames"); - DysonSpherePatch.AutoConstructMultiplier = Config.Bind("DysonSphere", "AutoConstructMultiplier", 10, "Dyson Sphere auto-construct speed multiplier"); + DysonSpherePatch.AutoConstructMultiplier = Config.Bind("DysonSphere", "AutoConstructMultiplier", 1, "Dyson Sphere auto-construct speed multiplier"); I18N.Init(); I18N.Add("UXAssist Config", "UXAssist Config", "UX助手设置");