From 245d5292629fe61c1238583f687e36e1219cebef Mon Sep 17 00:00:00 2001 From: Soar Qin Date: Tue, 3 Sep 2024 03:20:10 +0800 Subject: [PATCH] work in progress --- UXAssist/LogisticsPatch.cs | 313 +++++++++++++++++++++------------- UXAssist/UXAssist.cs | 2 + UXAssist/assets/icon/in.png | Bin 2193 -> 3907 bytes UXAssist/assets/icon/keep.png | Bin 925 -> 1245 bytes UXAssist/assets/icon/out.png | Bin 2179 -> 3918 bytes 5 files changed, 193 insertions(+), 122 deletions(-) diff --git a/UXAssist/LogisticsPatch.cs b/UXAssist/LogisticsPatch.cs index d8b64f3..f1f4dfb 100644 --- a/UXAssist/LogisticsPatch.cs +++ b/UXAssist/LogisticsPatch.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using System.Reflection.Emit; using BepInEx.Configuration; @@ -17,32 +18,42 @@ public static class LogisticsPatch public static ConfigEntry LogisticsCapacityTweaksEnabled; public static ConfigEntry AllowOverflowInLogisticsEnabled; public static ConfigEntry LogisticsConstrolPanelImprovementEnabled; + public static ConfigEntry RealtimeLogisticsInfoPanelEnabled; public static void Init() { LogisticsCapacityTweaksEnabled.SettingChanged += (_, _) => LogisticsCapacityTweaks.Enable(LogisticsCapacityTweaksEnabled.Value); AllowOverflowInLogisticsEnabled.SettingChanged += (_, _) => AllowOverflowInLogistics.Enable(AllowOverflowInLogisticsEnabled.Value); LogisticsConstrolPanelImprovementEnabled.SettingChanged += (_, _) => LogisticsConstrolPanelImprovement.Enable(LogisticsConstrolPanelImprovementEnabled.Value); + RealtimeLogisticsInfoPanelEnabled.SettingChanged += (_, _) => RealtimeLogisticsInfoPanel.Enable(RealtimeLogisticsInfoPanelEnabled.Value); LogisticsCapacityTweaks.Enable(LogisticsCapacityTweaksEnabled.Value); AllowOverflowInLogistics.Enable(AllowOverflowInLogisticsEnabled.Value); LogisticsConstrolPanelImprovement.Enable(LogisticsConstrolPanelImprovementEnabled.Value); + + GameLogic.OnGameBegin += RealtimeLogisticsInfoPanel.OnGameBegin; } public static void Uninit() { + GameLogic.OnGameBegin -= RealtimeLogisticsInfoPanel.OnGameBegin; + LogisticsCapacityTweaks.Enable(false); AllowOverflowInLogistics.Enable(false); LogisticsConstrolPanelImprovement.Enable(false); + RealtimeLogisticsInfoPanel.Enable(false); } public static void Start() { - LogisticsInfoWindow.InitGUI(); + RealtimeLogisticsInfoPanel.InitGUI(); } public static void OnUpdate() { - LogisticsInfoWindow.StationInfoWindowUpdate(); + if (RealtimeLogisticsInfoPanelEnabled.Value) + { + RealtimeLogisticsInfoPanel.StationInfoPanelsUpdate(); + } } public static class LogisticsCapacityTweaks @@ -466,24 +477,36 @@ public static class LogisticsPatch } } - private static class LogisticsInfoWindow + private static class RealtimeLogisticsInfoPanel { - private static int _maxCount; - private static StationTip[] _stationtips = new StationTip[_maxCount]; + private static StationTip[] _stationTips = new StationTip[16]; private static GameObject _stationTipRoot; private static GameObject _tipPrefab; - private static readonly Color OrangeColor = new(224f / 255, 139f / 255, 93f / 255); - private static readonly Color BlueColor = new(75f / 255, 172f / 255, 205f / 255); + private static readonly Color DemandColor = new(223.7f / 255, 139.6f / 255, 94f / 255); + private static readonly Color SupplyColor = new(60f / 255, 139f / 255, 166f / 255); private static Sprite _leftsprite; private static Sprite _rightsprite; private static Sprite _flatsprite; + private static PlanetData _lastPlanet; + + public static void Enable(bool on) + { + _stationTipRoot?.SetActive(on); + } + + public static void OnGameBegin() + { + _lastPlanet = null; + } + public static void InitGUI() { _leftsprite = Util.LoadEmbeddedSprite("assets/icon/in.png"); _rightsprite = Util.LoadEmbeddedSprite("assets/icon/out.png"); _flatsprite = Util.LoadEmbeddedSprite("assets/icon/keep.png"); - _stationTipRoot = UnityEngine.Object.Instantiate(GameObject.Find("UI Root/Overlay Canvas/In Game/Scene UIs/Vein Marks"), GameObject.Find("UI Root/Overlay Canvas/In Game/Scene UIs").transform); + _stationTipRoot = UnityEngine.Object.Instantiate(GameObject.Find("UI Root/Overlay Canvas/In Game/Scene UIs/Vein Marks"), + GameObject.Find("UI Root/Overlay Canvas/In Game/Scene UIs").transform); _stationTipRoot.name = "stationTip"; UnityEngine.Object.Destroy(_stationTipRoot.GetComponent()); _tipPrefab = UnityEngine.Object.Instantiate(GameObject.Find("UI Root/Overlay Canvas/In Game/Scene UIs/Vein Marks/vein-tip-prefab"), _stationTipRoot.transform); @@ -534,15 +557,17 @@ public static class LogisticsPatch stateRemote.GetComponent().pivot = new Vector2(0, 1); stateRemote.GetComponent().anchoredPosition3D = new Vector3(105, y - 15, 0); } + for (var i = 0; i < 3; i++) { - var iconText = UnityEngine.Object.Instantiate(GameObject.Find("UI Root/Overlay Canvas/In Game/Top Tips/Entity Briefs/brief-info-top/brief-info/content/icons/icon"), new Vector3(0, 0, 0), Quaternion.identity, _tipPrefab.transform); + var iconText = UnityEngine.Object.Instantiate(GameObject.Find("UI Root/Overlay Canvas/In Game/Top Tips/Entity Briefs/brief-info-top/brief-info/content/icons/icon"), + new Vector3(0, 0, 0), Quaternion.identity, _tipPrefab.transform); UnityEngine.Object.Destroy(iconText.transform.Find("count-text").gameObject); UnityEngine.Object.Destroy(iconText.transform.Find("bg").gameObject); UnityEngine.Object.Destroy(iconText.transform.Find("inc").gameObject); UnityEngine.Object.Destroy(iconText.GetComponent()); - iconText.name = "iconText" + i; + iconText.name = "carrierIconText" + i; iconText.GetComponent().localScale = new Vector3(0.7f, 0.7f, 1); iconText.GetComponent().anchorMax = new Vector2(0, 1); iconText.GetComponent().anchorMin = new Vector2(0, 1); @@ -551,7 +576,7 @@ public static class LogisticsPatch var countText = UnityEngine.Object.Instantiate(infoText, Vector3.zero, Quaternion.identity, iconText.transform); UnityEngine.Object.Destroy(countText.GetComponent()); - countText.name = "countText"; + countText.name = "carrierIdleCountText"; countText.GetComponent().fontSize = 22; countText.GetComponent().text = "100"; countText.GetComponent().alignment = TextAnchor.MiddleRight; @@ -561,12 +586,12 @@ public static class LogisticsPatch countText.GetComponent().pivot = new Vector2(0, 1); countText.GetComponent().localPosition = new Vector3(-50, -20, 0); - if (i == 2) continue; + if (i >= 2) continue; countText = UnityEngine.Object.Instantiate(infoText, Vector3.zero, Quaternion.identity, iconText.transform); UnityEngine.Object.Destroy(countText.GetComponent()); - countText.name = "countText2"; + countText.name = "carrierTotalCountText"; countText.GetComponent().fontSize = 22; countText.GetComponent().text = "100"; countText.GetComponent().alignment = TextAnchor.MiddleRight; @@ -576,30 +601,28 @@ public static class LogisticsPatch countText.GetComponent().pivot = new Vector2(0, 1); countText.GetComponent().localPosition = new Vector3(-50, 10, 0); } + _tipPrefab.transform.Find("icon").gameObject.SetActive(false); _tipPrefab.SetActive(false); - for (var i = 0; i < _maxCount; ++i) - { - var temptip = UnityEngine.Object.Instantiate(_tipPrefab, _stationTipRoot.transform); - var tempstationtip = temptip.AddComponent(); - _stationtips[i] = tempstationtip; - } } public class StationTip : MonoBehaviour { - [FormerlySerializedAs("RectTransform")] public RectTransform rectTransform; + [FormerlySerializedAs("RectTransform")] + public RectTransform rectTransform; + private Transform[] _icons; private RectTransform[] _iconRectTransforms; private Transform[] _iconLocals; private Transform[] _iconRemotes; private Transform[] _countTexts; - private Transform[] _iconTexts; - private Text[] _countText; - private Text[] _countText2; + private Transform[] _carrierIconTexts; + private Text[] _carrierIdleCountText; + private Text[] _carrierTotalCountText; private GameObject _infoText; + private int _layout = -1; public void InitStationTip() { @@ -608,22 +631,18 @@ public static class LogisticsPatch _iconLocals = new Transform[13]; _iconRemotes = new Transform[13]; _countTexts = new Transform[13]; - _iconTexts = new Transform[3]; - - - _countText = new Text[3]; - _countText2 = new Text[3]; + _carrierIconTexts = new Transform[3]; + _carrierIdleCountText = new Text[3]; + _carrierTotalCountText = new Text[2]; _iconRectTransforms = new RectTransform[13]; _infoText = transform.Find("info-text").gameObject; for (var i = 0; i < 3; i++) { - _iconTexts[i] = transform.Find("iconText" + i); - _countText[i] = _iconTexts[i].Find("countText").GetComponent(); - if (i != 2) - { - _countText2[i] = _iconTexts[i].Find("countText2").GetComponent(); - } + _carrierIconTexts[i] = transform.Find("carrierIconText" + i); + _carrierIdleCountText[i] = _carrierIconTexts[i].Find("carrierIdleCountText").GetComponent(); + if (i >= 2) continue; + _carrierTotalCountText[i] = _carrierIconTexts[i].Find("carrierTotalCountText").GetComponent(); } for (var i = 0; i < 13; i++) @@ -670,7 +689,7 @@ public static class LogisticsPatch } } - public void SetItem(int itemId, int itemCount, int i, ELogisticStorage localLogic, ELogisticStorage remoteLogic, bool isStellarorCollector) + public void SetItem(int itemId, int itemCount, int i, ELogisticStorage localLogic, ELogisticStorage remoteLogic, bool isStellar, bool isCollector) { var icon = _icons[i]; var iconPos = _iconRectTransforms[i].anchoredPosition3D; @@ -682,57 +701,67 @@ public static class LogisticsPatch var countUIText = countText.GetComponent(); if (itemId > 0) { - switch (localLogic) + if (!isCollector) { - case ELogisticStorage.Supply: - iconLocalImage.sprite = _rightsprite; - iconLocalImage.color = BlueColor; - countUIText.color = BlueColor; - break; - case ELogisticStorage.Demand: - iconLocalImage.sprite = _leftsprite; - iconLocalImage.color = OrangeColor; - countUIText.color = OrangeColor; - break; - case ELogisticStorage.None: - iconLocalImage.sprite = _flatsprite; - iconLocalImage.color = Color.gray; - countUIText.color = Color.gray; - break; + switch (localLogic) + { + case ELogisticStorage.Supply: + iconLocalImage.sprite = _rightsprite; + iconLocalImage.color = SupplyColor; + countUIText.color = SupplyColor; + break; + case ELogisticStorage.Demand: + iconLocalImage.sprite = _leftsprite; + iconLocalImage.color = DemandColor; + countUIText.color = DemandColor; + break; + case ELogisticStorage.None: + iconLocalImage.sprite = _flatsprite; + iconLocalImage.color = Color.gray; + countUIText.color = Color.gray; + break; + } } - if (isStellarorCollector) + if (isStellar || isCollector) { switch (remoteLogic) { case ELogisticStorage.Supply: iconRemoteImage.sprite = _rightsprite; - iconRemoteImage.color = BlueColor; + iconRemoteImage.color = SupplyColor; break; case ELogisticStorage.Demand: iconRemoteImage.sprite = _leftsprite; - iconRemoteImage.color = OrangeColor; + iconRemoteImage.color = DemandColor; break; case ELogisticStorage.None: iconRemoteImage.sprite = _flatsprite; iconRemoteImage.color = Color.gray; break; } - - iconRemote.gameObject.SetActive(true); } - iconLocal.gameObject.SetActive(true); countText.GetComponent().anchoredPosition3D = new Vector3(70, iconPos.y, 0); - if (isStellarorCollector) + if (isCollector) { + iconLocal.gameObject.SetActive(false); + iconRemote.gameObject.SetActive(true); + iconRemote.GetComponent().anchoredPosition3D = new Vector3(100, iconPos.y, 0); + iconRemote.GetComponent().sizeDelta = new Vector2(30, 30); + } + else if (isStellar) + { + iconLocal.gameObject.SetActive(true); + iconRemote.gameObject.SetActive(true); iconLocal.GetComponent().sizeDelta = new Vector2(20, 20); iconRemote.GetComponent().sizeDelta = new Vector2(20, 20); - iconLocal.GetComponent().anchoredPosition3D = new Vector3(105, iconPos.y, 0); - iconRemote.GetComponent().anchoredPosition3D = new Vector3(105, iconPos.y - 15, 0); + iconLocal.GetComponent().anchoredPosition3D = new Vector3(105, iconPos.y + 2, 0); + iconRemote.GetComponent().anchoredPosition3D = new Vector3(105, iconPos.y - 13, 0); } else { + iconLocal.gameObject.SetActive(true); iconRemote.gameObject.SetActive(false); iconLocal.GetComponent().anchoredPosition3D = new Vector3(100, iconPos.y, 0); iconLocal.GetComponent().sizeDelta = new Vector2(30, 30); @@ -740,7 +769,7 @@ public static class LogisticsPatch icon.GetComponent().sprite = LDB.items.Select(itemId)?.iconSprite; icon.gameObject.SetActive(true); - countUIText.text = itemCount.ToString("#,##0"); + countUIText.text = itemCount.ToString(CultureInfo.CurrentCulture); } else { @@ -748,10 +777,8 @@ public static class LogisticsPatch iconRemote.gameObject.SetActive(false); icon.gameObject.SetActive(false); countUIText.color = Color.white; - countUIText.text = "无"; - var anchoredX = showStationInfoMode ? isStellarorCollector ? 70 : 90 : 70; - - countUIText.GetComponent().anchoredPosition3D = new Vector3(anchoredX, iconPos.y, 0); + countUIText.text = "— "; + countUIText.GetComponent().anchoredPosition3D = new Vector3(70, iconPos.y, 0); } countText.gameObject.SetActive(true); @@ -761,28 +788,47 @@ public static class LogisticsPatch { if (itemId == 0) { - _iconTexts[index].gameObject.SetActive(false); + _carrierIconTexts[index].gameObject.SetActive(false); return; } if (index < 2) { - _countText2[index].color = Color.white; - _countText2[index].text = currentCount.ToString(); + _carrierTotalCountText[index].color = Color.white; + _carrierTotalCountText[index].text = currentCount.ToString(); } - _iconTexts[index].gameObject.GetComponent().anchoredPosition3D = new Vector3(index * 30, -30 - 30 * lastLine, 0); - _iconTexts[index].GetComponent().sprite = LDB.items.Select(itemId).iconSprite; - _countText[index].color = Color.white; - _countText[index].text = totalCount.ToString(); - _iconTexts[index].gameObject.SetActive(true); + _carrierIconTexts[index].gameObject.GetComponent().anchoredPosition3D = new Vector3(index * 30, -30 - 30 * lastLine, 0); + _carrierIconTexts[index].GetComponent().sprite = LDB.items.Select(itemId).iconSprite; + _carrierIdleCountText[index].color = Color.white; + _carrierIdleCountText[index].text = totalCount.ToString(); + _carrierIconTexts[index].gameObject.SetActive(true); } } - public static void StationInfoWindowUpdate() + public static void StationInfoPanelsUpdate() { - var pd = GameMain.localPlanet; - var transport = pd?.factory?.transport; + var localPlanet = GameMain.localPlanet; + if (localPlanet == null) + { + if (_lastPlanet == null) return; + _lastPlanet = null; + _stationTipRoot.SetActive(false); + return; + } + + if (_lastPlanet != localPlanet) + { + foreach (var stationTip in _stationTips) + { + stationTip?.gameObject.SetActive(false); + } + + _lastPlanet = localPlanet; + } + + var factory = localPlanet.factory; + var transport = factory?.transport; if (transport == null || transport.stationCursor == 0 || (UIGame.viewMode != EViewMode.Normal && UIGame.viewMode != EViewMode.Globe)) { if (_stationTipRoot.activeSelf) @@ -794,27 +840,53 @@ public static class LogisticsPatch } _stationTipRoot.SetActive(true); - var tipIndex = 0; var localPosition = GameCamera.main.transform.localPosition; var forward = GameCamera.main.transform.forward; - var realRadius = pd.realRadius; + var realRadius = localPlanet.realRadius; - foreach (var stationComponent in transport.stationPool) + var stationCount = transport.stationCursor; + if (stationCount >= _stationTips.Length) { - if (stationComponent?.storage == null) continue; - if (tipIndex == _maxCount) + var newSize = stationCount; + newSize |= newSize >> 1; + newSize |= newSize >> 2; + newSize |= newSize >> 4; + newSize |= newSize >> 8; + newSize |= newSize >> 16; + newSize++; + Array.Resize(ref _stationTips, newSize); + } + + for (var i = stationCount - 1; i >= 0; i--) + { + var stationComponent = transport.stationPool[i]; + var storageArray = stationComponent?.storage; + if (storageArray == null) { - _maxCount++; - var temptip = UnityEngine.Object.Instantiate(_tipPrefab, _stationTipRoot.transform); - var tempstationtip = temptip.AddComponent(); - tempstationtip.InitStationTip(); - Array.Resize(ref _stationtips, _maxCount); - _stationtips[_maxCount - 1] = tempstationtip; + _stationTips[i]?.gameObject.SetActive(false); + continue; } - var isStellarorCollector = stationComponent.isStellar || stationComponent.isCollector; - var position = pd.factory.entityPool[stationComponent.entityId].pos.normalized; - var storageNum = Math.Min(stationComponent.storage.Length, 5); + #if DEBUG + if (i != stationComponent.id) + { + UXAssist.Logger.LogWarning($"Station index mismatch: {i} != {stationComponent.id}"); + _stationTips[i]?.gameObject.SetActive(false); + continue; + } + #endif + + var stationTip = _stationTips[i]; + if (!stationTip) + { + var tempTip = UnityEngine.Object.Instantiate(_tipPrefab, _stationTipRoot.transform); + stationTip = tempTip.AddComponent(); + stationTip.InitStationTip(); + _stationTips[i] = stationTip; + } + + var position = factory.entityPool[stationComponent.entityId].pos.normalized; + var storageNum = Math.Min(storageArray.Length, 5); float tipWindowHeight = 40 * storageNum + 20; if (stationComponent.isCollector) { @@ -833,57 +905,57 @@ public static class LogisticsPatch position *= realRadius + 15; } - var stationtip = _stationtips[tipIndex]; var vec = position - localPosition; var magnitude = vec.magnitude; - if (magnitude < 1.0 || Vector3.Dot(forward, vec) < 1.0) + if (magnitude < 1.0 + || Vector3.Dot(forward, vec) < 1.0 + || !UIRoot.ScreenPointIntoRect(GameCamera.main.WorldToScreenPoint(position), _stationTipRoot.GetComponent(), out var rectPoint) + || rectPoint.x is < -4096f or > 4096f + || rectPoint.y is < -4096f or > 4096f + || Phys.RayCastSphere(localPosition, vec / magnitude, magnitude, Vector3.zero, realRadius, out _) + || storageArray.Select(x => x.itemId).All(x => x == 0)) + { + stationTip.gameObject.SetActive(false); continue; - if (!UIRoot.ScreenPointIntoRect(GameCamera.main.WorldToScreenPoint(position), _stationTipRoot.GetComponent(), out var rectPoint)) - continue; - if (rectPoint.x is < -4096f or > 4096f || rectPoint.y is < -4096f or > 4096f) - continue; - if (Phys.RayCastSphere(localPosition, vec / magnitude, magnitude, Vector3.zero, realRadius, out _)) - continue; - if (stationComponent.storage.Select(x => x.itemId).All(x => x == 0)) - continue; - tipIndex++; - stationtip.gameObject.SetActive(true); + } + + stationTip.gameObject.SetActive(true); rectPoint.x = Mathf.Round(rectPoint.x); rectPoint.y = Mathf.Round(rectPoint.y); - stationtip.rectTransform.anchoredPosition = rectPoint; - for (var i = 0; i < storageNum; ++i) + stationTip.rectTransform.anchoredPosition = rectPoint; + for (var j = storageNum - 1; j >= 0; j--) { - var storage = stationComponent.storage[i]; - stationtip.SetItem(storage.itemId, storage.count, i, storage.localLogic, storage.remoteLogic, /*ShowStationInfoMode.Value*/isStellarorCollector); + var storage = storageArray[j]; + stationTip.SetItem(storage.itemId, storage.count, j, storage.localLogic, storage.remoteLogic, stationComponent.isStellar, stationComponent.isCollector); } var lastLine = storageNum; - var stationComponentName = pd.factory.ReadExtraInfoOnEntity(stationComponent.entityId); - stationtip.SetStationName(stationComponentName, lastLine); + var stationComponentName = factory.ReadExtraInfoOnEntity(stationComponent.entityId); + stationTip.SetStationName(stationComponentName, lastLine); if (!string.IsNullOrEmpty(stationComponentName)) { tipWindowHeight += 27; lastLine++; } - for (var i = 0; i < 3; ++i) + for (var j = 0; j < 3; ++j) { - if (stationComponent.isCollector || stationComponent.isVeinCollector || (i >= 1 && !stationComponent.isStellar)) + if (stationComponent.isCollector || stationComponent.isVeinCollector || (j >= 1 && !stationComponent.isStellar)) { - stationtip.SetDroneShipWarp(i, 0, 0, 0, lastLine); + stationTip.SetDroneShipWarp(j, 0, 0, 0, lastLine); continue; } int itemId; int totalCount; var currentCount = 0; - if (i == 0) + if (j == 0) { itemId = 5001; totalCount = stationComponent.idleDroneCount + stationComponent.workDroneCount; currentCount = stationComponent.idleDroneCount; } - else if (i == 1) + else if (j == 1) { itemId = 5002; totalCount = stationComponent.idleShipCount + stationComponent.workShipCount; @@ -895,22 +967,19 @@ public static class LogisticsPatch totalCount = stationComponent.warperCount; } - stationtip.SetDroneShipWarp(i, itemId, totalCount, currentCount, lastLine); + stationTip.SetDroneShipWarp(j, itemId, totalCount, currentCount, lastLine); } float localScaleMultiple; - if (magnitude < 50.0) + if (magnitude < 50f) localScaleMultiple = 1.5f; - else if (magnitude < 250.0) - localScaleMultiple = (float)(1.75 - magnitude * 0.005); + else if (magnitude < 250f) + localScaleMultiple = (float)(1.75f - magnitude * 0.005f); else localScaleMultiple = 0.5f; - stationtip.transform.localScale = Vector3.one * localScaleMultiple; - stationtip.rectTransform.sizeDelta = new Vector2(125f, tipWindowHeight); + stationTip.transform.localScale = Vector3.one * localScaleMultiple; + stationTip.rectTransform.sizeDelta = new Vector2(125f, tipWindowHeight); } - - for (var i = tipIndex; i < _maxCount; ++i) - _stationtips[i].gameObject.SetActive(false); } } } \ No newline at end of file diff --git a/UXAssist/UXAssist.cs b/UXAssist/UXAssist.cs index b6119a1..62d15e4 100644 --- a/UXAssist/UXAssist.cs +++ b/UXAssist/UXAssist.cs @@ -115,6 +115,8 @@ public class UXAssist : BaseUnityPlugin, IModCanSave "Allow overflow in logistic stations"); LogisticsPatch.LogisticsConstrolPanelImprovementEnabled = Config.Bind("Factory", "LogisticsConstrolPanelImprovement", false, "Logistics control panel improvement"); + LogisticsPatch.RealtimeLogisticsInfoPanelEnabled = Config.Bind("Factory", "RealtimeLogisticsInfoPanel", false, + "Realtime logistics info panel"); PlanetFunctions.OrbitalCollectorMaxBuildCount = Config.Bind("Factory", "OCMaxBuildCount", 0, "Maximum Orbital Collectors to build once, set to 0 to build as many as possible"); PlayerPatch.EnhancedMechaForgeCountControlEnabled = Config.Bind("Player", "EnhancedMechaForgeCountControl", false, "Enhanced count control for hand-make, increases maximum of count to 1000, and you can hold Ctrl/Shift/Alt to change the count rapidly"); diff --git a/UXAssist/assets/icon/in.png b/UXAssist/assets/icon/in.png index 01ff5a1801a4fa6357a4421e0b139aa6a7cb0277..1826f29647fe705f85d533c288d95c76722899a1 100644 GIT binary patch literal 3907 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 diff --git a/UXAssist/assets/icon/keep.png b/UXAssist/assets/icon/keep.png index e020c414e0495e700b1c7cfbb185e6370bfd1200..c7f76cdce7a6f714d42945bdd5021ddb2f77b552 100644 GIT binary patch delta 909 zcmbQsewTBC11BS2fKQ04dx6iyz}$%maT609>V5UXlNcBnB1?k&f*C|RfBss^xazmr zpQmD$cX_9uT5VYB4=xBf}Pt3`Tz2Hv|iZocs( zm}9%kHMhpY2VLFo1#yYA7J9b$T;JNhY1Z6nQ@dvvO5d<$U|{C(ba4!+xb^n#^B|=_ z5!Z*@X1yxRLM%QUD`pg*vwZ!;ruhDU*R;3;^J~w|E3DObcpG}D^=@db^W=|=!u20E ztvq@8?bE4FhQh5=pO*Je4&L>Z3H)WdWJCQ*sk=5cCG+QhTeN!n%J=`Gl&zxge!XLVrSn~$ zj6TcGUX6qsYY)8hopPb@m)Mfkfk#%IpZdXh%EkK6H}=c7>R84w$WLJkDSpQID$wih zpa1hGg*60Sws5fSdU^ZZ{{EtOKFl&NSuHl**>AT%JR#w(frA~_E2(?`|1ObuP;^Dd zLECGV8TW<-k_qQ@4$MkxVBY*ZKJ_fa)566JlRMKIQZ8#8$P_V66iJ9SJ$w5~cmoW$0z!BLR2UdJ92l4c8W>m<@Gy5XC^yfP{3*_)6L#!gO3Io| zE94U_Zl9N%#&0nHZTk7s>>B^}&-cY`&g?~Z#LVjqKJ~gM+sM?b;;{+IDT^7_|J%At zdlloFxHWs$NF8`}_15}-Pha(e1lH?UA85K-d1sY-&YTF@je>k8%v;ueD?Zcr!qL0T zov$xW>)m}TV{U<6U5xu~yuEIdmw()#;Zb9E`?TMO>!-#wa9?IvxPIIJJ7x75U9!8a zBMkW#lzsT*|N5_Dc<8P8S~LC+ulVEn7cSrY|5kFnhqTsj>6P9M0lTl>xWAHBeJ5}0 zUuoxqzJ3q#7d+na|NZs@f2}U8U=4rywd3`_IH^5*%m28B+~sGQSI_h7jQ-VPN9U(^ zlI!o)IJan{p4Zu18-Q7i!PC{xWt~$(69AB!ll%Yx literal 925 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 E2j=Vem;e9( literal 2179 zcmeHH|3A}-AAi61MQmtdXJsAYD!IgnkZ;!*(l*0wK04!a=S$tF?dW`aukxiYy0TBA z!ld%$$aGOwvQ6ouL`pbymoFuAn=ssFX1nzV++T2?=P%Fa~z^!v=O+4~bl}#gk1vK^Hr}bJv4T}sU zrG@GKkAKqy?sYf`^s8`#LnB83otu6$6R*pP;@e#vHkN42aeub246Rbv2aohgZ%%(} zJ3k(Jjil{m|J7Czgv3Uky}!G>`o{yd549V+<2Sf(E=dOfWNrvCAoA$znTia0Bneko zIPtXL%NWMUjT2mp0Dmt;Ua)!K`AvpNZWrrZhHyI{BxhDTTz)&1^}(J*G5sh%GHdNU zoAqJUhdEX`6+cUG&6q9HpUgkuP(aN4@&CO$_1Ez&?LJl|cGl5vq>h3Vrx#aLnK}FN zaujEu?(s5FPL&VqoNxo{rTDZMQ4>8?lISF(EXr;QKQ`vZ5k5+okWgBunT9dB_WH$#JrJOiwq!s#T|PQWPmW5qS*g`_XqKAUN?pqiokwchXJZ*mt=eu_ z11(NLQx^_sXD_G}0m2@lGFE>6qujBRo9;xVdl#y-H;toOa1iz86Y;9FC zA?P6FYS~??hTAn*5zSL;Hn6}q_0*>Ha^P|^i?Nfo;sP6Ju=G!B^F_q|)}1v5b)}2o zNn8-Pmj{y{B+v8xoE*fGSFO#zPJMxN4$D9D#c~5Ng&P_UzK(!%5_P}qMBim?pDSa1 zcHLlC@zNWXdfPz8np{dB;uB z=VpL2+n=Ere02Mr6LfH8U_4R5z&2ZRqru}qJBo^ki{jb?wJ_ zbMUw1hJc;GZWPrZE}ZKI6vA3SoP~|4Ka=YP`~)h1S4b%wV;P6x-T?}M>qrKI3YGpB zJNNmRYN=*sq}rjb9(B~Dzu!-As+$F-g0b0A=Da~zC9FKRDrDNkY>l-4k-Wyl*{sI2 z$|@Kx-=Z8I-U^r3SFNRb6LB`ZJ%j1>cE--#VkX@VV1e02p;`~s_UT=5`MEZ3WN(WO zo9wNPWD!LMm1Yu%yEpb3IWsWHKU~UqIr^N(kWfZq)_LDL)6IWUozznNluzRRzA-`j zC5)y48C4d*8is3ZDCx?+(DBm%w^WpoYrJ_lpNU*K$CD zYARSI%-*cy9`OULplTpnlMHiKY%vl);co&QA^jjVMzMTR_tVi#?(>zOmSfh=S-L{L zSL!g!w?~3%Pj>Trf`H@2(V$kjGI|j2POlw_h3cB_-D3qG_Sb;uiF3bU zpzhP-WfdeL4@NW=oWNhS@YjULJbpOD
?k}~a)WiANDSwj@2En#cF?X(>=*$~6R zT8P_d4{isMxe3oAs}4t!k2$=fwU%GIJJ`4!pI`oPI7%S&Z#xhj%+2Re4$-snii`$y zNw!~$I8kEx(M^@(UA^q@x=NNJ^3P4H)B3yE!coP-Hd*SHg$gvrVPVOAwkxB;(OI5) zF7Nb09~L*S3{qBrQz-lrJ?@bZxSGraecQ(OACtN;kp+LOFja*D*gn&r4XQnTVfzms zCgK$H`;HFu2F#~Fe|OCFXENF;3vXVKdf&?h754Z6LdAaZhj2XfOd-JX^TY3Wn}U|C zHVH6tlgEVRjLIWWvHkKB^$m_z`5~e40`mJz^#;ewe6>l4Twb(}7?Ut6c}dKYm>VRL gu>bT70U%NXcZm(p&+9n!=2KHhAeq?oRowBv0YXFa4gdfE