diff --git a/Source/MetaCoreEditor/Private/MetaCoreBuiltinCoreServicesModule.cpp b/Source/MetaCoreEditor/Private/MetaCoreBuiltinCoreServicesModule.cpp index 5133f0b..578d037 100644 --- a/Source/MetaCoreEditor/Private/MetaCoreBuiltinCoreServicesModule.cpp +++ b/Source/MetaCoreEditor/Private/MetaCoreBuiltinCoreServicesModule.cpp @@ -6977,12 +6977,15 @@ public: ComponentSystemRegistry_.reset(); State_ = MetaCorePlayModeState::Edit; HasPrePlaySnapshot_ = false; + HasPendingStopRestoreSnapshot_ = false; CommandRecordingSuppressed_ = false; ElapsedTimeSeconds_ = 0.0; FixedTimeAccumulatorSeconds_ = 0.0; } [[nodiscard]] bool EnterPlayMode(MetaCoreEditorContext& editorContext) override { + ApplyPendingStopRestore(editorContext); + if (State_ != MetaCorePlayModeState::Edit) { MetaCoreDebugLog( "PlayMode", @@ -7045,17 +7048,13 @@ public: } if (HasPrePlaySnapshot_) { - MetaCoreDebugLog("PlayMode", "Exit capturing current snapshot"); - const MetaCoreEditorStateSnapshot currentSnapshot = editorContext.CaptureStateSnapshot(); MetaCoreDebugLog( "PlayMode", - "Exit committing undo preObjects=" + - std::to_string(PrePlaySnapshot_.SceneSnapshot.GameObjects.size()) + - " currentObjects=" + - std::to_string(currentSnapshot.SceneSnapshot.GameObjects.size()) + "Exit queueing prePlaySnapshot restore objects=" + + std::to_string(PrePlaySnapshot_.SceneSnapshot.GameObjects.size()) ); - (void)editorContext.CommitStateTransition("播放模式改动", PrePlaySnapshot_, currentSnapshot); - MetaCoreDebugLog("PlayMode", "Exit undo committed " + MetaCoreDebugSceneSummary(editorContext)); + PendingStopRestoreSnapshot_ = PrePlaySnapshot_; + HasPendingStopRestoreSnapshot_ = true; } else { MetaCoreDebugLog("PlayMode", "Exit no prePlaySnapshot, refresh dirty state"); RefreshSceneDirtyState(editorContext); @@ -7064,7 +7063,7 @@ public: HasPrePlaySnapshot_ = false; ElapsedTimeSeconds_ = 0.0; FixedTimeAccumulatorSeconds_ = 0.0; - editorContext.AddConsoleMessage(MetaCoreLogLevel::Info, "PlayMode", "已停止播放模式,播放期改动已保留"); + editorContext.AddConsoleMessage(MetaCoreLogLevel::Info, "PlayMode", "已停止播放模式,已恢复播放前场景状态"); MetaCoreDebugLog("PlayMode", "Exit end " + MetaCoreDebugSceneSummary(editorContext)); return true; } @@ -7128,6 +7127,11 @@ public: } void Tick(MetaCoreEditorContext& editorContext, double deltaSeconds) override { + if (HasPendingStopRestoreSnapshot_) { + ApplyPendingStopRestore(editorContext); + return; + } + if (State_ != MetaCorePlayModeState::Playing) { return; } @@ -7235,10 +7239,29 @@ private: } } + void ApplyPendingStopRestore(MetaCoreEditorContext& editorContext) { + if (!HasPendingStopRestoreSnapshot_) { + return; + } + + MetaCoreDebugLog( + "PlayMode", + "Apply pending stop restore begin objects=" + + std::to_string(PendingStopRestoreSnapshot_.SceneSnapshot.GameObjects.size()) + + " " + MetaCoreDebugSceneSummary(editorContext) + ); + editorContext.RestoreStateSnapshot(PendingStopRestoreSnapshot_); + HasPendingStopRestoreSnapshot_ = false; + PendingStopRestoreSnapshot_ = {}; + MetaCoreDebugLog("PlayMode", "Apply pending stop restore end " + MetaCoreDebugSceneSummary(editorContext)); + } + std::shared_ptr ComponentSystemRegistry_{}; MetaCorePlayModeState State_ = MetaCorePlayModeState::Edit; MetaCoreEditorStateSnapshot PrePlaySnapshot_{}; + MetaCoreEditorStateSnapshot PendingStopRestoreSnapshot_{}; bool HasPrePlaySnapshot_ = false; + bool HasPendingStopRestoreSnapshot_ = false; bool CommandRecordingSuppressed_ = false; double ElapsedTimeSeconds_ = 0.0; double FixedTimeStepSeconds_ = 1.0 / 60.0; diff --git a/tests/MetaCoreSmokeTests.cpp b/tests/MetaCoreSmokeTests.cpp index f2be623..81e9def 100644 --- a/tests/MetaCoreSmokeTests.cpp +++ b/tests/MetaCoreSmokeTests.cpp @@ -705,12 +705,13 @@ void MetaCoreTestPlayModeStateMachineAndLifecycle() { MetaCoreExpect(playMode->ExitPlayMode(editorContext), "应能退出播放模式"); MetaCoreExpect(playMode->GetState() == MetaCore::MetaCorePlayModeState::Edit, "退出后应回到 Edit"); MetaCoreExpect(countingSystem->StopCount == 1, "OnPlayStop 应只调用一次"); + playMode->Tick(editorContext, 0.0); coreServicesModule->Shutdown(moduleRegistry); moduleRegistry.ShutdownServices(); } -void MetaCoreTestPlayModeRotatorRetainsChangesAsSingleUndoStep() { +void MetaCoreTestPlayModeRotatorRestoresPrePlaySnapshotOnStop() { _putenv_s("METACORE_PROJECT_PATH", ""); MetaCore::MetaCoreWindow window; @@ -736,9 +737,7 @@ void MetaCoreTestPlayModeRotatorRetainsChangesAsSingleUndoStep() { ); const auto playMode = moduleRegistry.ResolveService(); - const auto scenePersistence = moduleRegistry.ResolveService(); MetaCoreExpect(playMode != nullptr, "应解析到 PlayModeService"); - MetaCoreExpect(scenePersistence != nullptr, "应解析到 ScenePersistenceService"); MetaCoreExpect(editorContext.GetCommandService().GetUndoCount() == 0, "播放前 Undo 栈应为空"); MetaCoreExpect(playMode->EnterPlayMode(editorContext), "应能进入播放模式"); @@ -783,34 +782,21 @@ void MetaCoreTestPlayModeRotatorRetainsChangesAsSingleUndoStep() { MetaCoreExpect(playMode->ExitPlayMode(editorContext), "应能停止播放"); MetaCoreExpect(playMode->GetState() == MetaCore::MetaCorePlayModeState::Edit, "停止后应回到 Edit"); - MetaCoreExpect(editorContext.GetCommandService().GetUndoCount() == 1, "停止后播放期差异应合并为一个 Undo 步"); - MetaCoreExpect(scenePersistence->IsSceneDirty(), "停止并保留播放改动后场景应标记为脏"); + MetaCoreExpect(editorContext.GetCommandService().GetUndoCount() == 0, "停止后不应把播放期差异写入 Undo 栈"); + playMode->Tick(editorContext, 0.0); - updatedSpinner = scene.FindGameObject(spinnerId); - MetaCoreExpectVec3Near( - updatedSpinner.GetComponent().RotationEulerDegrees, - glm::vec3(0.0F, 31.0F, 0.0F), - "停止后 Rotator 结果应保留" - ); - MetaCoreExpectVec3Near( - updatedSpinner.GetComponent().Position, - glm::vec3(2.0F, 0.0F, 0.0F), - "停止后播放期手动改动应保留" - ); - - MetaCoreExpect(editorContext.UndoCommand(), "Undo 应能回到播放前快照"); updatedSpinner = scene.FindGameObject(spinnerId); MetaCoreExpectVec3Near( updatedSpinner.GetComponent().RotationEulerDegrees, glm::vec3(0.0F, 0.0F, 0.0F), - "Undo 后 Rotator 旋转应回到播放前" + "停止后 Rotator 旋转应恢复播放前" ); MetaCoreExpectVec3Near( updatedSpinner.GetComponent().Position, glm::vec3(0.0F, 0.0F, 0.0F), - "Undo 后播放期手动改动应回到播放前" + "停止后播放期手动改动应丢弃" ); - MetaCoreExpect(updatedSpinner.HasComponent(), "Undo 后 Rotator 组件应保留"); + MetaCoreExpect(updatedSpinner.HasComponent(), "停止恢复后 Rotator 组件应保留"); coreServicesModule->Shutdown(moduleRegistry); moduleRegistry.ShutdownServices(); @@ -1008,12 +994,13 @@ void MetaCoreTestNativeScriptLifecycle() { MetaCoreExpect(playMode->ExitPlayMode(editorContext), "脚本生命周期测试应能退出播放模式"); MetaCoreExpect(counters->StopCount == 1, "脚本 OnPlayStop 应调用一次并清理运行时实例"); + playMode->Tick(editorContext, 0.0); coreServicesModule->Shutdown(moduleRegistry); moduleRegistry.ShutdownServices(); } -void MetaCoreTestNativeScriptBehavioursRetainChangesAsSingleUndoStep() { +void MetaCoreTestNativeScriptBehavioursRestorePrePlaySnapshotOnStop() { _putenv_s("METACORE_PROJECT_PATH", ""); MetaCore::MetaCoreWindow window; @@ -1051,9 +1038,7 @@ void MetaCoreTestNativeScriptBehavioursRetainChangesAsSingleUndoStep() { ); const auto playMode = moduleRegistry.ResolveService(); - const auto scenePersistence = moduleRegistry.ResolveService(); MetaCoreExpect(playMode != nullptr, "应解析到 PlayModeService"); - MetaCoreExpect(scenePersistence != nullptr, "应解析到 ScenePersistenceService"); MetaCoreExpect(editorContext.GetCommandService().GetUndoCount() == 0, "脚本播放前 Undo 栈应为空"); MetaCoreExpect(playMode->EnterPlayMode(editorContext), "脚本行为测试应能进入播放模式"); @@ -1101,30 +1086,21 @@ void MetaCoreTestNativeScriptBehavioursRetainChangesAsSingleUndoStep() { ); MetaCoreExpect(playMode->ExitPlayMode(editorContext), "脚本行为测试应能退出播放模式"); - MetaCoreExpect(editorContext.GetCommandService().GetUndoCount() == 1, "脚本播放期差异应合并为一个 Undo 步"); - MetaCoreExpect(scenePersistence->IsSceneDirty(), "脚本播放结果保留后场景应标记为脏"); - updatedObject = scene.FindGameObject(objectId); - MetaCoreExpect(updatedObject.HasComponent(), "停止后 Script 组件应保留"); - MetaCoreExpectVec3Near( - updatedObject.GetComponent().RotationEulerDegrees, - glm::vec3(0.0F, 31.0F, 0.0F), - "停止后 RotatorScript 结果应保留" - ); - - MetaCoreExpect(editorContext.UndoCommand(), "Undo 应能回到脚本播放前快照"); + MetaCoreExpect(editorContext.GetCommandService().GetUndoCount() == 0, "停止脚本播放后不应写入 Undo 步"); + playMode->Tick(editorContext, 0.0); updatedObject = scene.FindGameObject(objectId); + MetaCoreExpect(updatedObject.HasComponent(), "停止恢复后 Script 组件应保留"); MetaCoreExpectVec3Near( updatedObject.GetComponent().RotationEulerDegrees, glm::vec3(0.0F, 0.0F, 0.0F), - "Undo 后 RotatorScript 旋转应回到播放前" + "停止后 RotatorScript 旋转应恢复播放前" ); MetaCoreExpectVec3Near( updatedObject.GetComponent().Position, glm::vec3(0.0F, 0.0F, 0.0F), - "Undo 后 MoverScript 位移应回到播放前" + "停止后 MoverScript 位移应恢复播放前" ); - MetaCoreExpect(updatedObject.HasComponent(), "Undo 后 Script 组件应保留"); - MetaCoreExpect(updatedObject.GetComponent().Instances.size() == 2, "Undo 后脚本实例列表应保留"); + MetaCoreExpect(updatedObject.GetComponent().Instances.size() == 2, "停止恢复后脚本实例列表应保留"); coreServicesModule->Shutdown(moduleRegistry); moduleRegistry.ShutdownServices(); @@ -4003,16 +3979,16 @@ int main() { MetaCoreTestComponentRegistryDescriptors(); std::cout << "[RUN] MetaCoreTestPlayModeStateMachineAndLifecycle..." << std::endl; MetaCoreTestPlayModeStateMachineAndLifecycle(); - std::cout << "[RUN] MetaCoreTestPlayModeRotatorRetainsChangesAsSingleUndoStep..." << std::endl; - MetaCoreTestPlayModeRotatorRetainsChangesAsSingleUndoStep(); + std::cout << "[RUN] MetaCoreTestPlayModeRotatorRestoresPrePlaySnapshotOnStop..." << std::endl; + MetaCoreTestPlayModeRotatorRestoresPrePlaySnapshotOnStop(); std::cout << "[RUN] MetaCoreTestNativeScriptRegistryAndDefaults..." << std::endl; MetaCoreTestNativeScriptRegistryAndDefaults(); std::cout << "[RUN] MetaCoreTestScriptComponentSerializationSnapshotAndJson..." << std::endl; MetaCoreTestScriptComponentSerializationSnapshotAndJson(); std::cout << "[RUN] MetaCoreTestNativeScriptLifecycle..." << std::endl; MetaCoreTestNativeScriptLifecycle(); - std::cout << "[RUN] MetaCoreTestNativeScriptBehavioursRetainChangesAsSingleUndoStep..." << std::endl; - MetaCoreTestNativeScriptBehavioursRetainChangesAsSingleUndoStep(); + std::cout << "[RUN] MetaCoreTestNativeScriptBehavioursRestorePrePlaySnapshotOnStop..." << std::endl; + MetaCoreTestNativeScriptBehavioursRestorePrePlaySnapshotOnStop(); std::cout << "[RUN] MetaCoreTestSceneRenderSyncBuildsRenderableCameraLightSnapshot..." << std::endl; MetaCoreTestSceneRenderSyncBuildsRenderableCameraLightSnapshot(); std::cout << "[RUN] MetaCoreTestJsonSceneSaveCurrentSceneUsesMcsceneJson..." << std::endl;