From 94bb6f886b631a59c33c86a535afa55ea3330f8c Mon Sep 17 00:00:00 2001 From: Lorenz Junglas <4759511+lolleko@users.noreply.github.com> Date: Thu, 11 Dec 2025 09:10:03 +0100 Subject: [PATCH] Shutdown scene early (#3576) * Destroy ActiveScene early during game shutdown * Don't call into native when deleting scenemaps --- .../Sandbox.Engine/Systems/SceneSystem/SceneMap.cs | 2 +- .../Sandbox.Engine/Systems/SceneSystem/SceneWorld.cs | 12 ++++++++++-- engine/Sandbox.GameInstance/GameInstance.cs | 5 +++-- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/engine/Sandbox.Engine/Systems/SceneSystem/SceneMap.cs b/engine/Sandbox.Engine/Systems/SceneSystem/SceneMap.cs index 4a138dac..2df2afae 100644 --- a/engine/Sandbox.Engine/Systems/SceneSystem/SceneMap.cs +++ b/engine/Sandbox.Engine/Systems/SceneSystem/SceneMap.cs @@ -210,7 +210,7 @@ public sealed partial class SceneMap : IValid if ( PVS.IsValid ) { // don't destroy if another SceneWorld is using it - if ( !SceneWorld.All.Where( x => x.IsValid() && x.native.GetPVS() == PVS ).Any() ) + if ( !SceneWorld.All.Any( x => x.ActivePVS == PVS ) ) { g_pEnginePVSManager.DestroyPvs( PVS ); } diff --git a/engine/Sandbox.Engine/Systems/SceneSystem/SceneWorld.cs b/engine/Sandbox.Engine/Systems/SceneSystem/SceneWorld.cs index e6931ac9..fc6948f9 100644 --- a/engine/Sandbox.Engine/Systems/SceneSystem/SceneWorld.cs +++ b/engine/Sandbox.Engine/Systems/SceneSystem/SceneWorld.cs @@ -16,6 +16,7 @@ public sealed partial class SceneWorld : IHandle internal HashSet InternalSceneObjects { get; set; } = new(); internal HashSet InternalSceneMaps { get; set; } = new(); internal HashSet InternalSkyboxWorlds { get; set; } = new(); + internal IPVS ActivePVS { get; private set; } /// /// List of scene objects belonging to this scene world. @@ -100,6 +101,7 @@ public sealed partial class SceneWorld : IHandle CSceneSystem.DestroyWorld( this ); native = IntPtr.Zero; + ActivePVS = default; } internal void OnNativeInit( ISceneWorld ptr ) @@ -111,6 +113,7 @@ public sealed partial class SceneWorld : IHandle internal void OnNativeDestroy() { native = IntPtr.Zero; + ActivePVS = default; All.Remove( this ); } @@ -168,6 +171,7 @@ public sealed partial class SceneWorld : IHandle { //Log.Info( $"{this} - SET PVS from {sceneMap}" ); native.SetPVS( sceneMap.PVS ); + ActivePVS = sceneMap.PVS; } } } @@ -182,9 +186,13 @@ public sealed partial class SceneWorld : IHandle Log.Warning( "Couldn't remove sceneMap" ); } - if ( native.GetPVS() == sceneMap.PVS ) + if ( ActivePVS == sceneMap.PVS ) { - native.SetPVS( default ); + if ( !native.IsNull ) + { + native.SetPVS( default ); + } + ActivePVS = default; } } } diff --git a/engine/Sandbox.GameInstance/GameInstance.cs b/engine/Sandbox.GameInstance/GameInstance.cs index fd354eb0..f80a3b8b 100644 --- a/engine/Sandbox.GameInstance/GameInstance.cs +++ b/engine/Sandbox.GameInstance/GameInstance.cs @@ -106,6 +106,9 @@ internal partial class GameInstance : IGameInstance _packageAssembly = null; + // Tear down the active scene while content is still mounted so native handles remain valid during cleanup + Game.Shutdown(); + GlobalContext.Current.UISystem.Clear(); if ( activePackage != null && !Application.IsStandalone ) @@ -123,8 +126,6 @@ internal partial class GameInstance : IGameInstance GameInstanceDll.Current.Shutdown( this ); - Game.Shutdown(); - // If we were running a benchmark, leave the game if ( Application.IsBenchmark ) {