From 3b7477f621c98a9e401cf8fdbd4f312f56071dae Mon Sep 17 00:00:00 2001 From: Phantomical Date: Thu, 9 Jul 2026 02:30:52 -0700 Subject: [PATCH 1/2] Fix two NRE bugs found in testing --- src/RemoteTech/Network/NetworkState.cs | 88 ++++++++++++++++++-------- 1 file changed, 61 insertions(+), 27 deletions(-) diff --git a/src/RemoteTech/Network/NetworkState.cs b/src/RemoteTech/Network/NetworkState.cs index 0f18d6fc..d2168827 100644 --- a/src/RemoteTech/Network/NetworkState.cs +++ b/src/RemoteTech/Network/NetworkState.cs @@ -21,6 +21,8 @@ internal class NetworkState : IDisposable /// JobHandle dependentHandle; + bool disposed; + ISatellite[] satellites; // The settings snapshot this state was built from; reused by point-to-point @@ -78,32 +80,32 @@ public void Dispose() public JobHandle Dispose(JobHandle deps) { - var handle = new NetworkStateDisposeJob { state = new ObjectHandle(this) } - .Schedule(JobHandle.CombineDependencies(deps, this.handle, dependentHandle)); - return handle; - } + if (disposed) + return deps; + disposed = true; - void DisposeInternal() - { - satmap.Dispose(); - nodes.Dispose(); - edges.Dispose(); - connected.Dispose(); + return new NetworkStateDisposeJob + { + satmap = satmap, + nodes = nodes, + edges = edges, + connected = connected, - scoreGs.Dispose(); - parentGs.Dispose(); - originGs.Dispose(); + scoreGs = scoreGs, + parentGs = parentGs, + originGs = originGs, - scoreCs.Dispose(); - parentCs.Dispose(); - originCs.Dispose(); + scoreCs = scoreCs, + parentCs = parentCs, + originCs = originCs, - fingerprints.Dispose(); - changedNodes.Dispose(); + fingerprints = fingerprints, + changedNodes = changedNodes, - bodies.Dispose(); - coneCandidates.Dispose(); - markCandidates.Dispose(); + bodies = bodies, + coneCandidates = coneCandidates, + markCandidates = markCandidates, + }.Schedule(JobHandle.CombineDependencies(deps, this.handle, dependentHandle)); } void AddDependentHandle(JobHandle handle) @@ -177,7 +179,7 @@ public static NetworkState ScheduleNetworkUpdate(NetworkManager manager, Network NetworkUpdate.VisibilityState visibility = new() { ActiveVessel = FlightGlobals.ActiveVessel?.id ?? default, - TargetVessel = FlightGlobals.fetch?.VesselTarget?.GetVessel().id ?? default, + TargetVessel = FlightGlobals.fetch?.VesselTarget?.GetVessel()?.id ?? default, filter = MapViewFiltering.Instance.IsNotNullOrDestroyed() ? MapViewFiltering.vesselTypeFilter : null @@ -824,16 +826,48 @@ private bool TryGetEdge(int a, int b, out NetworkEdge edge) return false; } - - + [BurstCompile] struct NetworkStateDisposeJob : IJob { - public ObjectHandle state; + public NativeHashMap satmap; + [DeallocateOnJobCompletion] + public NativeArray nodes; + [DeallocateOnJobCompletion] + public NativeArray edges; + public NativeBitArray connected; + + [DeallocateOnJobCompletion] + public NativeArray scoreGs; + [DeallocateOnJobCompletion] + public NativeArray parentGs; + [DeallocateOnJobCompletion] + public NativeArray originGs; + + [DeallocateOnJobCompletion] + public NativeArray scoreCs; + [DeallocateOnJobCompletion] + public NativeArray parentCs; + [DeallocateOnJobCompletion] + public NativeArray originCs; + + public NativeList fingerprints; + public NativeList changedNodes; + + [DeallocateOnJobCompletion] + public NativeArray bodies; + public NativeList coneCandidates; + public NativeList markCandidates; public void Execute() { - using var guard = state; - state.Target.DisposeInternal(); + satmap.Dispose(); + connected.Dispose(); + + fingerprints.Dispose(); + changedNodes.Dispose(); + + coneCandidates.Dispose(); + markCandidates.Dispose(); } } From 9fbf1209a839577a1f8636efc4add8bb2386ce57 Mon Sep 17 00:00:00 2001 From: Phantomical Date: Thu, 9 Jul 2026 18:34:23 -0700 Subject: [PATCH 2/2] Avoid a NRE when the UI is disposed after appmanager is destroyed --- src/RemoteTech/RTSpaceCentre.cs | 2 +- src/RemoteTech/UI/FocusOverlay.cs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/RemoteTech/RTSpaceCentre.cs b/src/RemoteTech/RTSpaceCentre.cs index ad0356cc..5cabf85b 100644 --- a/src/RemoteTech/RTSpaceCentre.cs +++ b/src/RemoteTech/RTSpaceCentre.cs @@ -119,7 +119,7 @@ public void OnDestroy() _optionWindow = null; - if (LauncherButton != null) + if (LauncherButton != null && ApplicationLauncher.Instance != null) { ApplicationLauncher.Instance.RemoveModApplication(LauncherButton); } diff --git a/src/RemoteTech/UI/FocusOverlay.cs b/src/RemoteTech/UI/FocusOverlay.cs index 26a62392..d991e9dd 100644 --- a/src/RemoteTech/UI/FocusOverlay.cs +++ b/src/RemoteTech/UI/FocusOverlay.cs @@ -107,7 +107,8 @@ public void Dispose() } // Remove button on destroy - KSP.UI.Screens.ApplicationLauncher.Instance.RemoveModApplication(mButton); + if (mButton != null && KSP.UI.Screens.ApplicationLauncher.Instance != null) + KSP.UI.Screens.ApplicationLauncher.Instance.RemoveModApplication(mButton); RemoveTrackingListeners(); }