feat: add runtime play tick and play-mode scene editing semantics

This commit is contained in:
2026-04-02 19:37:35 +08:00
parent e30f5d5ffa
commit fb15d60be9
28 changed files with 2016 additions and 45 deletions

View File

@@ -7,6 +7,7 @@
#include "Commands/EntityCommands.h"
#include "Commands/SceneCommands.h"
#include "Core/EditorContext.h"
#include "Core/PlaySessionController.h"
#include <XCEngine/Core/Math/Quaternion.h>
#include <XCEngine/Core/Math/Vector3.h>
@@ -283,6 +284,45 @@ TEST_F(EditorActionRoutingTest, MainMenuRouterRequestsExitResetAndAboutPopup) {
m_context.GetEventBus().Unsubscribe<DockLayoutResetRequestedEvent>(resetSubscription);
}
TEST_F(EditorActionRoutingTest, PlayModeAllowsRuntimeSceneUndoRedoButKeepsSceneDocumentCommandsBlocked) {
const fs::path savedScenePath = m_projectRoot / "Assets" / "Scenes" / "PlayModeRuntimeEditing.xc";
ASSERT_TRUE(m_context.GetSceneManager().SaveSceneAs(savedScenePath.string()));
ASSERT_FALSE(m_context.GetSceneManager().IsSceneDirty());
PlaySessionController controller;
ASSERT_TRUE(controller.StartPlay(m_context));
EXPECT_EQ(m_context.GetRuntimeMode(), EditorRuntimeMode::Play);
EXPECT_FALSE(m_context.GetSceneManager().IsSceneDocumentDirtyTrackingEnabled());
EXPECT_FALSE(Commands::NewScene(m_context, "Blocked During Play"));
EXPECT_FALSE(Commands::SaveCurrentScene(m_context));
const size_t entityCountBeforeCreate = CountHierarchyEntities(m_context.GetSceneManager());
auto* runtimeEntity = Commands::CreateEmptyEntity(m_context, nullptr, "Create Runtime Entity", "RuntimeOnly");
ASSERT_NE(runtimeEntity, nullptr);
const uint64_t runtimeEntityId = runtimeEntity->GetID();
EXPECT_EQ(CountHierarchyEntities(m_context.GetSceneManager()), entityCountBeforeCreate + 1);
EXPECT_FALSE(m_context.GetSceneManager().IsSceneDirty());
const Actions::ActionBinding undoAction = Actions::MakeUndoAction(m_context);
EXPECT_TRUE(undoAction.enabled);
Actions::ExecuteUndo(m_context);
EXPECT_EQ(CountHierarchyEntities(m_context.GetSceneManager()), entityCountBeforeCreate);
EXPECT_EQ(m_context.GetSceneManager().GetEntity(runtimeEntityId), nullptr);
EXPECT_FALSE(m_context.GetSceneManager().IsSceneDirty());
const Actions::ActionBinding redoAction = Actions::MakeRedoAction(m_context);
EXPECT_TRUE(redoAction.enabled);
Actions::ExecuteRedo(m_context);
EXPECT_EQ(CountHierarchyEntities(m_context.GetSceneManager()), entityCountBeforeCreate + 1);
EXPECT_FALSE(m_context.GetSceneManager().IsSceneDirty());
ASSERT_TRUE(controller.StopPlay(m_context));
EXPECT_EQ(m_context.GetRuntimeMode(), EditorRuntimeMode::Edit);
EXPECT_TRUE(m_context.GetSceneManager().IsSceneDocumentDirtyTrackingEnabled());
EXPECT_FALSE(m_context.GetSceneManager().IsSceneDirty());
}
TEST_F(EditorActionRoutingTest, HierarchyRouterRenameHelpersPublishAndCommit) {
auto* entity = Commands::CreateEmptyEntity(m_context, nullptr, "Create Entity", "BeforeRename");
ASSERT_NE(entity, nullptr);