diff --git a/UXAssist/Patches/LogisticsPatch.cs b/UXAssist/Patches/LogisticsPatch.cs index bbc7383..c0301a8 100644 --- a/UXAssist/Patches/LogisticsPatch.cs +++ b/UXAssist/Patches/LogisticsPatch.cs @@ -797,7 +797,7 @@ public static class LogisticsPatch { RecycleStationTips(); _lastPlanetId = 0; - _stationTipsRoot.SetActive(false); + _stationTipsRoot?.SetActive(false); } public static void OnDataLoaded() @@ -1436,7 +1436,9 @@ public static class LogisticsPatch } barPositionChanged = true; } - } else { + } + else + { if (itemCount > itemLimit) itemCount = itemLimit; } diff --git a/UXAssist/Patches/UIPatch.cs b/UXAssist/Patches/UIPatch.cs index e7cb048..75fbd8e 100644 --- a/UXAssist/Patches/UIPatch.cs +++ b/UXAssist/Patches/UIPatch.cs @@ -2,6 +2,9 @@ namespace UXAssist.Patches; using Common; using HarmonyLib; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.UI; [PatchGuid(PluginInfo.PLUGIN_GUID)] public class UIPatch : PatchImpl @@ -10,6 +13,250 @@ public class UIPatch : PatchImpl { Enable(true); Functions.UIFunctions.InitMenuButtons(); + PlanetVeinUtilization.Enable(true); + } + + public static void Uninit() + { + PlanetVeinUtilization.Enable(false); + Enable(false); + } + + private class PlanetVeinUtilization : PatchImpl + { + + private static bool planetPanelInitialized = false; + private static bool starPanelInitialized = false; + private static readonly VeinTypeInfo[] planetVeinCount = new VeinTypeInfo[(int)EVeinType.Max]; + private static readonly VeinTypeInfo[] starVeinCount = new VeinTypeInfo[(int)EVeinType.Max]; + private static readonly Dictionary tmpGroups = []; + + protected override void OnEnable() + { + InitializeVeinCountArray(planetVeinCount); + InitializeVeinCountArray(starVeinCount); + } + + #region Helper functions + private static void ProcessVeinData(VeinTypeInfo[] veinCount, VeinData[] veinPool) + { + lock (veinPool) + { + foreach (VeinData veinData in veinPool) + { + if (veinData.groupIndex == 0 || veinData.amount == 0) continue; + if (tmpGroups.TryGetValue(veinData.groupIndex, out bool hasMiner)) + { + if (hasMiner) continue; + hasMiner = veinData.minerCount > 0; + if (!hasMiner) continue; + tmpGroups[veinData.groupIndex] = true; + VeinTypeInfo vti = veinCount[(int)veinData.type]; + vti.numVeinGroupsWithCollector++; + } + else + { + hasMiner = veinData.minerCount > 0; + tmpGroups.Add(veinData.groupIndex, hasMiner); + VeinTypeInfo vti = veinCount[(int)veinData.type]; + vti.numVeinGroups++; + if (hasMiner) + { + vti.numVeinGroupsWithCollector++; + } + } + } + } + tmpGroups.Clear(); + } + + private static void FormatResource(int refId, UIResAmountEntry uiresAmountEntry, VeinTypeInfo vt) + { + if (vt.textCtrl == null) + { + var parent = uiresAmountEntry.labelText.transform.parent; + vt.textCtrl = Object.Instantiate(uiresAmountEntry.valueText, parent); + vt.textCtrl.font = uiresAmountEntry.labelText.font; + RectTransform trans = vt.textCtrl.rectTransform; + var pos = uiresAmountEntry.rectTrans.localPosition; + pos.x = pos.x + uiresAmountEntry.iconImage.rectTransform.localPosition.x - 25f; + trans.localPosition = pos; + Vector2 size = trans.sizeDelta; + size.x = 40f; + trans.sizeDelta = size; + } + else + { + RectTransform trans = vt.textCtrl.rectTransform; + Vector3 pos = trans.localPosition; + pos.y = uiresAmountEntry.rectTrans.localPosition.y; + trans.localPosition = pos; + } + vt.textCtrl.text = $"{vt.numVeinGroupsWithCollector}/{vt.numVeinGroups}"; + } + + private static void InitializeVeinCountArray(VeinTypeInfo[] veinCountArray) + { + for (int i = 0; i < veinCountArray.Length; i++) + { + veinCountArray[i] = new VeinTypeInfo(); + } + } + + private static Vector2 GetAdjustedSizeDelta(Vector2 origSizeDelta) + { + return new Vector2(origSizeDelta.x + 45f, origSizeDelta.y); + } + #endregion + + #region UIPlanetDetail patches + [HarmonyPrefix, HarmonyPatch(typeof(UIPlanetDetail), nameof(UIPlanetDetail.OnPlanetDataSet))] + public static void UIPlanetDetail_OnPlanetDataSet_Prefix(UIPlanetDetail __instance) + { + if (!planetPanelInitialized) + { + planetPanelInitialized = true; + __instance.rectTrans.sizeDelta = GetAdjustedSizeDelta(__instance.rectTrans.sizeDelta); + } + foreach (VeinTypeInfo vti in planetVeinCount) + { + vti.Reset(); + } + } + + [HarmonyPostfix, HarmonyPatch(typeof(UIPlanetDetail), nameof(UIPlanetDetail.RefreshDynamicProperties))] + public static void UIPlanetDetail_RefreshDynamicProperties_Postfix(UIPlanetDetail __instance) + { + PlanetData planet = __instance.planet; + if (planet == null || planet.runtimeVeinGroups == null || __instance.tabIndex != 0) { return; } + + int observeLevelCheck = __instance.planet == GameMain.localPlanet ? 1 : 2; + if (GameMain.history.universeObserveLevel < observeLevelCheck) { return; } + + foreach (VeinTypeInfo vti in planetVeinCount) + { + vti.numVeinGroups = 0; + vti.numVeinGroupsWithCollector = 0; + } + // count up the total number of vein groups per resource type, as well as the total number of groups that have a miner attached + PlanetFactory factory = planet.factory; + if (factory != null) + { + ProcessVeinData(planetVeinCount, factory.veinPool); + } + else + { + VeinGroup[] veinGroups = planet.runtimeVeinGroups; + lock (planet.veinGroupsLock) + { + for (int i = 1; i < veinGroups.Length; i++) + { + planetVeinCount[(int)veinGroups[i].type].numVeinGroups++; + } + } + } + + // update each resource to show the following vein group info: + // Iron: / + foreach (UIResAmountEntry uiresAmountEntry in __instance.entries) + { + int refId = uiresAmountEntry.refId; + if (refId > 0 && refId < (int)EVeinType.Max) + { + var vt = planetVeinCount[refId]; + if (vt.numVeinGroups > 0) + { + FormatResource(refId, uiresAmountEntry, vt); + } + else + { + vt.textCtrl?.gameObject.SetActive(false); + } + } + } + } + #endregion + + #region UIStarDetail patches + [HarmonyPrefix, HarmonyPatch(typeof(UIStarDetail), nameof(UIStarDetail.OnStarDataSet))] + public static void UIStaretail_OnStarDataSet_Prefix(UIStarDetail __instance) + { + if (!starPanelInitialized) + { + starPanelInitialized = true; + __instance.rectTrans.sizeDelta = GetAdjustedSizeDelta(__instance.rectTrans.sizeDelta); + } + foreach (VeinTypeInfo vti in starVeinCount) + { + vti.Reset(); + } + } + + [HarmonyPostfix, HarmonyPatch(typeof(UIStarDetail), nameof(UIStarDetail.RefreshDynamicProperties))] + public static void UIStarDetail_RefreshDynamicProperties_Postfix(UIStarDetail __instance) + { + if (__instance.star == null || __instance.tabIndex != 0) { return; } + if (GameMain.history.universeObserveLevel < 2) { return; } + + foreach (VeinTypeInfo vti in starVeinCount) + { + vti.numVeinGroups = 0; + vti.numVeinGroupsWithCollector = 0; + } + foreach (PlanetData planet in __instance.star.planets) + { + if (planet.runtimeVeinGroups == null) { continue; } + PlanetFactory factory = planet.factory; + if (factory != null) + { + ProcessVeinData(starVeinCount, factory.veinPool); + } + else + { + VeinGroup[] veinGroups = planet.runtimeVeinGroups; + lock (planet.veinGroupsLock) + { + for (int i = 1; i < veinGroups.Length; i++) + { + starVeinCount[(int)veinGroups[i].type].numVeinGroups++; + } + } + } + } + // update each resource to show the following vein group info: + // Iron: / + foreach (UIResAmountEntry uiresAmountEntry in __instance.entries) + { + int refId = uiresAmountEntry.refId; + if (refId > 0 && refId < (int)EVeinType.Max) + { + var vt = starVeinCount[refId]; + if (vt.numVeinGroups > 0) + { + FormatResource(refId, uiresAmountEntry, vt); + } + else + { + vt.textCtrl?.gameObject.SetActive(false); + } + } + } + } + #endregion + } + + public class VeinTypeInfo + { + public int numVeinGroups; + public int numVeinGroupsWithCollector; + public Text textCtrl; + + public void Reset() + { + numVeinGroups = 0; + numVeinGroupsWithCollector = 0; + if (textCtrl != null) textCtrl.text = ""; + } } // Add config button to main menu