From 150868fcea6c4ac5229f98277ebf1fbf8622b8b6 Mon Sep 17 00:00:00 2001 From: Soar Qin Date: Wed, 23 Apr 2025 21:26:11 +0800 Subject: [PATCH] work in progress --- UXAssist/Functions/UIFunctions.cs | 242 +++++++++++++++++++++------- UXAssist/Patches/PlayerPatch.cs | 11 ++ UXAssist/UI/MyCheckButton.cs | 252 ++++++++++++++++++++++++++++++ UXAssist/UI/MyCheckbox.cs | 2 +- UXAssist/UI/MyWindow.cs | 1 + 5 files changed, 452 insertions(+), 56 deletions(-) create mode 100644 UXAssist/UI/MyCheckButton.cs diff --git a/UXAssist/Functions/UIFunctions.cs b/UXAssist/Functions/UIFunctions.cs index 658c03a..def3b08 100644 --- a/UXAssist/Functions/UIFunctions.cs +++ b/UXAssist/Functions/UIFunctions.cs @@ -7,6 +7,9 @@ using UnityEngine; using UnityEngine.UI; using System; using System.Linq; +using System.Runtime.Remoting.Messaging; +using System.Collections.Generic; +using System.Text.RegularExpressions; public static class UIFunctions { @@ -17,6 +20,8 @@ public static class UIFunctions private static GameObject _buttonOnPlanetGlobe; private static int _cornerComboBoxIndex; private static string[] _starOrderNames; + private static bool _starFilterEnabled; + public static bool[] ShowStarName; public static void Init() { @@ -32,6 +37,7 @@ public static class UIFunctions GameLogic.OnGameBegin += () => { var galaxy = GameMain.data.galaxy; + ShowStarName = new bool[galaxy.starCount]; _starOrderNames = new string[galaxy.starCount]; StarData[] stars = [..galaxy.stars.Where(star => star != null)]; Array.Sort(stars, (a, b) => @@ -40,10 +46,63 @@ public static class UIFunctions if (res != 0) return res; return a.index.CompareTo(b.index); }); + for (int i = 0; i < stars.Length; i++) + { + var star = stars[i]; + _starOrderNames[star.index] = star.displayName; + } + int[] spectrCount = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + for (int i = 0; i < stars.Length; i++) + { + var star = stars[i]; + var index = star.index; + switch (star.type) + { + case EStarType.MainSeqStar: + switch (star.spectr) + { + case ESpectrType.M: + _starOrderNames[index] = String.Format("M{0}", ++spectrCount[0]); + break; + case ESpectrType.K: + _starOrderNames[index] = String.Format("K{0}", ++spectrCount[1]); + break; + case ESpectrType.G: + _starOrderNames[index] = String.Format("G{0}", ++spectrCount[2]); + break; + case ESpectrType.F: + _starOrderNames[index] = String.Format("F{0}", ++spectrCount[3]); + break; + case ESpectrType.A: + _starOrderNames[index] = String.Format("A{0}", ++spectrCount[4]); + break; + case ESpectrType.B: + _starOrderNames[index] = String.Format("B{0}", ++spectrCount[5]); + break; + case ESpectrType.O: + _starOrderNames[index] = String.Format("O{0}", ++spectrCount[6]); + break; + } + break; + case EStarType.GiantStar: + _starOrderNames[index] = String.Format("GS{0}", ++spectrCount[7]); + break; + case EStarType.WhiteDwarf: + _starOrderNames[index] = String.Format("WD{0}", ++spectrCount[8]); + break; + case EStarType.NeutronStar: + _starOrderNames[index] = String.Format("NS{0}", ++spectrCount[9]); + break; + case EStarType.BlackHole: + _starOrderNames[index] = String.Format("BH{0}", ++spectrCount[10]); + break; + } + } }; GameLogic.OnGameEnd += () => { _starOrderNames = null; + ShowStarName = null; }; } @@ -133,12 +192,128 @@ public static class UIFunctions } } { - var cb = UI.MyCornerComboBox.CreateComboBox(125, 0, uiRoot.uiGame.starmap.transform as RectTransform, true).WithItems("显示原始名称", "显示距离", "显示行星数", "显示主要矿物", "显示全部信息"); + var rtrans = uiRoot.uiGame.starmap.transform as RectTransform; + var cb = UI.MyCornerComboBox.CreateComboBox(125, 0, rtrans, true).WithItems("显示原始名称", "显示距离", "显示行星数", "显示主要矿物", "显示全部信息"); cb.SetIndex(Functions.UIFunctions.CornerComboBoxIndex); cb.OnSelChanged += (index) => { Functions.UIFunctions.CornerComboBoxIndex = index; }; + var toggleButton = UI.MyCheckButton.CreateCheckButton(20, 0, rtrans, false, ">>").WithSize(20, 20); + MyCheckButton[] buttons = [ + UI.MyCheckButton.CreateCheckButton(40, 0, rtrans, false).WithIcon().WithSize(20, 20), + UI.MyCheckButton.CreateCheckButton(60, 0, rtrans, false).WithIcon().WithSize(20, 20), + UI.MyCheckButton.CreateCheckButton(80, 0, rtrans, false).WithIcon().WithSize(20, 20), + UI.MyCheckButton.CreateCheckButton(100, 0, rtrans, false).WithIcon().WithSize(20, 20), + UI.MyCheckButton.CreateCheckButton(120, 0, rtrans, false).WithIcon().WithSize(20, 20), + UI.MyCheckButton.CreateCheckButton(140, 0, rtrans, false).WithIcon().WithSize(20, 20), + UI.MyCheckButton.CreateCheckButton(160, 0, rtrans, false).WithIcon().WithSize(20, 20), + UI.MyCheckButton.CreateCheckButton(180, 0, rtrans, false).WithIcon().WithSize(20, 20), + ]; + toggleButton.OnChecked += UpdateButtons; + foreach (var button in buttons) + { + button.OnChecked += UpdateStarmapStarFilters; + } + + GameLogic.OnDataLoaded += () => + { + for (int i = 0; i < 8; i++) + { + buttons[i].SetIcon(LDB.veins.Select(i + 7)._iconSprite); + } + }; + GameLogic.OnGameBegin += () => + { + UpdateButtons(); + SetStarFilterEnabled(false); + }; + void UpdateButtons() + { + var chk = toggleButton.Checked; + foreach (var button in buttons) + { + if (chk) + button.gameObject.SetActive(true); + else + { + button.gameObject.SetActive(false); + button.Checked = false; + } + } + toggleButton.SetLabelText(chk ? "X" : ">>"); + if (!chk) + { + UpdateStarmapStarFilters(); + } + } + void UpdateStarmapStarFilters() + { + List starFilter = []; + bool showAny = false; + if (toggleButton.Checked) + { + for (int i = buttons.Length - 1; i >= 0; i--) + { + if (buttons[i].Checked) + { + starFilter.Add(i + 7); + showAny = true; + } + } + } + if (!showAny) + { + for (int i = 0; i < ShowStarName.Length; i++) + { + ShowStarName[i] = false; + } + SetStarFilterEnabled(false); + return; + } + var galaxy = GameMain.data.galaxy; + var stars = galaxy.stars; + for (int i = 0; i < galaxy.starCount; i++) + { + var star = stars[i]; + if (star == null) continue; + ShowStarName[i] = false; + var allMatch = true; + foreach (var filter in starFilter) + { + var match = false; + foreach (var planet in star.planets) + { + if (planet == null) continue; + if (planet.type == EPlanetType.Gas) + { + } + else + { + foreach (var group in planet.veinGroups) + { + if (group.amount > 0 && (int)group.type == filter) + { + match = true; + break; + } + } + } + if (match) break; + } + if (!match) + { + allMatch = false; + break; + } + } + if (allMatch) + { + ShowStarName[i] = true; + } + } + SetStarFilterEnabled(true); + } } _initialized = true; } @@ -173,65 +348,22 @@ public static class UIFunctions set { _cornerComboBoxIndex = value; - Patches.PlayerPatch.ShortcutKeysForStarsName.SetForceShowAllStarsNameExternal(_cornerComboBoxIndex != 0); + Patches.PlayerPatch.ShortcutKeysForStarsName.SetForceShowAllStarsNameExternal(_cornerComboBoxIndex != 0 && !_starFilterEnabled); UpdateStarmapStarNames(); } } - public static void UpdateStarmapStarNames() + private static void SetStarFilterEnabled(bool enabled) + { + if (_starFilterEnabled == enabled) return; + _starFilterEnabled = enabled; + if (!enabled) Patches.PlayerPatch.ShortcutKeysForStarsName.SetShowAllStarsNameStatus(0); + Patches.PlayerPatch.ShortcutKeysForStarsName.SetForceShowAllStarsNameExternal(_cornerComboBoxIndex != 0 && !_starFilterEnabled); + UpdateStarmapStarNames(); + } + + private static void UpdateStarmapStarNames() { - if (_cornerComboBoxIndex > 0) - { - int[] spectrCount = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; - var galaxy = GameMain.data.galaxy; - StarData[] stars = new StarData[galaxy.starCount]; - for (int i = 0; i < galaxy.starCount; i++) - { - var star = stars[i]; - var index = star.index; - switch (star.type) - { - case EStarType.MainSeqStar: - switch (star.spectr) - { - case ESpectrType.M: - _starOrderNames[index] = String.Format("M{0}", ++spectrCount[0]); - break; - case ESpectrType.K: - _starOrderNames[index] = String.Format("K{0}", ++spectrCount[1]); - break; - case ESpectrType.G: - _starOrderNames[index] = String.Format("G{0}", ++spectrCount[2]); - break; - case ESpectrType.F: - _starOrderNames[index] = String.Format("F{0}", ++spectrCount[3]); - break; - case ESpectrType.A: - _starOrderNames[index] = String.Format("A{0}", ++spectrCount[4]); - break; - case ESpectrType.B: - _starOrderNames[index] = String.Format("B{0}", ++spectrCount[5]); - break; - case ESpectrType.O: - _starOrderNames[index] = String.Format("O{0}", ++spectrCount[6]); - break; - } - break; - case EStarType.GiantStar: - _starOrderNames[index] = String.Format("GS{0}", ++spectrCount[7]); - break; - case EStarType.WhiteDwarf: - _starOrderNames[index] = String.Format("WD{0}", ++spectrCount[8]); - break; - case EStarType.NeutronStar: - _starOrderNames[index] = String.Format("NS{0}", ++spectrCount[9]); - break; - case EStarType.BlackHole: - _starOrderNames[index] = String.Format("BH{0}", ++spectrCount[10]); - break; - } - } - } foreach (var starUI in UIRoot.instance.uiGame.starmap.starUIs) { var star = starUI?.star; diff --git a/UXAssist/Patches/PlayerPatch.cs b/UXAssist/Patches/PlayerPatch.cs index c495491..4e73b65 100644 --- a/UXAssist/Patches/PlayerPatch.cs +++ b/UXAssist/Patches/PlayerPatch.cs @@ -156,6 +156,11 @@ public static class PlayerPatch private static bool _forceShowAllStarsName; private static bool _forceShowAllStarsNameExternal; + public static void SetShowAllStarsNameStatus(int status) + { + _showAllStarsNameStatus = status; + } + public static void ToggleAllStarsName() { _showAllStarsNameStatus = (_showAllStarsNameStatus + 1) % 3; @@ -205,6 +210,12 @@ public static class PlayerPatch new CodeInstruction(OpCodes.Brtrue, jumpPos.Value), new CodeInstruction(OpCodes.Ldsfld, AccessTools.Field(typeof(PlayerPatch.ShortcutKeysForStarsName), nameof(_forceShowAllStarsName))), new CodeInstruction(OpCodes.Brtrue, jumpPos.Value), + new CodeInstruction(OpCodes.Ldsfld, AccessTools.Field(typeof(Functions.UIFunctions), nameof(Functions.UIFunctions.ShowStarName))), + new CodeInstruction(OpCodes.Ldarg_0), + new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(UIStarmapStar), nameof(UIStarmapStar.star))), + new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(StarData), nameof(StarData.index))), + new CodeInstruction(OpCodes.Ldelem_I1), + new CodeInstruction(OpCodes.Brtrue, jumpPos.Value), new CodeInstruction(OpCodes.Ldsfld, AccessTools.Field(typeof(ShortcutKeysForStarsName), nameof(_showAllStarsNameStatus))), new CodeInstruction(OpCodes.Ldc_I4_2), new CodeInstruction(OpCodes.Ceq), diff --git a/UXAssist/UI/MyCheckButton.cs b/UXAssist/UI/MyCheckButton.cs new file mode 100644 index 0000000..ed0fc37 --- /dev/null +++ b/UXAssist/UI/MyCheckButton.cs @@ -0,0 +1,252 @@ +using System; +using BepInEx.Configuration; +using UnityEngine; +using UnityEngine.UI; + +namespace UXAssist.UI; + +// MyCheckButton modified from LSTM: https://github.com/hetima/DSP_LSTM/blob/main/LSTM/MyCheckButton.cs +public class MyCheckButton : MonoBehaviour +{ + public RectTransform rectTrans; + public UIButton uiButton; + public Image icon; + public Text labelText; + public event Action OnChecked; + private bool _checked; + private float _iconWidth = 28f; + + private static GameObject _baseObject; + + private static Color openMouseOverColor; + private static Color openPressColor; + private static Color openNormalColor; + private static Color closeMouseOverColor; + private static Color closePressColor; + private static Color closeNormalColor; + + public static void InitBaseObject() + { + if (_baseObject) return; + var tankWindow = UIRoot.instance.uiGame.tankWindow; + openMouseOverColor = tankWindow.openMouseOverColor; + openPressColor = tankWindow.openPressColor; + openNormalColor = tankWindow.openNormalColor; + closeMouseOverColor = tankWindow.closeMouseOverColor; + closePressColor = tankWindow.closePressColor; + closeNormalColor = tankWindow.closeNormalColor; + + var go = Instantiate(UIRoot.instance.uiGame.beltWindow.reverseButton.gameObject); + go.name = "my-checkbutton"; + go.SetActive(false); + var comp = go.transform.Find("text"); + if (comp) + { + var txt = comp.GetComponent(); + if (txt) + { + txt.text = ""; + txt.rectTransform.pivot = new Vector2(0.5f, 0.5f); + } + var localizer = comp.GetComponent(); + if (localizer) DestroyImmediate(localizer); + } + _baseObject = go; + } + + protected void OnDestroy() + { + if (_config != null) _config.SettingChanged -= _configChanged; + } + + public static MyCheckButton CreateCheckButton(float x, float y, RectTransform parent, ConfigEntry config, string label = "", int fontSize = 15) + { + return CreateCheckButton(x, y, parent, config.Value, label, fontSize).WithConfigEntry(config); + } + + public static MyCheckButton CreateCheckButton(float x, float y, RectTransform parent, bool check, string label = "", int fontSize = 15) + { + return CreateCheckButton(x, y, parent, fontSize).WithCheck(check).WithLabelText(label); + } + + public static MyCheckButton CreateCheckButton(float x, float y, RectTransform parent, int fontSize = 15) + { + var go = Instantiate(_baseObject); + go.name = "my-checkbutton"; + go.SetActive(true); + var cb = go.AddComponent(); + var rect = Util.NormalizeRectWithTopLeft(cb, x, y, parent); + + cb.rectTrans = rect; + cb.uiButton = go.GetComponent(); + + var child = go.transform.Find("text"); + if (child != null) + { + cb.labelText = child.GetComponent(); + if (cb.labelText) + { + cb.labelText.text = ""; + cb.labelText.fontSize = fontSize; + cb.UpdateLabelTextWidth(); + } + } + + cb.uiButton.onClick += cb.OnClick; + cb._iconWidth = Mathf.Min(cb._iconWidth > 0f ? cb._iconWidth : 28f, rect.sizeDelta.y); + cb.UpdateCheckColor(); + return cb; + } + + private void UpdateLabelTextWidth() + { + if (labelText) labelText.rectTransform.sizeDelta = new Vector2(labelText.preferredWidth, labelText.rectTransform.sizeDelta.y); + } + + public bool Checked + { + get => _checked; + set + { + _checked = value; + UpdateCheckColor(); + } + } + + public void SetLabelText(string val) + { + if (labelText != null) + { + labelText.text = val.Translate(); + UpdateLabelTextWidth(); + } + } + + private EventHandler _configChanged; + private Action _checkedChanged; + private ConfigEntry _config; + public void SetConfigEntry(ConfigEntry config) + { + if (_checkedChanged != null) OnChecked -= _checkedChanged; + if (_configChanged != null) config.SettingChanged -= _configChanged; + + _config = config; + _checkedChanged = () => config.Value = !config.Value; + OnChecked += _checkedChanged; + _configChanged = (_, _) => Checked = config.Value; + config.SettingChanged += _configChanged; + } + + public MyCheckButton WithLabelText(string val) + { + SetLabelText(val); + return this; + } + + private void UpdateSize() + { + var width = rectTrans.sizeDelta.x; + var height = rectTrans.sizeDelta.y; + labelText.rectTransform.sizeDelta = new Vector2(icon != null ? width - _iconWidth : width, height); + if (icon != null) + { + icon.transform.localPosition = new Vector3((-width - _iconWidth) * 0.5f, 0f, 0f); + } + } + + public MyCheckButton WithSize(float width, float height) + { + rectTrans.sizeDelta = new Vector2(width, height); + if (height > _iconWidth) _iconWidth = height; + UpdateSize(); + return this; + } + + public MyCheckButton WithIconWidth(float width) + { + if (_iconWidth == width) return this; + var height = rectTrans.sizeDelta.y; + if (width > height) + { + width = height; + if (_iconWidth == width) return this; + } + _iconWidth = width; + if (icon != null) UpdateSize(); + return this; + } + + public MyCheckButton WithIcon(Sprite sprite = null) + { + var trans = labelText.gameObject.transform; + if (icon == null) + { + var iconGo = new GameObject("icon"); + var rect = iconGo.AddComponent(); + (icon = iconGo.AddComponent()).sprite = sprite; + iconGo.transform.SetParent(trans); + rect.localPosition = new Vector3(0f, 0f, 0f); + rect.sizeDelta = new Vector2(_iconWidth, _iconWidth); + rect.localScale = new Vector3(1f, 1f, 1f); + rect.anchorMax = new Vector2(0f, 1f); + rect.anchorMin = new Vector2(0f, 1f); + rect.pivot = new Vector2(0f, 0.5f); + iconGo.SetActive(sprite != null); + + var width = rectTrans.sizeDelta.x; + var originPosition = labelText.rectTransform.localPosition; + labelText.rectTransform.localPosition = new Vector3(originPosition.x + _iconWidth * 0.5f, originPosition.y, originPosition.z); + labelText.rectTransform.sizeDelta = new Vector2(width - _iconWidth, labelText.rectTransform.sizeDelta.y); + } + else + { + SetIcon(sprite); + } + return this; + } + + public void SetIcon(Sprite sprite = null) + { + icon.sprite = sprite; + icon.transform.localPosition = new Vector3((-rectTrans.sizeDelta.x - _iconWidth) * 0.5f, 0f, 0f); + icon.gameObject.SetActive(sprite != null); + } + + public MyCheckButton WithCheck(bool check) + { + Checked = check; + return this; + } + + public MyCheckButton WithConfigEntry(ConfigEntry config) + { + SetConfigEntry(config); + return this; + } + + public void OnClick(int obj) + { + _checked = !_checked; + UpdateCheckColor(); + OnChecked?.Invoke(); + } + + public float Width => rectTrans.sizeDelta.x + labelText.rectTransform.sizeDelta.x; + public float Height => Math.Max(rectTrans.sizeDelta.y, labelText.rectTransform.sizeDelta.y); + + private void UpdateCheckColor() + { + if (_checked) + { + uiButton.transitions[0].mouseoverColor = openMouseOverColor; + uiButton.transitions[0].pressedColor = openPressColor; + uiButton.transitions[0].normalColor = openNormalColor; + } + else + { + uiButton.transitions[0].mouseoverColor = closeMouseOverColor; + uiButton.transitions[0].pressedColor = closePressColor; + uiButton.transitions[0].normalColor = closeNormalColor; + } + } +} diff --git a/UXAssist/UI/MyCheckbox.cs b/UXAssist/UI/MyCheckbox.cs index 4b1fb73..60b4c95 100644 --- a/UXAssist/UI/MyCheckbox.cs +++ b/UXAssist/UI/MyCheckbox.cs @@ -41,7 +41,7 @@ public class MyCheckBox : MonoBehaviour protected void OnDestroy() { - _config.SettingChanged -= _configChanged; + if (_config != null) _config.SettingChanged -= _configChanged; } public static MyCheckBox CreateCheckBox(float x, float y, RectTransform parent, ConfigEntry config, string label = "", int fontSize = 15) diff --git a/UXAssist/UI/MyWindow.cs b/UXAssist/UI/MyWindow.cs index 40774ca..aa3469f 100644 --- a/UXAssist/UI/MyWindow.cs +++ b/UXAssist/UI/MyWindow.cs @@ -564,6 +564,7 @@ public abstract class MyWindowManager public static void InitBaseObjects() { MyWindow.InitBaseObject(); + MyCheckButton.InitBaseObject(); MyCheckBox.InitBaseObject(); MyComboBox.InitBaseObject(); MyCornerComboBox.InitBaseObject();