Fix play mode runtime scene replacement

This commit is contained in:
2026-04-08 00:33:50 +08:00
parent 69cb80ccd4
commit 23ff4004f4
9 changed files with 149 additions and 0 deletions

View File

@@ -72,6 +72,7 @@ void PlaySessionController::Attach(IEditorContext& context) {
void PlaySessionController::Detach(IEditorContext& context) {
StopPlay(context);
ClearRuntimeSceneSyncSubscription(context);
if (m_playStartRequestedHandlerId != 0) {
context.GetEventBus().Unsubscribe<PlayModeStartRequestedEvent>(m_playStartRequestedHandlerId);
@@ -141,6 +142,7 @@ bool PlaySessionController::StartPlay(IEditorContext& context) {
XCEngine::Input::InputManager::Get().Shutdown();
XCEngine::Input::InputManager::Get().Initialize(nullptr);
m_runtimeLoop.Start(sceneManager.GetScene());
EnsureRuntimeSceneSyncSubscription(context);
context.GetUndoManager().ClearHistory();
context.SetRuntimeMode(EditorRuntimeMode::Play);
context.GetEventBus().Publish(PlayModeStartedEvent{});
@@ -152,6 +154,7 @@ bool PlaySessionController::StopPlay(IEditorContext& context) {
return false;
}
ClearRuntimeSceneSyncSubscription(context);
auto& sceneManager = context.GetSceneManager();
m_runtimeLoop.Stop();
ResetRuntimeInputBridge();
@@ -206,6 +209,39 @@ void PlaySessionController::ResetRuntimeInputBridge() {
m_hasPendingGameViewInput = false;
}
void PlaySessionController::EnsureRuntimeSceneSyncSubscription(IEditorContext& context) {
if (m_runtimeSceneChangedHandlerId != 0) {
return;
}
m_runtimeSceneChangedHandlerId = context.GetEventBus().Subscribe<SceneChangedEvent>(
[this, &context](const SceneChangedEvent&) {
SyncRuntimeSceneIfNeeded(context);
});
}
void PlaySessionController::ClearRuntimeSceneSyncSubscription(IEditorContext& context) {
if (m_runtimeSceneChangedHandlerId == 0) {
return;
}
context.GetEventBus().Unsubscribe<SceneChangedEvent>(m_runtimeSceneChangedHandlerId);
m_runtimeSceneChangedHandlerId = 0;
}
void PlaySessionController::SyncRuntimeSceneIfNeeded(IEditorContext& context) {
if (!IsEditorRuntimeActive(context.GetRuntimeMode())) {
return;
}
auto* currentScene = context.GetSceneManager().GetScene();
if (currentScene == m_runtimeLoop.GetScene()) {
return;
}
m_runtimeLoop.ReplaceScene(currentScene);
}
void PlaySessionController::ApplyGameViewInputFrame(float deltaTime) {
using XCEngine::Input::InputManager;
using XCEngine::Input::KeyCode;

View File

@@ -28,9 +28,14 @@ public:
bool ResumePlay(IEditorContext& context);
bool StepPlay(IEditorContext& context);
::XCEngine::Components::Scene* GetRuntimeScene() const { return m_runtimeLoop.GetScene(); }
private:
void ResetRuntimeInputBridge();
void ApplyGameViewInputFrame(float deltaTime);
void EnsureRuntimeSceneSyncSubscription(IEditorContext& context);
void ClearRuntimeSceneSyncSubscription(IEditorContext& context);
void SyncRuntimeSceneIfNeeded(IEditorContext& context);
uint64_t m_playStartRequestedHandlerId = 0;
uint64_t m_playStopRequestedHandlerId = 0;
@@ -38,6 +43,7 @@ private:
uint64_t m_playResumeRequestedHandlerId = 0;
uint64_t m_playStepRequestedHandlerId = 0;
uint64_t m_gameViewInputFrameHandlerId = 0;
uint64_t m_runtimeSceneChangedHandlerId = 0;
SceneSnapshot m_editorSnapshot = {};
GameViewInputFrameEvent m_pendingGameViewInput = {};
GameViewInputFrameEvent m_appliedGameViewInput = {};