205 lines
6.6 KiB
C++
205 lines
6.6 KiB
C++
#include "Features/Hierarchy/HierarchyModel.h"
|
|
#include "Scene/EditorSceneBridge.h"
|
|
|
|
#include <XCEngine/Components/GameObject.h>
|
|
#include <XCEngine/Core/Asset/ResourceManager.h>
|
|
#include <XCEngine/Scene/Scene.h>
|
|
#include <XCEngine/Scene/SceneManager.h>
|
|
|
|
#include <gtest/gtest.h>
|
|
|
|
#include <chrono>
|
|
#include <filesystem>
|
|
|
|
namespace XCEngine::UI::Editor::App {
|
|
namespace {
|
|
|
|
using ::XCEngine::Components::GameObject;
|
|
using ::XCEngine::Components::Scene;
|
|
using ::XCEngine::Components::SceneManager;
|
|
|
|
class ScopedSceneManagerReset final {
|
|
public:
|
|
ScopedSceneManagerReset() {
|
|
Reset();
|
|
}
|
|
|
|
~ScopedSceneManagerReset() {
|
|
Reset();
|
|
}
|
|
|
|
private:
|
|
static void Reset() {
|
|
SceneManager& manager = SceneManager::Get();
|
|
const auto scenes = manager.GetAllScenes();
|
|
for (Scene* scene : scenes) {
|
|
manager.UnloadScene(scene);
|
|
}
|
|
}
|
|
};
|
|
|
|
class TemporaryProjectRoot final {
|
|
public:
|
|
TemporaryProjectRoot() {
|
|
const auto uniqueSuffix =
|
|
std::chrono::steady_clock::now().time_since_epoch().count();
|
|
m_root =
|
|
std::filesystem::temp_directory_path() /
|
|
("xcui_hierarchy_scene_bridge_" + std::to_string(uniqueSuffix));
|
|
}
|
|
|
|
~TemporaryProjectRoot() {
|
|
std::error_code errorCode = {};
|
|
std::filesystem::remove_all(m_root, errorCode);
|
|
}
|
|
|
|
const std::filesystem::path& Root() const {
|
|
return m_root;
|
|
}
|
|
|
|
private:
|
|
std::filesystem::path m_root = {};
|
|
};
|
|
|
|
TEST(HierarchySceneBindingTests, BuildFromSceneUsesRealGameObjectIds) {
|
|
ScopedSceneManagerReset reset = {};
|
|
|
|
Scene* scene = SceneManager::Get().CreateScene("Main");
|
|
ASSERT_NE(scene, nullptr);
|
|
SceneManager::Get().SetActiveScene(scene);
|
|
|
|
GameObject* root = scene->CreateGameObject("Root");
|
|
ASSERT_NE(root, nullptr);
|
|
GameObject* child = scene->CreateGameObject("Child", root);
|
|
ASSERT_NE(child, nullptr);
|
|
|
|
const HierarchyModel model = HierarchyModel::BuildFromScene(scene);
|
|
const HierarchyNode* rootNode =
|
|
model.FindNode(MakeEditorGameObjectItemId(root->GetID()));
|
|
ASSERT_NE(rootNode, nullptr);
|
|
EXPECT_EQ(rootNode->label, "Root");
|
|
ASSERT_EQ(rootNode->children.size(), 1u);
|
|
EXPECT_EQ(
|
|
rootNode->children.front().nodeId,
|
|
MakeEditorGameObjectItemId(child->GetID()));
|
|
EXPECT_EQ(rootNode->children.front().label, "Child");
|
|
}
|
|
|
|
TEST(HierarchySceneBindingTests, DuplicateGameObjectClonesHierarchyIntoScene) {
|
|
ScopedSceneManagerReset reset = {};
|
|
|
|
Scene* scene = SceneManager::Get().CreateScene("Main");
|
|
ASSERT_NE(scene, nullptr);
|
|
SceneManager::Get().SetActiveScene(scene);
|
|
|
|
GameObject* root = scene->CreateGameObject("Root");
|
|
ASSERT_NE(root, nullptr);
|
|
GameObject* child = scene->CreateGameObject("Child", root);
|
|
ASSERT_NE(child, nullptr);
|
|
|
|
const std::string duplicateId =
|
|
DuplicateEditorGameObject(MakeEditorGameObjectItemId(root->GetID()));
|
|
ASSERT_FALSE(duplicateId.empty());
|
|
|
|
const HierarchyModel model = HierarchyModel::BuildFromScene(scene);
|
|
const HierarchyNode* duplicateNode = model.FindNode(duplicateId);
|
|
ASSERT_NE(duplicateNode, nullptr);
|
|
EXPECT_EQ(duplicateNode->label, "Root");
|
|
ASSERT_EQ(duplicateNode->children.size(), 1u);
|
|
EXPECT_EQ(duplicateNode->children.front().label, "Child");
|
|
|
|
const auto roots = scene->GetRootGameObjects();
|
|
EXPECT_EQ(roots.size(), 2u);
|
|
}
|
|
|
|
TEST(HierarchySceneBindingTests, RenameGameObjectUpdatesRealSceneAndProjection) {
|
|
ScopedSceneManagerReset reset = {};
|
|
|
|
Scene* scene = SceneManager::Get().CreateScene("Main");
|
|
ASSERT_NE(scene, nullptr);
|
|
SceneManager::Get().SetActiveScene(scene);
|
|
|
|
GameObject* gameObject = scene->CreateGameObject("Camera");
|
|
ASSERT_NE(gameObject, nullptr);
|
|
|
|
const std::string itemId =
|
|
MakeEditorGameObjectItemId(gameObject->GetID());
|
|
ASSERT_TRUE(RenameEditorGameObject(itemId, "PlayerCamera"));
|
|
EXPECT_EQ(gameObject->GetName(), "PlayerCamera");
|
|
|
|
const HierarchyModel model = HierarchyModel::BuildFromScene(scene);
|
|
const HierarchyNode* node = model.FindNode(itemId);
|
|
ASSERT_NE(node, nullptr);
|
|
EXPECT_EQ(node->label, "PlayerCamera");
|
|
}
|
|
|
|
TEST(HierarchySceneBindingTests, ReparentAndMoveToRootOperateOnRealScene) {
|
|
ScopedSceneManagerReset reset = {};
|
|
|
|
Scene* scene = SceneManager::Get().CreateScene("Main");
|
|
ASSERT_NE(scene, nullptr);
|
|
SceneManager::Get().SetActiveScene(scene);
|
|
|
|
GameObject* parentA = scene->CreateGameObject("ParentA");
|
|
ASSERT_NE(parentA, nullptr);
|
|
GameObject* parentB = scene->CreateGameObject("ParentB");
|
|
ASSERT_NE(parentB, nullptr);
|
|
GameObject* child = scene->CreateGameObject("Child", parentA);
|
|
ASSERT_NE(child, nullptr);
|
|
|
|
ASSERT_TRUE(ReparentEditorGameObject(
|
|
MakeEditorGameObjectItemId(child->GetID()),
|
|
MakeEditorGameObjectItemId(parentB->GetID())));
|
|
EXPECT_EQ(child->GetParent(), parentB);
|
|
|
|
HierarchyModel model = HierarchyModel::BuildFromScene(scene);
|
|
const HierarchyNode* parentBNode =
|
|
model.FindNode(MakeEditorGameObjectItemId(parentB->GetID()));
|
|
ASSERT_NE(parentBNode, nullptr);
|
|
ASSERT_EQ(parentBNode->children.size(), 1u);
|
|
EXPECT_EQ(parentBNode->children.front().label, "Child");
|
|
|
|
ASSERT_TRUE(MoveEditorGameObjectToRoot(
|
|
MakeEditorGameObjectItemId(child->GetID())));
|
|
EXPECT_EQ(child->GetParent(), nullptr);
|
|
|
|
model = HierarchyModel::BuildFromScene(scene);
|
|
const auto roots = scene->GetRootGameObjects();
|
|
EXPECT_EQ(roots.size(), 3u);
|
|
}
|
|
|
|
TEST(HierarchySceneBindingTests, EnsureStartupSceneLoadsMainSceneAndSetsActive) {
|
|
ScopedSceneManagerReset reset = {};
|
|
TemporaryProjectRoot projectRoot = {};
|
|
|
|
const std::filesystem::path scenePath =
|
|
projectRoot.Root() / "Assets" / "Scenes" / "Main.xc";
|
|
std::filesystem::create_directories(scenePath.parent_path());
|
|
{
|
|
Scene scene("Main");
|
|
scene.CreateGameObject("Camera");
|
|
scene.Save(scenePath.string());
|
|
}
|
|
|
|
const EditorStartupSceneResult result =
|
|
EnsureEditorStartupScene(projectRoot.Root());
|
|
EXPECT_TRUE(result.ready);
|
|
EXPECT_TRUE(result.loadedFromDisk);
|
|
ASSERT_NE(GetActiveEditorScene(), nullptr);
|
|
EXPECT_EQ(GetActiveEditorScene()->GetName(), "Main");
|
|
|
|
const HierarchyModel model =
|
|
HierarchyModel::BuildFromScene(GetActiveEditorScene());
|
|
EXPECT_FALSE(model.Empty());
|
|
|
|
SceneManager& sceneManager = SceneManager::Get();
|
|
const auto scenes = sceneManager.GetAllScenes();
|
|
for (Scene* scene : scenes) {
|
|
sceneManager.UnloadScene(scene);
|
|
}
|
|
::XCEngine::Resources::ResourceManager::Get().Shutdown();
|
|
}
|
|
|
|
} // namespace
|
|
} // namespace XCEngine::UI::Editor::App
|