diff --git a/Source/EngineerReport/SystemHeatEngineerReport.cs b/Source/EngineerReport/SystemHeatEngineerReport.cs index c0e8506..839501a 100644 --- a/Source/EngineerReport/SystemHeatEngineerReport.cs +++ b/Source/EngineerReport/SystemHeatEngineerReport.cs @@ -20,7 +20,18 @@ public void OnDestroy() { GameEvents.onGUIEngineersReportReady.Remove(ReportReady); GameEvents.onGUIEngineersReportDestroy.Remove(ReportDestroyed); + + RemoveTest(); + } + + // onGUIEngineersReportReady only fires once per editor session, so on a hot + // reload we need to re-add the tests manually here. + private void OnHotReload(MonoBehaviour old) + { + if (EngineersReport.Instance != null) + AddTest(); } + private void AddTest() { //Wait for DeltaV simulation to be instantiated and to finish. @@ -38,6 +49,9 @@ private void AddTest() private void RemoveTest() { + // EngineersReport may already be torn down on scene exit; tests are tied + // to its lifetime and don't need to be removed in that case. + if (EngineersReport.Instance == null) return; //Only if it was actually added, deregister it. if (tempTest != null) EngineersReport.Instance.RemoveTest(tempTest); diff --git a/Source/Modules/ModuleSystemHeatColorAnimator.cs b/Source/Modules/ModuleSystemHeatColorAnimator.cs index eb3702c..dfd7c36 100644 --- a/Source/Modules/ModuleSystemHeatColorAnimator.cs +++ b/Source/Modules/ModuleSystemHeatColorAnimator.cs @@ -84,7 +84,7 @@ protected void Start() { targetRenderers = new List(); - if (includedTransformList == "") + if (string.IsNullOrEmpty(includedTransformList)) { foreach (Transform x in part.GetComponentsInChildren()) { diff --git a/Source/SystemHeat.csproj b/Source/SystemHeat.csproj index 85fc6d1..09d48f4 100644 --- a/Source/SystemHeat.csproj +++ b/Source/SystemHeat.csproj @@ -29,6 +29,10 @@ + + + + diff --git a/Source/SystemHeatEditor.cs b/Source/SystemHeatEditor.cs index 7cb0007..c6809ba 100644 --- a/Source/SystemHeatEditor.cs +++ b/Source/SystemHeatEditor.cs @@ -40,6 +40,12 @@ protected void OnDestroy() RemoveEditorCallbacks(); Instance = null; } + + private void OnHotReload(MonoBehaviour old) + { + if (HighLogic.LoadedSceneIsEditor && EditorLogic.fetch != null) + InitializeEditorConstruct(EditorLogic.fetch.ship, false); + } protected void FixedUpdate() { if (simulator != null) @@ -51,7 +57,6 @@ protected void FixedUpdate() simulator.SimulationSpeed = SystemHeatUI.Instance.toolbarPanel.SimSituationVelocity; } simulator.SimulateEditor(); - } } #region Editor diff --git a/Source/SystemHeatGameSettings.cs b/Source/SystemHeatGameSettings.cs index 62ee6eb..4b036a4 100644 --- a/Source/SystemHeatGameSettings.cs +++ b/Source/SystemHeatGameSettings.cs @@ -5,7 +5,6 @@ namespace SystemHeat public class SystemHeatGameSettings_ReactorDamage : GameParameters.CustomParameterNode { - [GameParameters.CustomParameterUI("AllowReactorDamage", title = "#LOC_SystemHeat_Settings_AllowReactorDamage_Title", toolTip = "#LOC_SystemHeat_Settings_AllowReactorDamage_Tooltip", diff --git a/Source/SystemHeatSettings.cs b/Source/SystemHeatSettings.cs index 78b5bce..3f52e74 100644 --- a/Source/SystemHeatSettings.cs +++ b/Source/SystemHeatSettings.cs @@ -127,6 +127,7 @@ public static Color GetLoopColor(int id) { return SystemHeatSettings.ColorData[Mathf.Clamp(id, 0, 9)]; } + /// /// Load data from configuration /// @@ -216,5 +217,7 @@ public static CoolantType GetCoolantType(string name) return new CoolantType(); } } + + static void OnHotLoad() => Load(); } } diff --git a/Source/UI/Overlay/SystemHeatOverlay.cs b/Source/UI/Overlay/SystemHeatOverlay.cs index 8ab2ad0..51e430d 100644 --- a/Source/UI/Overlay/SystemHeatOverlay.cs +++ b/Source/UI/Overlay/SystemHeatOverlay.cs @@ -69,6 +69,8 @@ protected void OnDestroy() GameEvents.onEditorStarted.Remove(onEditorStart); GameEvents.OnMapEntered.Remove(onEnterMapView); GameEvents.OnMapExited.Remove(onExitMapView); + ClearPanels(); + DestroyOverlay(); Instance = null; } diff --git a/Source/UI/ReactorUI/ReactorToolbar.cs b/Source/UI/ReactorUI/ReactorToolbar.cs index c3bc182..1c8f860 100644 --- a/Source/UI/ReactorUI/ReactorToolbar.cs +++ b/Source/UI/ReactorUI/ReactorToolbar.cs @@ -212,7 +212,9 @@ public void OnDestroy() if (stockToolbarButton != null) { ApplicationLauncher.Instance.RemoveModApplication(stockToolbarButton); + stockToolbarButton = null; } + DestroyToolbarPanel(); } protected void OnToolbarButtonToggle() diff --git a/Source/UI/SystemHeatAssets.cs b/Source/UI/SystemHeatAssets.cs index 37d6558..0db711a 100644 --- a/Source/UI/SystemHeatAssets.cs +++ b/Source/UI/SystemHeatAssets.cs @@ -1,5 +1,7 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.IO; +using System.Reflection; using UnityEngine; @@ -20,6 +22,7 @@ public class SystemHeatAssets : MonoBehaviour internal static string ASSET_PATH = "GameData/SystemHeat/UI/systemheatui.dat"; internal static string SPRITE_ATLAS_NAME = "system-heat-sprites-1"; + private void Awake() { Utils.Log("[SystemHeatAssets]: Loading Assets", LogType.UI); @@ -42,5 +45,28 @@ private void Awake() } Utils.Log($"[SystemHeatAssets]: Loaded {Sprites.Count} sprites", LogType.UI); } + + // We can't load the asset bundle again - it is already loaded, and it would + // instantiate the old types. Instead, we use reflection to read them out of + // the old assembly. Hot-reloading will take care of replacing any widgets + // within. + private static void OnHotLoad(Assembly prev) + { + const BindingFlags Flags = BindingFlags.Public | BindingFlags.Static; + + var old = prev.GetType(typeof(SystemHeatAssets).FullName); + OverlayPanelPrefab = GetPrefabProperty(old, nameof(OverlayPanelPrefab)); + ToolbarPanelPrefab = GetPrefabProperty(old, nameof(ToolbarPanelPrefab)); + ToolbarPanelLoopPrefab = GetPrefabProperty(old, nameof(ToolbarPanelLoopPrefab)); + ReactorWidgetPrefab = GetPrefabProperty(old, nameof(ReactorWidgetPrefab)); + ReactorToolbarPanelPrefab = GetPrefabProperty(old, nameof(ReactorToolbarPanelPrefab)); + Sprites = (Dictionary)old.GetProperty(nameof(Sprites), Flags).GetValue(null); + } + + private static GameObject GetPrefabProperty(Type old, string name) + { + const BindingFlags Flags = BindingFlags.Public | BindingFlags.Static; + return (GameObject)old.GetProperty(name, Flags).GetValue(null); + } } } diff --git a/Source/UI/SystemHeatUI.cs b/Source/UI/SystemHeatUI.cs index d5ea89f..8694836 100644 --- a/Source/UI/SystemHeatUI.cs +++ b/Source/UI/SystemHeatUI.cs @@ -50,8 +50,14 @@ public void Start() { if (ApplicationLauncher.Ready) OnGUIAppLauncherReady(); + } - + // Explicitly destroy the toolbar panel because hot-reloading will destroy + // the old component but leave the panel game object orphaned. + private void OnHotReload(MonoBehaviour old) + { + DestroyToolbarPanel(); + toolbarPanel = null; } protected void CreateToolbarPanel() @@ -264,11 +270,12 @@ public void OnDestroy() { Utils.Log("[UI]: OnDestroy Fired", LogType.UI); // Remove the stock toolbar button - GameEvents.onGUIApplicationLauncherReady.Remove(OnGUIAppLauncherReady); if (stockToolbarButton != null) { ApplicationLauncher.Instance.RemoveModApplication(stockToolbarButton); + stockToolbarButton = null; } + DestroyToolbarPanel(); GameEvents.onGUIApplicationLauncherReady.Remove(OnGUIAppLauncherReady); GameEvents.onGUIApplicationLauncherDestroyed.Remove(OnGUIAppLauncherDestroyed); GameEvents.onGUIApplicationLauncherUnreadifying.Remove(new EventData.OnEvent(OnGUIAppLauncherUnreadifying));