mirror of
https://github.com/soarqin/DSP_Mods.git
synced 2026-05-09 12:17:12 +08:00
fix ghost station tips persisting after planet transition
Object.Destroy(stationTip) where stationTip is a MonoBehaviour destroys only the component, leaving the cloned UI GameObject (icons, sliders, text) orphaned and potentially visible under _stationTipsRoot. When the recycle pool (128 slots) fills up during a planet with many stations, excess tips were disposed this way; those orphaned GameObjects would reappear as frozen 'ghost' tips on every subsequent planet. - Add ReleaseStationTip() helper: calls Object.Destroy(go) on the whole GameObject after SetActive(false), replacing the broken Destroy(component) - Simplify RecycleStationTips() and RecycleStationTip(int) to delegate to ReleaseStationTip() - Add HideAndRecycleStationTips() single cleanup entry point used by Enable(false), OnGameBegin(), and new OnGameEnd() - Add LocalPlanetWatcher (PatchImpl) hooking GameData.localPlanet setter: triggers HideAndRecycleStationTips() on any planet id change, covering frames where Update() is skipped by VFInput.inputing - Subscribe OnGameEnd to clear tips when exiting a save/returning to menu
This commit is contained in:
@@ -75,12 +75,14 @@ public static class LogisticsPatch
|
||||
RealtimeLogisticsInfoPanel.EnableBars(RealtimeLogisticsInfoPanelBarsEnabled.Value);
|
||||
|
||||
GameLogicProc.OnGameBegin += RealtimeLogisticsInfoPanel.OnGameBegin;
|
||||
GameLogicProc.OnGameEnd += RealtimeLogisticsInfoPanel.OnGameEnd;
|
||||
GameLogicProc.OnDataLoaded += RealtimeLogisticsInfoPanel.OnDataLoaded;
|
||||
}
|
||||
|
||||
public static void Uninit()
|
||||
{
|
||||
GameLogicProc.OnDataLoaded -= RealtimeLogisticsInfoPanel.OnDataLoaded;
|
||||
GameLogicProc.OnGameEnd -= RealtimeLogisticsInfoPanel.OnGameEnd;
|
||||
GameLogicProc.OnGameBegin -= RealtimeLogisticsInfoPanel.OnGameBegin;
|
||||
|
||||
AutoConfigLogistics.Enable(false);
|
||||
@@ -798,12 +800,13 @@ public static class LogisticsPatch
|
||||
|
||||
public static void Enable(bool on)
|
||||
{
|
||||
// Toggle the defensive localPlanet setter hook regardless of whether the GUI
|
||||
// root has been initialized yet (InitGUI may run later via OnDataLoaded).
|
||||
LocalPlanetWatcher.Enable(on);
|
||||
if (_stationTipsRoot == null) return;
|
||||
if (!on)
|
||||
{
|
||||
RecycleStationTips();
|
||||
_lastPlanetId = 0;
|
||||
_stationTipsRoot.SetActive(false);
|
||||
HideAndRecycleStationTips();
|
||||
return;
|
||||
}
|
||||
if (DSPGame.IsMenuDemo || !GameMain.isRunning)
|
||||
@@ -827,9 +830,12 @@ public static class LogisticsPatch
|
||||
|
||||
public static void OnGameBegin()
|
||||
{
|
||||
RecycleStationTips();
|
||||
_lastPlanetId = 0;
|
||||
_stationTipsRoot?.SetActive(false);
|
||||
HideAndRecycleStationTips();
|
||||
}
|
||||
|
||||
public static void OnGameEnd()
|
||||
{
|
||||
HideAndRecycleStationTips();
|
||||
}
|
||||
|
||||
public static void OnDataLoaded()
|
||||
@@ -1065,22 +1071,32 @@ public static class LogisticsPatch
|
||||
StateSprite[2] = Util.LoadEmbeddedSprite("assets/icon/in.png");
|
||||
}
|
||||
|
||||
private static void ReleaseStationTip(StationTip stationTip)
|
||||
{
|
||||
if (!stationTip) return;
|
||||
var go = stationTip.gameObject;
|
||||
if (_stationTipsRecycleCount < StationTipsRecycle.Length)
|
||||
{
|
||||
stationTip.ResetStationTip();
|
||||
go.SetActive(false);
|
||||
StationTipsRecycle[_stationTipsRecycleCount++] = stationTip;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Recycle pool is full: destroy the cloned UI GameObject (not just the
|
||||
// StationTip MonoBehaviour). Destroying only the component would leave the
|
||||
// GameObject and all its UI children orphaned under _stationTipsRoot,
|
||||
// causing "ghost" tips to remain visible whenever the root is reactivated.
|
||||
go.SetActive(false);
|
||||
Object.Destroy(go);
|
||||
}
|
||||
}
|
||||
|
||||
private static void RecycleStationTips()
|
||||
{
|
||||
foreach (var stationTip in _stationTips)
|
||||
{
|
||||
if (!stationTip) continue;
|
||||
if (_stationTipsRecycleCount < 128)
|
||||
{
|
||||
stationTip.ResetStationTip();
|
||||
stationTip.gameObject.SetActive(false);
|
||||
StationTipsRecycle[_stationTipsRecycleCount] = stationTip;
|
||||
_stationTipsRecycleCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
Object.Destroy(stationTip);
|
||||
}
|
||||
ReleaseStationTip(stationTip);
|
||||
}
|
||||
_stationTips = new StationTip[16];
|
||||
}
|
||||
@@ -1089,19 +1105,17 @@ public static class LogisticsPatch
|
||||
{
|
||||
var stationTip = _stationTips[index];
|
||||
if (!stationTip) return;
|
||||
if (_stationTipsRecycleCount < 128)
|
||||
{
|
||||
stationTip.ResetStationTip();
|
||||
stationTip.gameObject.SetActive(false);
|
||||
StationTipsRecycle[_stationTipsRecycleCount++] = stationTip;
|
||||
}
|
||||
else
|
||||
{
|
||||
Object.Destroy(stationTip);
|
||||
}
|
||||
ReleaseStationTip(stationTip);
|
||||
_stationTips[index] = null;
|
||||
}
|
||||
|
||||
private static void HideAndRecycleStationTips()
|
||||
{
|
||||
_stationTipsRoot?.SetActive(false);
|
||||
RecycleStationTips();
|
||||
_lastPlanetId = 0;
|
||||
}
|
||||
|
||||
private static StationTip AllocateStationTip()
|
||||
{
|
||||
if (_stationTipsRecycleCount > 0)
|
||||
@@ -1247,6 +1261,26 @@ public static class LogisticsPatch
|
||||
}
|
||||
}
|
||||
|
||||
// Defensive Harmony hook on GameData.localPlanet setter.
|
||||
// It guarantees tips are hidden and recycled when the local planet id changes,
|
||||
// even if UXAssist.Update() is skipped that frame (e.g. by VFInput.inputing
|
||||
// while the player is typing while transitioning between planets, or by a brief
|
||||
// !GameMain.isRunning state during loading). _lastPlanetId is reset to 0 here so
|
||||
// the next StationInfoPanelsUpdate() re-validates factoryLoaded/transport/viewMode
|
||||
// and re-allocates fresh tips for the new planet.
|
||||
private class LocalPlanetWatcher : PatchImpl<LocalPlanetWatcher>
|
||||
{
|
||||
[HarmonyPrefix]
|
||||
[HarmonyPatch(typeof(GameData), nameof(GameData.localPlanet), MethodType.Setter)]
|
||||
private static void GameData_localPlanet_Setter_Prefix(GameData __instance, PlanetData value)
|
||||
{
|
||||
var oldId = __instance.localPlanet?.id ?? 0;
|
||||
var newId = value?.id ?? 0;
|
||||
if (oldId == newId) return;
|
||||
HideAndRecycleStationTips();
|
||||
}
|
||||
}
|
||||
|
||||
public class StationTip : MonoBehaviour
|
||||
{
|
||||
[FormerlySerializedAs("RectTransform")]
|
||||
|
||||
Reference in New Issue
Block a user