642 lines
27 KiB
C++
642 lines
27 KiB
C++
#include <gtest/gtest.h>
|
|
|
|
#include "Core/EditorContext.h"
|
|
#include "Core/EditorRuntimeMode.h"
|
|
#include "Core/PlaySessionController.h"
|
|
|
|
#include <XCEngine/Debug/ILogSink.h>
|
|
#include <XCEngine/Debug/Logger.h>
|
|
#include <XCEngine/Core/Math/Vector2.h>
|
|
#include <XCEngine/Core/Math/Vector3.h>
|
|
#include <XCEngine/Scripting/Mono/MonoScriptRuntime.h>
|
|
#include <XCEngine/Scripting/ScriptComponent.h>
|
|
#include <XCEngine/Scripting/ScriptEngine.h>
|
|
|
|
#include <cstdint>
|
|
#include <memory>
|
|
#include <string>
|
|
|
|
using namespace XCEngine::Components;
|
|
using namespace XCEngine::Scripting;
|
|
|
|
namespace XCEngine::Editor {
|
|
namespace {
|
|
|
|
MonoScriptRuntime::Settings CreateMonoSettings() {
|
|
MonoScriptRuntime::Settings settings;
|
|
settings.assemblyDirectory = XCENGINE_TEST_MANAGED_OUTPUT_DIR;
|
|
settings.corlibDirectory = XCENGINE_TEST_MANAGED_OUTPUT_DIR;
|
|
settings.coreAssemblyPath = XCENGINE_TEST_SCRIPT_CORE_DLL;
|
|
settings.appAssemblyPath = XCENGINE_TEST_GAME_SCRIPTS_DLL;
|
|
return settings;
|
|
}
|
|
|
|
void ExpectVector3Near(const Math::Vector3& actual, const Math::Vector3& expected, float tolerance = 0.001f) {
|
|
EXPECT_NEAR(actual.x, expected.x, tolerance);
|
|
EXPECT_NEAR(actual.y, expected.y, tolerance);
|
|
EXPECT_NEAR(actual.z, expected.z, tolerance);
|
|
}
|
|
|
|
class CapturingLogSink final : public Debug::ILogSink {
|
|
public:
|
|
void Log(const Debug::LogEntry& entry) override {
|
|
entries.push_back(entry);
|
|
}
|
|
|
|
void Flush() override {
|
|
}
|
|
|
|
std::vector<std::string> CollectMessagesWithPrefix(const char* prefix) const {
|
|
std::vector<std::string> messages;
|
|
for (const Debug::LogEntry& entry : entries) {
|
|
const std::string message = entry.message.CStr();
|
|
if (message.rfind(prefix, 0) == 0) {
|
|
messages.push_back(message);
|
|
}
|
|
}
|
|
|
|
return messages;
|
|
}
|
|
|
|
std::vector<Debug::LogEntry> entries;
|
|
};
|
|
|
|
ScriptComponent* FindLifecycleProbe(GameObject* gameObject) {
|
|
if (!gameObject) {
|
|
return nullptr;
|
|
}
|
|
|
|
for (ScriptComponent* component : gameObject->GetComponents<ScriptComponent>()) {
|
|
if (!component) {
|
|
continue;
|
|
}
|
|
|
|
if (component->GetAssemblyName() == "GameScripts"
|
|
&& component->GetNamespaceName() == "Gameplay"
|
|
&& component->GetClassName() == "LifecycleProbe") {
|
|
return component;
|
|
}
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
ScriptComponent* FindInputProbe(GameObject* gameObject) {
|
|
if (!gameObject) {
|
|
return nullptr;
|
|
}
|
|
|
|
for (ScriptComponent* component : gameObject->GetComponents<ScriptComponent>()) {
|
|
if (!component) {
|
|
continue;
|
|
}
|
|
|
|
if (component->GetAssemblyName() == "GameScripts"
|
|
&& component->GetNamespaceName() == "Gameplay"
|
|
&& component->GetClassName() == "InputProbe") {
|
|
return component;
|
|
}
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
ScriptComponent* FindTickLogProbe(GameObject* gameObject) {
|
|
if (!gameObject) {
|
|
return nullptr;
|
|
}
|
|
|
|
for (ScriptComponent* component : gameObject->GetComponents<ScriptComponent>()) {
|
|
if (!component) {
|
|
continue;
|
|
}
|
|
|
|
if (component->GetAssemblyName() == "GameScripts"
|
|
&& component->GetNamespaceName() == "Gameplay"
|
|
&& component->GetClassName() == "TickLogProbe") {
|
|
return component;
|
|
}
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
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 PlaySessionControllerScriptingTest : public ::testing::Test {
|
|
protected:
|
|
void SetUp() override {
|
|
engine = &ScriptEngine::Get();
|
|
engine->OnRuntimeStop();
|
|
|
|
runtime = std::make_unique<MonoScriptRuntime>(CreateMonoSettings());
|
|
ASSERT_TRUE(runtime->Initialize()) << runtime->GetLastError();
|
|
engine->SetRuntime(runtime.get());
|
|
|
|
context.GetSceneManager().NewScene("Play Session Script Scene");
|
|
controller.Attach(context);
|
|
}
|
|
|
|
void TearDown() override {
|
|
controller.Detach(context);
|
|
engine->OnRuntimeStop();
|
|
engine->SetRuntime(nullptr);
|
|
runtime.reset();
|
|
}
|
|
|
|
ScriptComponent* AddLifecycleProbe(GameObject* gameObject) {
|
|
ScriptComponent* component = gameObject->AddComponent<ScriptComponent>();
|
|
component->SetScriptClass("GameScripts", "Gameplay", "LifecycleProbe");
|
|
return component;
|
|
}
|
|
|
|
ScriptComponent* AddInputProbe(GameObject* gameObject) {
|
|
ScriptComponent* component = gameObject->AddComponent<ScriptComponent>();
|
|
component->SetScriptClass("GameScripts", "Gameplay", "InputProbe");
|
|
return component;
|
|
}
|
|
|
|
ScriptComponent* AddTickLogProbe(GameObject* gameObject) {
|
|
ScriptComponent* component = gameObject->AddComponent<ScriptComponent>();
|
|
component->SetScriptClass("GameScripts", "Gameplay", "TickLogProbe");
|
|
return component;
|
|
}
|
|
|
|
ScriptEngine* engine = nullptr;
|
|
std::unique_ptr<MonoScriptRuntime> runtime;
|
|
EditorContext context;
|
|
PlaySessionController controller;
|
|
};
|
|
|
|
TEST_F(PlaySessionControllerScriptingTest, StartPlayAndRuntimeTickDriveManagedLifecycleThroughPlayController) {
|
|
GameObject* host = context.GetSceneManager().CreateEntity("Host");
|
|
ASSERT_NE(host, nullptr);
|
|
ScriptComponent* script = AddLifecycleProbe(host);
|
|
ASSERT_NE(script, nullptr);
|
|
|
|
script->GetFieldStorage().SetFieldValue("Label", "EditorLabel");
|
|
script->GetFieldStorage().SetFieldValue("Speed", 5.0f);
|
|
script->GetFieldStorage().SetFieldValue("SpawnPoint", Math::Vector3(2.0f, 4.0f, 6.0f));
|
|
|
|
const uint64_t hostId = host->GetID();
|
|
|
|
ASSERT_TRUE(controller.StartPlay(context));
|
|
EXPECT_EQ(context.GetRuntimeMode(), EditorRuntimeMode::Play);
|
|
|
|
GameObject* runtimeHost = context.GetSceneManager().GetEntity(hostId);
|
|
ASSERT_NE(runtimeHost, nullptr);
|
|
ScriptComponent* runtimeScript = FindLifecycleProbe(runtimeHost);
|
|
ASSERT_NE(runtimeScript, nullptr);
|
|
EXPECT_TRUE(engine->HasRuntimeInstance(runtimeScript));
|
|
EXPECT_TRUE(runtime->HasManagedInstance(runtimeScript));
|
|
|
|
int32_t awakeCount = 0;
|
|
int32_t enableCount = 0;
|
|
int32_t startCount = 0;
|
|
int32_t fixedUpdateCount = 0;
|
|
int32_t updateCount = 0;
|
|
int32_t lateUpdateCount = 0;
|
|
std::string label;
|
|
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "AwakeCount", awakeCount));
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "EnableCount", enableCount));
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "StartCount", startCount));
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "FixedUpdateCount", fixedUpdateCount));
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "UpdateCount", updateCount));
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "LateUpdateCount", lateUpdateCount));
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "Label", label));
|
|
|
|
EXPECT_EQ(awakeCount, 1);
|
|
EXPECT_EQ(enableCount, 1);
|
|
EXPECT_EQ(startCount, 0);
|
|
EXPECT_EQ(fixedUpdateCount, 0);
|
|
EXPECT_EQ(updateCount, 0);
|
|
EXPECT_EQ(lateUpdateCount, 0);
|
|
EXPECT_EQ(label, "EditorLabel|Awake");
|
|
|
|
controller.Update(context, 0.036f);
|
|
|
|
float observedFixedDeltaTime = 0.0f;
|
|
float observedConfiguredFixedDeltaTime = 0.0f;
|
|
float observedConfiguredFixedDeltaTimeInUpdate = 0.0f;
|
|
float observedUpdateDeltaTime = 0.0f;
|
|
float observedLateDeltaTime = 0.0f;
|
|
float speed = 0.0f;
|
|
Math::Vector3 spawnPoint;
|
|
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "StartCount", startCount));
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "FixedUpdateCount", fixedUpdateCount));
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "UpdateCount", updateCount));
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "LateUpdateCount", lateUpdateCount));
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "ObservedFixedDeltaTime", observedFixedDeltaTime));
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "ObservedConfiguredFixedDeltaTime", observedConfiguredFixedDeltaTime));
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "ObservedConfiguredFixedDeltaTimeInUpdate", observedConfiguredFixedDeltaTimeInUpdate));
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "ObservedUpdateDeltaTime", observedUpdateDeltaTime));
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "ObservedLateDeltaTime", observedLateDeltaTime));
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "Speed", speed));
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "SpawnPoint", spawnPoint));
|
|
|
|
EXPECT_EQ(startCount, 1);
|
|
EXPECT_EQ(fixedUpdateCount, 1);
|
|
EXPECT_EQ(updateCount, 1);
|
|
EXPECT_EQ(lateUpdateCount, 1);
|
|
EXPECT_FLOAT_EQ(observedFixedDeltaTime, 0.02f);
|
|
EXPECT_FLOAT_EQ(observedConfiguredFixedDeltaTime, 0.02f);
|
|
EXPECT_FLOAT_EQ(observedConfiguredFixedDeltaTimeInUpdate, 0.02f);
|
|
EXPECT_FLOAT_EQ(observedUpdateDeltaTime, 0.036f);
|
|
EXPECT_FLOAT_EQ(observedLateDeltaTime, 0.036f);
|
|
EXPECT_FLOAT_EQ(speed, 6.0f);
|
|
EXPECT_EQ(runtimeHost->GetName(), "Host_Managed");
|
|
ExpectVector3Near(runtimeHost->GetTransform()->GetLocalPosition(), Math::Vector3(8.0f, 8.0f, 9.0f));
|
|
ExpectVector3Near(spawnPoint, Math::Vector3(3.0f, 4.0f, 6.0f));
|
|
}
|
|
|
|
TEST_F(PlaySessionControllerScriptingTest, PauseAndStepGateManagedUpdatesInPlayMode) {
|
|
GameObject* host = context.GetSceneManager().CreateEntity("Host");
|
|
ASSERT_NE(host, nullptr);
|
|
ScriptComponent* script = AddLifecycleProbe(host);
|
|
ASSERT_NE(script, nullptr);
|
|
|
|
script->GetFieldStorage().SetFieldValue("Label", "EditorLabel");
|
|
|
|
const uint64_t hostId = host->GetID();
|
|
|
|
ASSERT_TRUE(controller.StartPlay(context));
|
|
GameObject* runtimeHost = context.GetSceneManager().GetEntity(hostId);
|
|
ASSERT_NE(runtimeHost, nullptr);
|
|
ScriptComponent* runtimeScript = FindLifecycleProbe(runtimeHost);
|
|
ASSERT_NE(runtimeScript, nullptr);
|
|
|
|
controller.Update(context, 0.02f);
|
|
|
|
int32_t startCount = 0;
|
|
int32_t fixedUpdateCount = 0;
|
|
int32_t updateCount = 0;
|
|
int32_t lateUpdateCount = 0;
|
|
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "StartCount", startCount));
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "FixedUpdateCount", fixedUpdateCount));
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "UpdateCount", updateCount));
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "LateUpdateCount", lateUpdateCount));
|
|
|
|
EXPECT_EQ(startCount, 1);
|
|
EXPECT_EQ(fixedUpdateCount, 1);
|
|
EXPECT_EQ(updateCount, 1);
|
|
EXPECT_EQ(lateUpdateCount, 1);
|
|
|
|
ASSERT_TRUE(controller.PausePlay(context));
|
|
EXPECT_EQ(context.GetRuntimeMode(), EditorRuntimeMode::Paused);
|
|
|
|
controller.Update(context, 0.02f);
|
|
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "FixedUpdateCount", fixedUpdateCount));
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "UpdateCount", updateCount));
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "LateUpdateCount", lateUpdateCount));
|
|
|
|
EXPECT_EQ(fixedUpdateCount, 1);
|
|
EXPECT_EQ(updateCount, 1);
|
|
EXPECT_EQ(lateUpdateCount, 1);
|
|
|
|
ASSERT_TRUE(controller.StepPlay(context));
|
|
controller.Update(context, 0.02f);
|
|
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "FixedUpdateCount", fixedUpdateCount));
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "UpdateCount", updateCount));
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "LateUpdateCount", lateUpdateCount));
|
|
|
|
EXPECT_EQ(context.GetRuntimeMode(), EditorRuntimeMode::Paused);
|
|
EXPECT_EQ(fixedUpdateCount, 2);
|
|
EXPECT_EQ(updateCount, 2);
|
|
EXPECT_EQ(lateUpdateCount, 2);
|
|
|
|
ASSERT_TRUE(controller.ResumePlay(context));
|
|
EXPECT_EQ(context.GetRuntimeMode(), EditorRuntimeMode::Play);
|
|
|
|
controller.Update(context, 0.02f);
|
|
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "FixedUpdateCount", fixedUpdateCount));
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "UpdateCount", updateCount));
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "LateUpdateCount", lateUpdateCount));
|
|
|
|
EXPECT_EQ(fixedUpdateCount, 3);
|
|
EXPECT_EQ(updateCount, 3);
|
|
EXPECT_EQ(lateUpdateCount, 3);
|
|
}
|
|
|
|
TEST_F(PlaySessionControllerScriptingTest, StopPlayDestroysManagedInstancesAndRestoresEditorSnapshot) {
|
|
GameObject* host = context.GetSceneManager().CreateEntity("Host");
|
|
ASSERT_NE(host, nullptr);
|
|
host->GetTransform()->SetLocalPosition(Math::Vector3(1.0f, 2.0f, 3.0f));
|
|
|
|
ScriptComponent* script = AddLifecycleProbe(host);
|
|
ASSERT_NE(script, nullptr);
|
|
script->GetFieldStorage().SetFieldValue("Label", "EditorLabel");
|
|
script->GetFieldStorage().SetFieldValue("Speed", 5.0f);
|
|
script->GetFieldStorage().SetFieldValue("SpawnPoint", Math::Vector3(2.0f, 4.0f, 6.0f));
|
|
|
|
const uint64_t hostId = host->GetID();
|
|
const uint64_t scriptComponentUUID = script->GetScriptComponentUUID();
|
|
|
|
ASSERT_TRUE(controller.StartPlay(context));
|
|
GameObject* runtimeHost = context.GetSceneManager().GetEntity(hostId);
|
|
ASSERT_NE(runtimeHost, nullptr);
|
|
ScriptComponent* runtimeScript = FindLifecycleProbe(runtimeHost);
|
|
ASSERT_NE(runtimeScript, nullptr);
|
|
|
|
controller.Update(context, 0.02f);
|
|
|
|
EXPECT_EQ(runtime->GetManagedInstanceCount(), 1u);
|
|
EXPECT_EQ(runtimeHost->GetName(), "Host_Managed");
|
|
ExpectVector3Near(runtimeHost->GetTransform()->GetLocalPosition(), Math::Vector3(8.0f, 8.0f, 9.0f));
|
|
|
|
ASSERT_TRUE(controller.StopPlay(context));
|
|
EXPECT_EQ(context.GetRuntimeMode(), EditorRuntimeMode::Edit);
|
|
EXPECT_FALSE(engine->IsRuntimeRunning());
|
|
EXPECT_EQ(runtime->GetManagedInstanceCount(), 0u);
|
|
|
|
GameObject* restoredHost = context.GetSceneManager().GetEntity(hostId);
|
|
ASSERT_NE(restoredHost, nullptr);
|
|
EXPECT_EQ(restoredHost->GetName(), "Host");
|
|
ExpectVector3Near(restoredHost->GetTransform()->GetLocalPosition(), Math::Vector3(1.0f, 2.0f, 3.0f));
|
|
|
|
ScriptComponent* restoredScript = FindLifecycleProbe(restoredHost);
|
|
ASSERT_NE(restoredScript, nullptr);
|
|
EXPECT_EQ(restoredScript->GetScriptComponentUUID(), scriptComponentUUID);
|
|
|
|
std::string label;
|
|
float speed = 0.0f;
|
|
Math::Vector3 spawnPoint;
|
|
int32_t awakeCount = 0;
|
|
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(restoredScript, "Label", label));
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(restoredScript, "Speed", speed));
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(restoredScript, "SpawnPoint", spawnPoint));
|
|
|
|
EXPECT_EQ(label, "EditorLabel");
|
|
EXPECT_FLOAT_EQ(speed, 5.0f);
|
|
ExpectVector3Near(spawnPoint, Math::Vector3(2.0f, 4.0f, 6.0f));
|
|
EXPECT_FALSE(engine->TryGetScriptFieldValue(restoredScript, "AwakeCount", awakeCount));
|
|
EXPECT_FALSE(restoredScript->GetFieldStorage().Contains("AwakeCount"));
|
|
}
|
|
|
|
TEST_F(PlaySessionControllerScriptingTest, GameViewInputBridgeFeedsManagedInputApiDuringPlayMode) {
|
|
GameObject* host = context.GetSceneManager().CreateEntity("Host");
|
|
ASSERT_NE(host, nullptr);
|
|
ScriptComponent* script = AddInputProbe(host);
|
|
ASSERT_NE(script, nullptr);
|
|
|
|
const uint64_t hostId = host->GetID();
|
|
|
|
controller.Attach(context);
|
|
ASSERT_TRUE(controller.StartPlay(context));
|
|
GameObject* runtimeHost = context.GetSceneManager().GetEntity(hostId);
|
|
ASSERT_NE(runtimeHost, nullptr);
|
|
ScriptComponent* runtimeScript = FindInputProbe(runtimeHost);
|
|
ASSERT_NE(runtimeScript, nullptr);
|
|
|
|
context.GetEventBus().Publish(CreateGameViewInputFrame(
|
|
true,
|
|
true,
|
|
{XCEngine::Input::KeyCode::A, XCEngine::Input::KeyCode::Space, XCEngine::Input::KeyCode::LeftCtrl},
|
|
{XCEngine::Input::MouseButton::Left},
|
|
XCEngine::Math::Vector2(120.0f, 48.0f),
|
|
XCEngine::Math::Vector2(3.0f, -2.0f),
|
|
1.0f));
|
|
|
|
controller.Update(context, 0.016f);
|
|
|
|
int32_t updateCount = 0;
|
|
bool observedKeyA = false;
|
|
bool observedKeyADown = false;
|
|
bool observedKeyAUp = false;
|
|
bool observedKeySpace = false;
|
|
bool observedJump = false;
|
|
bool observedJumpDown = false;
|
|
bool observedJumpUp = false;
|
|
bool observedFire1 = false;
|
|
bool observedFire1Down = false;
|
|
bool observedFire1Up = false;
|
|
bool observedAnyKey = false;
|
|
bool observedAnyKeyDown = false;
|
|
bool observedLeftMouse = false;
|
|
bool observedLeftMouseDown = false;
|
|
bool observedLeftMouseUp = false;
|
|
float observedHorizontal = 0.0f;
|
|
float observedHorizontalRaw = 0.0f;
|
|
XCEngine::Math::Vector2 observedMouseScrollDelta;
|
|
XCEngine::Math::Vector3 observedMousePosition;
|
|
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "UpdateCount", updateCount));
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "ObservedKeyA", observedKeyA));
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "ObservedKeyADown", observedKeyADown));
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "ObservedKeyAUp", observedKeyAUp));
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "ObservedKeySpace", observedKeySpace));
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "ObservedJump", observedJump));
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "ObservedJumpDown", observedJumpDown));
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "ObservedJumpUp", observedJumpUp));
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "ObservedFire1", observedFire1));
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "ObservedFire1Down", observedFire1Down));
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "ObservedFire1Up", observedFire1Up));
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "ObservedAnyKey", observedAnyKey));
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "ObservedAnyKeyDown", observedAnyKeyDown));
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "ObservedLeftMouse", observedLeftMouse));
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "ObservedLeftMouseDown", observedLeftMouseDown));
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "ObservedLeftMouseUp", observedLeftMouseUp));
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "ObservedHorizontal", observedHorizontal));
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "ObservedHorizontalRaw", observedHorizontalRaw));
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "ObservedMousePosition", observedMousePosition));
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "ObservedMouseScrollDelta", observedMouseScrollDelta));
|
|
|
|
EXPECT_EQ(updateCount, 1);
|
|
EXPECT_TRUE(observedKeyA);
|
|
EXPECT_TRUE(observedKeyADown);
|
|
EXPECT_FALSE(observedKeyAUp);
|
|
EXPECT_TRUE(observedKeySpace);
|
|
EXPECT_TRUE(observedJump);
|
|
EXPECT_TRUE(observedJumpDown);
|
|
EXPECT_FALSE(observedJumpUp);
|
|
EXPECT_TRUE(observedFire1);
|
|
EXPECT_TRUE(observedFire1Down);
|
|
EXPECT_FALSE(observedFire1Up);
|
|
EXPECT_TRUE(observedAnyKey);
|
|
EXPECT_TRUE(observedAnyKeyDown);
|
|
EXPECT_TRUE(observedLeftMouse);
|
|
EXPECT_TRUE(observedLeftMouseDown);
|
|
EXPECT_FALSE(observedLeftMouseUp);
|
|
EXPECT_FLOAT_EQ(observedHorizontal, -1.0f);
|
|
EXPECT_FLOAT_EQ(observedHorizontalRaw, -1.0f);
|
|
EXPECT_EQ(observedMousePosition, XCEngine::Math::Vector3(120.0f, 48.0f, 0.0f));
|
|
EXPECT_EQ(observedMouseScrollDelta, XCEngine::Math::Vector2(0.0f, 1.0f));
|
|
|
|
context.GetEventBus().Publish(CreateGameViewInputFrame(
|
|
true,
|
|
true,
|
|
{XCEngine::Input::KeyCode::A, XCEngine::Input::KeyCode::Space, XCEngine::Input::KeyCode::LeftCtrl},
|
|
{XCEngine::Input::MouseButton::Left},
|
|
XCEngine::Math::Vector2(120.0f, 48.0f)));
|
|
|
|
controller.Update(context, 0.016f);
|
|
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "UpdateCount", updateCount));
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "ObservedKeyA", observedKeyA));
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "ObservedKeyADown", observedKeyADown));
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "ObservedKeyAUp", observedKeyAUp));
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "ObservedJump", observedJump));
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "ObservedJumpDown", observedJumpDown));
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "ObservedJumpUp", observedJumpUp));
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "ObservedFire1", observedFire1));
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "ObservedFire1Down", observedFire1Down));
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "ObservedFire1Up", observedFire1Up));
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "ObservedAnyKey", observedAnyKey));
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "ObservedAnyKeyDown", observedAnyKeyDown));
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "ObservedLeftMouse", observedLeftMouse));
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "ObservedLeftMouseDown", observedLeftMouseDown));
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "ObservedLeftMouseUp", observedLeftMouseUp));
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "ObservedHorizontalRaw", observedHorizontalRaw));
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "ObservedMouseScrollDelta", observedMouseScrollDelta));
|
|
|
|
EXPECT_EQ(updateCount, 2);
|
|
EXPECT_TRUE(observedKeyA);
|
|
EXPECT_FALSE(observedKeyADown);
|
|
EXPECT_FALSE(observedKeyAUp);
|
|
EXPECT_TRUE(observedJump);
|
|
EXPECT_FALSE(observedJumpDown);
|
|
EXPECT_FALSE(observedJumpUp);
|
|
EXPECT_TRUE(observedFire1);
|
|
EXPECT_FALSE(observedFire1Down);
|
|
EXPECT_FALSE(observedFire1Up);
|
|
EXPECT_TRUE(observedAnyKey);
|
|
EXPECT_FALSE(observedAnyKeyDown);
|
|
EXPECT_TRUE(observedLeftMouse);
|
|
EXPECT_FALSE(observedLeftMouseDown);
|
|
EXPECT_FALSE(observedLeftMouseUp);
|
|
EXPECT_FLOAT_EQ(observedHorizontalRaw, -1.0f);
|
|
EXPECT_EQ(observedMouseScrollDelta, XCEngine::Math::Vector2(0.0f, 0.0f));
|
|
|
|
context.GetEventBus().Publish(CreateGameViewInputFrame(
|
|
true,
|
|
true,
|
|
{XCEngine::Input::KeyCode::Space},
|
|
{},
|
|
XCEngine::Math::Vector2(120.0f, 48.0f)));
|
|
controller.Update(context, 0.016f);
|
|
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "UpdateCount", updateCount));
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "ObservedKeyA", observedKeyA));
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "ObservedKeyAUp", observedKeyAUp));
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "ObservedKeySpace", observedKeySpace));
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "ObservedJump", observedJump));
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "ObservedJumpUp", observedJumpUp));
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "ObservedFire1", observedFire1));
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "ObservedFire1Up", observedFire1Up));
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "ObservedAnyKey", observedAnyKey));
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "ObservedAnyKeyDown", observedAnyKeyDown));
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "ObservedLeftMouse", observedLeftMouse));
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "ObservedLeftMouseUp", observedLeftMouseUp));
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "ObservedHorizontal", observedHorizontal));
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "ObservedHorizontalRaw", observedHorizontalRaw));
|
|
|
|
EXPECT_EQ(updateCount, 3);
|
|
EXPECT_FALSE(observedKeyA);
|
|
EXPECT_TRUE(observedKeyAUp);
|
|
EXPECT_TRUE(observedKeySpace);
|
|
EXPECT_TRUE(observedJump);
|
|
EXPECT_FALSE(observedJumpUp);
|
|
EXPECT_FALSE(observedFire1);
|
|
EXPECT_TRUE(observedFire1Up);
|
|
EXPECT_TRUE(observedAnyKey);
|
|
EXPECT_FALSE(observedAnyKeyDown);
|
|
EXPECT_FALSE(observedLeftMouse);
|
|
EXPECT_TRUE(observedLeftMouseUp);
|
|
EXPECT_FLOAT_EQ(observedHorizontal, 0.0f);
|
|
EXPECT_FLOAT_EQ(observedHorizontalRaw, 0.0f);
|
|
|
|
context.GetEventBus().Publish(CreateGameViewInputFrame(
|
|
true,
|
|
true,
|
|
{},
|
|
{},
|
|
XCEngine::Math::Vector2(120.0f, 48.0f)));
|
|
controller.Update(context, 0.016f);
|
|
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "UpdateCount", updateCount));
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "ObservedKeySpace", observedKeySpace));
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "ObservedJump", observedJump));
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "ObservedJumpUp", observedJumpUp));
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "ObservedAnyKey", observedAnyKey));
|
|
ASSERT_TRUE(engine->TryGetScriptFieldValue(runtimeScript, "ObservedAnyKeyDown", observedAnyKeyDown));
|
|
|
|
EXPECT_EQ(updateCount, 4);
|
|
EXPECT_FALSE(observedKeySpace);
|
|
EXPECT_FALSE(observedJump);
|
|
EXPECT_TRUE(observedJumpUp);
|
|
EXPECT_FALSE(observedAnyKey);
|
|
EXPECT_FALSE(observedAnyKeyDown);
|
|
}
|
|
|
|
TEST_F(PlaySessionControllerScriptingTest, PlayModeTickWritesManagedDebugLogsToNativeLogger) {
|
|
auto sink = std::make_unique<CapturingLogSink>();
|
|
CapturingLogSink* sinkPtr = sink.get();
|
|
Debug::Logger::Get().AddSink(std::move(sink));
|
|
|
|
GameObject* host = context.GetSceneManager().CreateEntity("Host");
|
|
ASSERT_NE(host, nullptr);
|
|
ScriptComponent* script = AddTickLogProbe(host);
|
|
ASSERT_NE(script, nullptr);
|
|
|
|
const uint64_t hostId = host->GetID();
|
|
|
|
ASSERT_TRUE(controller.StartPlay(context));
|
|
GameObject* runtimeHost = context.GetSceneManager().GetEntity(hostId);
|
|
ASSERT_NE(runtimeHost, nullptr);
|
|
ASSERT_NE(FindTickLogProbe(runtimeHost), nullptr);
|
|
|
|
controller.Update(context, 0.036f);
|
|
|
|
const std::vector<std::string> messages = sinkPtr->CollectMessagesWithPrefix("[TickLogProbe]");
|
|
const std::vector<std::string> expected = {
|
|
"[TickLogProbe] Awake",
|
|
"[TickLogProbe] FixedUpdate 1",
|
|
"[TickLogProbe] Start",
|
|
"[TickLogProbe] Update 1",
|
|
"[TickLogProbe] LateUpdate 1",
|
|
};
|
|
|
|
EXPECT_EQ(messages, expected);
|
|
|
|
Debug::Logger::Get().RemoveSink(sinkPtr);
|
|
}
|
|
|
|
} // namespace
|
|
} // namespace XCEngine::Editor
|