Files
XCEngine/tests/editor/test_play_session_controller.cpp

279 lines
11 KiB
C++

#include <gtest/gtest.h>
#include "Core/EditorContext.h"
#include "Core/EditorEvents.h"
#include "Core/PlaySessionController.h"
#include "Commands/EntityCommands.h"
#include <XCEngine/Core/Math/Vector3.h>
#include <XCEngine/Input/InputManager.h>
namespace XCEngine::Editor {
namespace {
GameViewInputFrameEvent CreateGameViewInputFrame(
bool focused,
bool hovered,
std::initializer_list<XCEngine::Input::KeyCode> keys = {},
std::initializer_list<XCEngine::Input::MouseButton> mouseButtons = {},
XCEngine::Math::Vector2 mousePosition = XCEngine::Math::Vector2::Zero(),
XCEngine::Math::Vector2 mouseDelta = XCEngine::Math::Vector2::Zero(),
float mouseWheel = 0.0f) {
GameViewInputFrameEvent event = {};
event.focused = focused;
event.hovered = hovered;
event.mousePosition = mousePosition;
event.mouseDelta = mouseDelta;
event.mouseWheel = mouseWheel;
for (const XCEngine::Input::KeyCode key : keys) {
const size_t index = static_cast<size_t>(key);
if (index < event.keyDown.size()) {
event.keyDown[index] = true;
}
}
for (const XCEngine::Input::MouseButton button : mouseButtons) {
const size_t index = static_cast<size_t>(button);
if (index < event.mouseButtonDown.size()) {
event.mouseButtonDown[index] = true;
}
}
return event;
}
class PlaySessionControllerTest : public ::testing::Test {
protected:
void SetUp() override {
XCEngine::Input::InputManager::Get().Shutdown();
m_context.GetSceneManager().NewScene("Play Session Scene");
}
void TearDown() override {
m_controller.Detach(m_context);
XCEngine::Input::InputManager::Get().Shutdown();
}
EditorContext m_context;
PlaySessionController m_controller;
};
TEST_F(PlaySessionControllerTest, StartPlayClonesCurrentSceneAndStopRestoresEditorScene) {
auto* editorEntity = m_context.GetSceneManager().CreateEntity("Persistent");
ASSERT_NE(editorEntity, nullptr);
const uint64_t editorEntityId = editorEntity->GetID();
editorEntity->GetTransform()->SetLocalPosition(Math::Vector3(1.0f, 2.0f, 3.0f));
int startedCount = 0;
int stoppedCount = 0;
const uint64_t startedSubscription = m_context.GetEventBus().Subscribe<PlayModeStartedEvent>(
[&](const PlayModeStartedEvent&) {
++startedCount;
});
const uint64_t stoppedSubscription = m_context.GetEventBus().Subscribe<PlayModeStoppedEvent>(
[&](const PlayModeStoppedEvent&) {
++stoppedCount;
});
ASSERT_TRUE(m_controller.StartPlay(m_context));
EXPECT_EQ(m_context.GetRuntimeMode(), EditorRuntimeMode::Play);
EXPECT_EQ(startedCount, 1);
auto* runtimeEntity = m_context.GetSceneManager().GetEntity(editorEntityId);
ASSERT_NE(runtimeEntity, nullptr);
runtimeEntity->GetTransform()->SetLocalPosition(Math::Vector3(8.0f, 9.0f, 10.0f));
auto* runtimeOnlyEntity = m_context.GetSceneManager().CreateEntity("RuntimeOnly");
ASSERT_NE(runtimeOnlyEntity, nullptr);
const uint64_t runtimeOnlyId = runtimeOnlyEntity->GetID();
ASSERT_TRUE(m_controller.StopPlay(m_context));
EXPECT_EQ(m_context.GetRuntimeMode(), EditorRuntimeMode::Edit);
EXPECT_EQ(stoppedCount, 1);
auto* restoredEntity = m_context.GetSceneManager().GetEntity(editorEntityId);
ASSERT_NE(restoredEntity, nullptr);
EXPECT_EQ(m_context.GetSceneManager().GetEntity(runtimeOnlyId), nullptr);
const Math::Vector3 restoredPosition = restoredEntity->GetTransform()->GetLocalPosition();
EXPECT_NEAR(restoredPosition.x, 1.0f, 1e-4f);
EXPECT_NEAR(restoredPosition.y, 2.0f, 1e-4f);
EXPECT_NEAR(restoredPosition.z, 3.0f, 1e-4f);
m_context.GetEventBus().Unsubscribe<PlayModeStartedEvent>(startedSubscription);
m_context.GetEventBus().Unsubscribe<PlayModeStoppedEvent>(stoppedSubscription);
}
TEST_F(PlaySessionControllerTest, StartAndStopRequestsRouteThroughEventBus) {
auto* editorEntity = m_context.GetSceneManager().CreateEntity("Persistent");
ASSERT_NE(editorEntity, nullptr);
m_controller.Attach(m_context);
m_context.GetEventBus().Publish(PlayModeStartRequestedEvent{});
EXPECT_EQ(m_context.GetRuntimeMode(), EditorRuntimeMode::Play);
m_context.GetEventBus().Publish(PlayModeStopRequestedEvent{});
EXPECT_EQ(m_context.GetRuntimeMode(), EditorRuntimeMode::Edit);
m_controller.Detach(m_context);
}
TEST_F(PlaySessionControllerTest, PauseResumeAndStepRequestsDrivePlayStateMachine) {
auto* editorEntity = m_context.GetSceneManager().CreateEntity("Persistent");
ASSERT_NE(editorEntity, nullptr);
int pausedCount = 0;
int resumedCount = 0;
const uint64_t pausedSubscription = m_context.GetEventBus().Subscribe<PlayModePausedEvent>(
[&](const PlayModePausedEvent&) {
++pausedCount;
});
const uint64_t resumedSubscription = m_context.GetEventBus().Subscribe<PlayModeResumedEvent>(
[&](const PlayModeResumedEvent&) {
++resumedCount;
});
m_controller.Attach(m_context);
m_context.GetEventBus().Publish(PlayModeStartRequestedEvent{});
EXPECT_EQ(m_context.GetRuntimeMode(), EditorRuntimeMode::Play);
m_context.GetEventBus().Publish(PlayModePauseRequestedEvent{});
EXPECT_EQ(m_context.GetRuntimeMode(), EditorRuntimeMode::Paused);
EXPECT_EQ(pausedCount, 1);
m_context.GetEventBus().Publish(PlayModeStepRequestedEvent{});
EXPECT_EQ(m_context.GetRuntimeMode(), EditorRuntimeMode::Paused);
EXPECT_EQ(pausedCount, 1);
EXPECT_EQ(resumedCount, 0);
m_context.GetEventBus().Publish(PlayModeResumeRequestedEvent{});
EXPECT_EQ(m_context.GetRuntimeMode(), EditorRuntimeMode::Play);
EXPECT_EQ(resumedCount, 1);
m_context.GetEventBus().Publish(PlayModeStopRequestedEvent{});
EXPECT_EQ(m_context.GetRuntimeMode(), EditorRuntimeMode::Edit);
m_controller.Detach(m_context);
m_context.GetEventBus().Unsubscribe<PlayModePausedEvent>(pausedSubscription);
m_context.GetEventBus().Unsubscribe<PlayModeResumedEvent>(resumedSubscription);
}
TEST_F(PlaySessionControllerTest, GameViewInputFramesDoNotAffectInputManagerOutsidePlayMode) {
m_controller.Attach(m_context);
m_context.GetEventBus().Publish(CreateGameViewInputFrame(
true,
true,
{XCEngine::Input::KeyCode::A},
{XCEngine::Input::MouseButton::Left},
XCEngine::Math::Vector2(120.0f, 48.0f),
XCEngine::Math::Vector2(3.0f, -2.0f),
1.0f));
m_controller.Update(m_context, 0.016f);
auto& inputManager = XCEngine::Input::InputManager::Get();
EXPECT_FALSE(inputManager.IsKeyDown(XCEngine::Input::KeyCode::A));
EXPECT_FALSE(inputManager.IsMouseButtonDown(XCEngine::Input::MouseButton::Left));
EXPECT_EQ(inputManager.GetMousePosition(), XCEngine::Math::Vector2::Zero());
EXPECT_FLOAT_EQ(inputManager.GetMouseScrollDelta(), 0.0f);
m_controller.Detach(m_context);
}
TEST_F(PlaySessionControllerTest, GameViewInputFramesDriveAndReleaseRuntimeInputDuringPlayMode) {
auto* editorEntity = m_context.GetSceneManager().CreateEntity("Persistent");
ASSERT_NE(editorEntity, nullptr);
m_controller.Attach(m_context);
ASSERT_TRUE(m_controller.StartPlay(m_context));
m_context.GetEventBus().Publish(CreateGameViewInputFrame(
true,
true,
{XCEngine::Input::KeyCode::A, XCEngine::Input::KeyCode::Space},
{XCEngine::Input::MouseButton::Left},
XCEngine::Math::Vector2(120.0f, 48.0f),
XCEngine::Math::Vector2(3.0f, -2.0f),
1.0f));
m_controller.Update(m_context, 0.016f);
auto& inputManager = XCEngine::Input::InputManager::Get();
EXPECT_TRUE(inputManager.IsKeyDown(XCEngine::Input::KeyCode::A));
EXPECT_TRUE(inputManager.IsKeyPressed(XCEngine::Input::KeyCode::A));
EXPECT_TRUE(inputManager.IsKeyDown(XCEngine::Input::KeyCode::Space));
EXPECT_TRUE(inputManager.IsMouseButtonDown(XCEngine::Input::MouseButton::Left));
EXPECT_TRUE(inputManager.IsMouseButtonClicked(XCEngine::Input::MouseButton::Left));
EXPECT_EQ(inputManager.GetMousePosition(), XCEngine::Math::Vector2(120.0f, 48.0f));
EXPECT_EQ(inputManager.GetMouseDelta(), XCEngine::Math::Vector2(3.0f, -2.0f));
EXPECT_FLOAT_EQ(inputManager.GetMouseScrollDelta(), 1.0f);
m_context.GetEventBus().Publish(CreateGameViewInputFrame(
true,
true,
{XCEngine::Input::KeyCode::A, XCEngine::Input::KeyCode::Space},
{XCEngine::Input::MouseButton::Left},
XCEngine::Math::Vector2(120.0f, 48.0f)));
m_controller.Update(m_context, 0.016f);
EXPECT_TRUE(inputManager.IsKeyDown(XCEngine::Input::KeyCode::A));
EXPECT_FALSE(inputManager.IsKeyPressed(XCEngine::Input::KeyCode::A));
EXPECT_TRUE(inputManager.IsMouseButtonDown(XCEngine::Input::MouseButton::Left));
EXPECT_FALSE(inputManager.IsMouseButtonClicked(XCEngine::Input::MouseButton::Left));
EXPECT_EQ(inputManager.GetMouseDelta(), XCEngine::Math::Vector2::Zero());
EXPECT_FLOAT_EQ(inputManager.GetMouseScrollDelta(), 0.0f);
m_context.GetEventBus().Publish(GameViewInputFrameEvent{});
m_controller.Update(m_context, 0.016f);
EXPECT_FALSE(inputManager.IsKeyDown(XCEngine::Input::KeyCode::A));
EXPECT_FALSE(inputManager.IsKeyDown(XCEngine::Input::KeyCode::Space));
EXPECT_FALSE(inputManager.IsMouseButtonDown(XCEngine::Input::MouseButton::Left));
m_controller.Detach(m_context);
}
TEST_F(PlaySessionControllerTest, RuntimeSceneUndoRedoRebindsPlaySessionBeforeStop) {
auto* editorEntity = m_context.GetSceneManager().CreateEntity("Persistent");
ASSERT_NE(editorEntity, nullptr);
const uint64_t editorEntityId = editorEntity->GetID();
ASSERT_TRUE(m_controller.StartPlay(m_context));
ASSERT_EQ(m_context.GetRuntimeMode(), EditorRuntimeMode::Play);
const auto* runtimeSceneBeforeUndo = m_context.GetSceneManager().GetScene();
ASSERT_NE(runtimeSceneBeforeUndo, nullptr);
ASSERT_EQ(m_controller.GetRuntimeScene(), runtimeSceneBeforeUndo);
auto* runtimeEntity = Commands::CreateEmptyEntity(m_context, nullptr, "Create Runtime Entity", "RuntimeOnly");
ASSERT_NE(runtimeEntity, nullptr);
const uint64_t runtimeEntityId = runtimeEntity->GetID();
ASSERT_EQ(m_controller.GetRuntimeScene(), m_context.GetSceneManager().GetScene());
m_context.GetUndoManager().Undo();
const auto* runtimeSceneAfterUndo = m_context.GetSceneManager().GetScene();
ASSERT_NE(runtimeSceneAfterUndo, nullptr);
EXPECT_NE(runtimeSceneAfterUndo, runtimeSceneBeforeUndo);
EXPECT_EQ(m_controller.GetRuntimeScene(), runtimeSceneAfterUndo);
EXPECT_EQ(m_context.GetSceneManager().GetEntity(runtimeEntityId), nullptr);
m_context.GetUndoManager().Redo();
const auto* runtimeSceneAfterRedo = m_context.GetSceneManager().GetScene();
ASSERT_NE(runtimeSceneAfterRedo, nullptr);
EXPECT_NE(runtimeSceneAfterRedo, runtimeSceneAfterUndo);
EXPECT_EQ(m_controller.GetRuntimeScene(), runtimeSceneAfterRedo);
EXPECT_NE(m_context.GetSceneManager().GetEntity(runtimeEntityId), nullptr);
ASSERT_TRUE(m_controller.StopPlay(m_context));
EXPECT_EQ(m_context.GetRuntimeMode(), EditorRuntimeMode::Edit);
ASSERT_NE(m_context.GetSceneManager().GetEntity(editorEntityId), nullptr);
EXPECT_EQ(m_context.GetSceneManager().GetEntity(runtimeEntityId), nullptr);
}
} // namespace
} // namespace XCEngine::Editor