From d9ed016297b04d0537a1c6f3f599d772b6d49089 Mon Sep 17 00:00:00 2001 From: "j.foucher" Date: Tue, 5 May 2026 13:28:39 +0200 Subject: [PATCH] Reset bIsEditorModeActive on editor-PC EndPlay and SceneLoader entry Co-Authored-By: Claude Opus 4.7 (1M context) --- .../GameMode/PS_Editor_PlayerController.cpp | 14 ++++++++++++++ .../GameMode/PS_Editor_PlayerController.h | 1 + .../Serialization/PS_Editor_SceneLoader.cpp | 7 +++++++ 3 files changed, 22 insertions(+) diff --git a/Unreal/Plugins/PS_Editor/Source/PS_Editor/GameMode/PS_Editor_PlayerController.cpp b/Unreal/Plugins/PS_Editor/Source/PS_Editor/GameMode/PS_Editor_PlayerController.cpp index e178208..1dde091 100644 --- a/Unreal/Plugins/PS_Editor/Source/PS_Editor/GameMode/PS_Editor_PlayerController.cpp +++ b/Unreal/Plugins/PS_Editor/Source/PS_Editor/GameMode/PS_Editor_PlayerController.cpp @@ -210,6 +210,20 @@ void APS_Editor_PlayerController::BeginPlay() }); } +void APS_Editor_PlayerController::EndPlay(const EEndPlayReason::Type EndPlayReason) +{ + // Reset the runtime-editor flag whenever this controller's world tears down — covers + // OpenLevel from any caller (Play button, scenario loader BP, gameplay code that calls + // OpenLevel directly), end of PIE, and seamless world transitions. Without this, the + // static would stay 'true' from the previous editor session and IsInEditorMode() would + // lie in the next world (which has no PS_Editor PlayerController). The 3 existing eager + // resets (CloseEditor + Play buttons) remain as defense-in-depth so any check between + // the click and the actual world tear-down also returns false. + UPS_Editor_SceneLoader::bIsEditorModeActive = false; + + Super::EndPlay(EndPlayReason); +} + void APS_Editor_PlayerController::Tick(float DeltaTime) { Super::Tick(DeltaTime); diff --git a/Unreal/Plugins/PS_Editor/Source/PS_Editor/GameMode/PS_Editor_PlayerController.h b/Unreal/Plugins/PS_Editor/Source/PS_Editor/GameMode/PS_Editor_PlayerController.h index 24217d1..0e1f105 100644 --- a/Unreal/Plugins/PS_Editor/Source/PS_Editor/GameMode/PS_Editor_PlayerController.h +++ b/Unreal/Plugins/PS_Editor/Source/PS_Editor/GameMode/PS_Editor_PlayerController.h @@ -143,6 +143,7 @@ public: protected: virtual void BeginPlay() override; + virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override; virtual void Tick(float DeltaTime) override; virtual void OnPossess(APawn* InPawn) override; diff --git a/Unreal/Plugins/PS_Editor/Source/PS_Editor/Serialization/PS_Editor_SceneLoader.cpp b/Unreal/Plugins/PS_Editor/Source/PS_Editor/Serialization/PS_Editor_SceneLoader.cpp index ac994ae..69783b3 100644 --- a/Unreal/Plugins/PS_Editor/Source/PS_Editor/Serialization/PS_Editor_SceneLoader.cpp +++ b/Unreal/Plugins/PS_Editor/Source/PS_Editor/Serialization/PS_Editor_SceneLoader.cpp @@ -131,6 +131,13 @@ bool UPS_Editor_SceneLoader::LoadSceneFromData(UWorld* World, const FPS_Editor_S return false; } + // Defensive: reaching the gameplay-side SceneLoader means we are NOT in the runtime + // editor (the editor uses UPS_Editor_SceneSerializer instead). Force the static flag + // false now so subsequent IsInEditorMode() checks reflect reality even if a previous + // PIE session left the static at 'true' — PIE keeps C++ statics across stop/start, and + // a forced PIE-stop or BP-driven OpenLevel can skip the EndPlay reset on the editor PC. + bIsEditorModeActive = false; + // Apply the scenario's dynamic-navigation flag BEFORE spawning actors. If the scenario // needs runtime nav generation, switching the level's RecastNavMesh to Dynamic now // means the actors we're about to spawn will dirty + rebuild tiles around them. Cooked