Make editor play mode transactional

This commit is contained in:
2026-04-29 04:33:30 +08:00
parent 595d39c4c3
commit a3a80dff8f
9 changed files with 444 additions and 4 deletions

View File

@@ -96,6 +96,89 @@ std::string ResolveUniqueSceneName(
static_cast<std::uint64_t>(sceneManager.GetAllScenes().size() + 1u));
}
bool IsSceneLoaded(
const SceneManager& sceneManager,
const Scene* scene) {
if (scene == nullptr) {
return false;
}
const std::vector<Scene*> scenes = sceneManager.GetAllScenes();
return std::find(scenes.begin(), scenes.end(), scene) != scenes.end();
}
Scene* CreateSceneFromSerializedSnapshot(
SceneManager& sceneManager,
ResourceManager& resourceManager,
std::string_view requestedName,
const std::string& serializedScene) {
const std::string sceneName =
ResolveUniqueSceneName(sceneManager, requestedName);
Scene* scene = sceneManager.CreateScene(sceneName);
if (scene == nullptr) {
return nullptr;
}
{
ResourceManager::ScopedDeferredSceneLoad deferredSceneLoad(resourceManager);
scene->DeserializeFromString(serializedScene);
}
sceneManager.SetActiveScene(scene);
return scene;
}
class EngineEditorScenePlaySession final : public EditorScenePlaySession {
public:
EngineEditorScenePlaySession(
SceneManager& sceneManager,
ResourceManager& resourceManager,
Scene* runtimeScene,
std::string editSceneName,
std::string editSceneSnapshot)
: m_sceneManager(sceneManager)
, m_resourceManager(resourceManager)
, m_runtimeScene(runtimeScene)
, m_editSceneName(std::move(editSceneName))
, m_editSceneSnapshot(std::move(editSceneSnapshot)) {}
~EngineEditorScenePlaySession() override {
RestoreEditScene();
}
Scene* GetRuntimeScene() const override {
return m_runtimeScene;
}
private:
void RestoreEditScene() {
if (m_restored) {
return;
}
if (IsSceneLoaded(m_sceneManager, m_runtimeScene)) {
m_sceneManager.UnloadScene(m_runtimeScene);
}
m_runtimeScene = nullptr;
if (!m_editSceneSnapshot.empty()) {
CreateSceneFromSerializedSnapshot(
m_sceneManager,
m_resourceManager,
m_editSceneName,
m_editSceneSnapshot);
}
m_restored = true;
}
SceneManager& m_sceneManager;
ResourceManager& m_resourceManager;
Scene* m_runtimeScene = nullptr;
std::string m_editSceneName = {};
std::string m_editSceneSnapshot = {};
bool m_restored = false;
};
std::pair<std::string, std::string> SerializeComponent(
const Component* component) {
std::ostringstream payload = {};
@@ -1824,6 +1907,43 @@ public:
return ResolvePrimaryScene(m_sceneManager);
}
std::unique_ptr<EditorScenePlaySession> BeginPlaySession() override {
Scene* editScene = ResolvePrimaryScene(m_sceneManager);
if (editScene == nullptr) {
return nullptr;
}
const std::string editSceneName = editScene->GetName().empty()
? std::string("Untitled")
: editScene->GetName();
const std::string editSceneSnapshot = editScene->SerializeToString();
if (editSceneSnapshot.empty()) {
return nullptr;
}
m_sceneManager.UnloadScene(editScene);
Scene* runtimeScene = CreateSceneFromSerializedSnapshot(
m_sceneManager,
m_resourceManager,
editSceneName + " Play",
editSceneSnapshot);
if (runtimeScene == nullptr) {
CreateSceneFromSerializedSnapshot(
m_sceneManager,
m_resourceManager,
editSceneName,
editSceneSnapshot);
return nullptr;
}
return std::make_unique<EngineEditorScenePlaySession>(
m_sceneManager,
m_resourceManager,
runtimeScene,
editSceneName,
editSceneSnapshot);
}
std::optional<EditorSceneObjectSnapshot> GetObjectSnapshot(
std::string_view itemId) const override {
const GameObject* gameObject = FindGameObject(itemId);