873 lines
45 KiB
C++
873 lines
45 KiB
C++
#include <gtest/gtest.h>
|
|
|
|
#include <XCEngine/Components/CameraComponent.h>
|
|
#include <XCEngine/Components/LightComponent.h>
|
|
#include <XCEngine/Components/MeshFilterComponent.h>
|
|
#include <XCEngine/Components/MeshRendererComponent.h>
|
|
#include <XCEngine/Core/Math/Vector3.h>
|
|
#include <XCEngine/Core/Math/Vector4.h>
|
|
#include <XCEngine/Scene/Scene.h>
|
|
#include <XCEngine/Scripting/Mono/MonoScriptRuntime.h>
|
|
#include <XCEngine/Scripting/ScriptComponent.h>
|
|
#include <XCEngine/Scripting/ScriptEngine.h>
|
|
|
|
#include <algorithm>
|
|
#include <cstdint>
|
|
#include <memory>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
using namespace XCEngine::Components;
|
|
using namespace XCEngine::Scripting;
|
|
|
|
namespace {
|
|
|
|
void ExpectVector3Near(const XCEngine::Math::Vector3& actual, const XCEngine::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);
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
class MonoScriptRuntimeTest : 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());
|
|
}
|
|
|
|
void TearDown() override {
|
|
engine->OnRuntimeStop();
|
|
engine->SetRuntime(nullptr);
|
|
runtime.reset();
|
|
scene.reset();
|
|
}
|
|
|
|
Scene* CreateScene(const std::string& sceneName) {
|
|
scene = std::make_unique<Scene>(sceneName);
|
|
return scene.get();
|
|
}
|
|
|
|
ScriptComponent* AddScript(GameObject* gameObject, const std::string& namespaceName, const std::string& className) {
|
|
ScriptComponent* component = gameObject->AddComponent<ScriptComponent>();
|
|
component->SetScriptClass("GameScripts", namespaceName, className);
|
|
return component;
|
|
}
|
|
|
|
ScriptEngine* engine = nullptr;
|
|
std::unique_ptr<MonoScriptRuntime> runtime;
|
|
std::unique_ptr<Scene> scene;
|
|
};
|
|
|
|
TEST_F(MonoScriptRuntimeTest, InitializesAndDiscoversConcreteMonoBehaviourClasses) {
|
|
const std::vector<std::string> classNames = runtime->GetScriptClassNames("GameScripts");
|
|
|
|
EXPECT_TRUE(runtime->IsInitialized());
|
|
EXPECT_TRUE(runtime->IsClassAvailable("GameScripts", "Gameplay", "LifecycleProbe"));
|
|
EXPECT_NE(std::find(classNames.begin(), classNames.end(), "Gameplay.LifecycleProbe"), classNames.end());
|
|
EXPECT_EQ(std::find(classNames.begin(), classNames.end(), "Gameplay.AbstractLifecycleProbe"), classNames.end());
|
|
EXPECT_EQ(std::find(classNames.begin(), classNames.end(), "Gameplay.UtilityHelper"), classNames.end());
|
|
}
|
|
|
|
TEST_F(MonoScriptRuntimeTest, ScriptEngineAppliesStoredFieldsAndInvokesLifecycleMethods) {
|
|
Scene* runtimeScene = CreateScene("MonoRuntimeScene");
|
|
GameObject* host = runtimeScene->CreateGameObject("Host");
|
|
GameObject* target = runtimeScene->CreateGameObject("Target");
|
|
ScriptComponent* component = AddScript(host, "Gameplay", "LifecycleProbe");
|
|
|
|
component->GetFieldStorage().SetFieldValue("Speed", 5.0f);
|
|
component->GetFieldStorage().SetFieldValue("Label", "Configured");
|
|
component->GetFieldStorage().SetFieldValue("Target", GameObjectReference{target->GetUUID()});
|
|
component->GetFieldStorage().SetFieldValue("SpawnPoint", XCEngine::Math::Vector3(2.0f, 4.0f, 6.0f));
|
|
|
|
engine->OnRuntimeStart(runtimeScene);
|
|
engine->OnFixedUpdate(0.02f);
|
|
engine->OnUpdate(0.016f);
|
|
engine->OnLateUpdate(0.016f);
|
|
|
|
EXPECT_TRUE(runtime->HasManagedInstance(component));
|
|
EXPECT_EQ(runtime->GetManagedInstanceCount(), 1u);
|
|
|
|
int32_t awakeCount = 0;
|
|
int32_t enableCount = 0;
|
|
int32_t startCount = 0;
|
|
int32_t fixedUpdateCount = 0;
|
|
int32_t updateCount = 0;
|
|
int32_t lateUpdateCount = 0;
|
|
bool wasAwakened = false;
|
|
bool warningLogged = false;
|
|
bool errorLogged = false;
|
|
bool hasTransform = false;
|
|
bool transformLookupSucceeded = false;
|
|
bool hasUnsupportedComponent = true;
|
|
bool unsupportedComponentLookupReturnedNull = false;
|
|
bool targetResolved = false;
|
|
bool rotationAccessed = false;
|
|
bool scaleAccessed = false;
|
|
bool transformAccessed = false;
|
|
bool observedEnabled = false;
|
|
bool observedActiveSelf = false;
|
|
bool observedActiveInHierarchy = false;
|
|
bool observedIsActiveAndEnabled = false;
|
|
float speed = 0.0f;
|
|
float observedFixedDeltaTime = 0.0f;
|
|
float observedUpdateDeltaTime = 0.0f;
|
|
float observedLateDeltaTime = 0.0f;
|
|
std::string label;
|
|
std::string observedGameObjectName;
|
|
std::string observedTargetName;
|
|
GameObjectReference targetReference;
|
|
GameObjectReference selfReference;
|
|
XCEngine::Math::Vector4 observedLocalRotation;
|
|
XCEngine::Math::Vector3 observedLocalPosition;
|
|
XCEngine::Math::Vector3 observedLocalScale;
|
|
XCEngine::Math::Vector3 spawnPoint;
|
|
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "AwakeCount", awakeCount));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "EnableCount", enableCount));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "StartCount", startCount));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "FixedUpdateCount", fixedUpdateCount));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "UpdateCount", updateCount));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "LateUpdateCount", lateUpdateCount));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "WasAwakened", wasAwakened));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "WarningLogged", warningLogged));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ErrorLogged", errorLogged));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "HasTransform", hasTransform));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "TransformLookupSucceeded", transformLookupSucceeded));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "HasUnsupportedComponent", hasUnsupportedComponent));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "UnsupportedComponentLookupReturnedNull", unsupportedComponentLookupReturnedNull));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "TargetResolved", targetResolved));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "RotationAccessed", rotationAccessed));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ScaleAccessed", scaleAccessed));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "TransformAccessed", transformAccessed));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedEnabled", observedEnabled));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedActiveSelf", observedActiveSelf));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedActiveInHierarchy", observedActiveInHierarchy));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedIsActiveAndEnabled", observedIsActiveAndEnabled));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "Speed", speed));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedFixedDeltaTime", observedFixedDeltaTime));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedUpdateDeltaTime", observedUpdateDeltaTime));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedLateDeltaTime", observedLateDeltaTime));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "Label", label));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedGameObjectName", observedGameObjectName));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedTargetName", observedTargetName));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "Target", targetReference));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "SelfReference", selfReference));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedLocalRotation", observedLocalRotation));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedLocalPosition", observedLocalPosition));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedLocalScale", observedLocalScale));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "SpawnPoint", spawnPoint));
|
|
|
|
EXPECT_EQ(awakeCount, 1);
|
|
EXPECT_EQ(enableCount, 1);
|
|
EXPECT_EQ(startCount, 1);
|
|
EXPECT_EQ(fixedUpdateCount, 1);
|
|
EXPECT_EQ(updateCount, 1);
|
|
EXPECT_EQ(lateUpdateCount, 1);
|
|
EXPECT_TRUE(wasAwakened);
|
|
EXPECT_TRUE(warningLogged);
|
|
EXPECT_TRUE(errorLogged);
|
|
EXPECT_TRUE(hasTransform);
|
|
EXPECT_TRUE(transformLookupSucceeded);
|
|
EXPECT_FALSE(hasUnsupportedComponent);
|
|
EXPECT_TRUE(unsupportedComponentLookupReturnedNull);
|
|
EXPECT_TRUE(targetResolved);
|
|
EXPECT_TRUE(rotationAccessed);
|
|
EXPECT_TRUE(scaleAccessed);
|
|
EXPECT_TRUE(transformAccessed);
|
|
EXPECT_TRUE(observedEnabled);
|
|
EXPECT_TRUE(observedActiveSelf);
|
|
EXPECT_TRUE(observedActiveInHierarchy);
|
|
EXPECT_TRUE(observedIsActiveAndEnabled);
|
|
EXPECT_FLOAT_EQ(speed, 6.0f);
|
|
EXPECT_FLOAT_EQ(observedFixedDeltaTime, 0.02f);
|
|
EXPECT_FLOAT_EQ(observedUpdateDeltaTime, 0.016f);
|
|
EXPECT_FLOAT_EQ(observedLateDeltaTime, 0.016f);
|
|
EXPECT_EQ(label, "Configured|Awake");
|
|
EXPECT_EQ(observedGameObjectName, "Host_Managed");
|
|
EXPECT_EQ(observedTargetName, "Target");
|
|
EXPECT_EQ(targetReference, GameObjectReference{target->GetUUID()});
|
|
EXPECT_EQ(selfReference, GameObjectReference{host->GetUUID()});
|
|
EXPECT_EQ(observedLocalRotation, XCEngine::Math::Vector4(0.0f, 0.5f, 0.0f, 0.8660254f));
|
|
EXPECT_EQ(observedLocalPosition, XCEngine::Math::Vector3(8.0f, 8.0f, 9.0f));
|
|
EXPECT_EQ(observedLocalScale, XCEngine::Math::Vector3(3.0f, 3.0f, 4.0f));
|
|
EXPECT_EQ(spawnPoint, XCEngine::Math::Vector3(3.0f, 4.0f, 6.0f));
|
|
EXPECT_EQ(host->GetName(), "Host_Managed");
|
|
EXPECT_EQ(host->GetTransform()->GetLocalPosition(), XCEngine::Math::Vector3(8.0f, 8.0f, 9.0f));
|
|
EXPECT_EQ(host->GetTransform()->GetLocalScale(), XCEngine::Math::Vector3(3.0f, 3.0f, 4.0f));
|
|
|
|
const XCEngine::Math::Quaternion& localRotation = host->GetTransform()->GetLocalRotation();
|
|
EXPECT_FLOAT_EQ(localRotation.x, 0.0f);
|
|
EXPECT_FLOAT_EQ(localRotation.y, 0.5f);
|
|
EXPECT_FLOAT_EQ(localRotation.z, 0.0f);
|
|
EXPECT_FLOAT_EQ(localRotation.w, 0.8660254f);
|
|
}
|
|
|
|
TEST_F(MonoScriptRuntimeTest, GameObjectComponentApiResolvesTransformAndRejectsUnsupportedManagedTypes) {
|
|
Scene* runtimeScene = CreateScene("MonoRuntimeScene");
|
|
GameObject* host = runtimeScene->CreateGameObject("Host");
|
|
ScriptComponent* component = AddScript(host, "Gameplay", "LifecycleProbe");
|
|
|
|
engine->OnRuntimeStart(runtimeScene);
|
|
engine->OnUpdate(0.016f);
|
|
|
|
bool hasTransform = false;
|
|
bool transformLookupSucceeded = false;
|
|
bool hasUnsupportedComponent = true;
|
|
bool unsupportedComponentLookupReturnedNull = false;
|
|
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "HasTransform", hasTransform));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "TransformLookupSucceeded", transformLookupSucceeded));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "HasUnsupportedComponent", hasUnsupportedComponent));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "UnsupportedComponentLookupReturnedNull", unsupportedComponentLookupReturnedNull));
|
|
|
|
EXPECT_TRUE(hasTransform);
|
|
EXPECT_TRUE(transformLookupSucceeded);
|
|
EXPECT_FALSE(hasUnsupportedComponent);
|
|
EXPECT_TRUE(unsupportedComponentLookupReturnedNull);
|
|
EXPECT_EQ(host->GetTransform()->GetLocalPosition(), XCEngine::Math::Vector3(7.0f, 8.0f, 9.0f));
|
|
}
|
|
|
|
TEST_F(MonoScriptRuntimeTest, ManagedBuiltInComponentWrappersReadAndWriteCameraAndLight) {
|
|
Scene* runtimeScene = CreateScene("MonoRuntimeScene");
|
|
GameObject* host = runtimeScene->CreateGameObject("Host");
|
|
CameraComponent* camera = host->AddComponent<CameraComponent>();
|
|
LightComponent* light = host->AddComponent<LightComponent>();
|
|
ScriptComponent* component = AddScript(host, "Gameplay", "BuiltinComponentProbe");
|
|
|
|
camera->SetFieldOfView(52.0f);
|
|
camera->SetNearClipPlane(0.2f);
|
|
camera->SetFarClipPlane(300.0f);
|
|
camera->SetDepth(1.5f);
|
|
camera->SetPrimary(true);
|
|
|
|
light->SetIntensity(1.25f);
|
|
light->SetRange(12.0f);
|
|
light->SetSpotAngle(33.0f);
|
|
light->SetCastsShadows(false);
|
|
|
|
engine->OnRuntimeStart(runtimeScene);
|
|
engine->OnUpdate(0.016f);
|
|
|
|
bool hasCamera = false;
|
|
bool hasLight = false;
|
|
bool cameraLookupSucceeded = false;
|
|
bool lightLookupSucceeded = false;
|
|
bool observedPrimary = false;
|
|
bool observedCastsShadows = true;
|
|
float observedFieldOfView = 0.0f;
|
|
float observedNearClipPlane = 0.0f;
|
|
float observedFarClipPlane = 0.0f;
|
|
float observedDepth = 0.0f;
|
|
float observedIntensity = 0.0f;
|
|
float observedRange = 0.0f;
|
|
float observedSpotAngle = 0.0f;
|
|
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "HasCamera", hasCamera));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "HasLight", hasLight));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "CameraLookupSucceeded", cameraLookupSucceeded));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "LightLookupSucceeded", lightLookupSucceeded));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedFieldOfView", observedFieldOfView));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedNearClipPlane", observedNearClipPlane));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedFarClipPlane", observedFarClipPlane));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedDepth", observedDepth));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedPrimary", observedPrimary));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedIntensity", observedIntensity));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedRange", observedRange));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedSpotAngle", observedSpotAngle));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedCastsShadows", observedCastsShadows));
|
|
|
|
EXPECT_TRUE(hasCamera);
|
|
EXPECT_TRUE(hasLight);
|
|
EXPECT_TRUE(cameraLookupSucceeded);
|
|
EXPECT_TRUE(lightLookupSucceeded);
|
|
|
|
EXPECT_FLOAT_EQ(observedFieldOfView, 52.0f);
|
|
EXPECT_FLOAT_EQ(observedNearClipPlane, 0.2f);
|
|
EXPECT_FLOAT_EQ(observedFarClipPlane, 300.0f);
|
|
EXPECT_FLOAT_EQ(observedDepth, 1.5f);
|
|
EXPECT_TRUE(observedPrimary);
|
|
EXPECT_FLOAT_EQ(observedIntensity, 1.25f);
|
|
EXPECT_FLOAT_EQ(observedRange, 12.0f);
|
|
EXPECT_FLOAT_EQ(observedSpotAngle, 33.0f);
|
|
EXPECT_FALSE(observedCastsShadows);
|
|
|
|
EXPECT_FLOAT_EQ(camera->GetFieldOfView(), 75.0f);
|
|
EXPECT_FLOAT_EQ(camera->GetNearClipPlane(), 0.3f);
|
|
EXPECT_FLOAT_EQ(camera->GetFarClipPlane(), 500.0f);
|
|
EXPECT_FLOAT_EQ(camera->GetDepth(), 3.0f);
|
|
EXPECT_FALSE(camera->IsPrimary());
|
|
|
|
EXPECT_FLOAT_EQ(light->GetIntensity(), 2.5f);
|
|
EXPECT_FLOAT_EQ(light->GetRange(), 42.0f);
|
|
EXPECT_FLOAT_EQ(light->GetSpotAngle(), 55.0f);
|
|
EXPECT_TRUE(light->GetCastsShadows());
|
|
}
|
|
|
|
TEST_F(MonoScriptRuntimeTest, ManagedMeshComponentWrappersReadAndWritePathsAndFlags) {
|
|
Scene* runtimeScene = CreateScene("MonoRuntimeScene");
|
|
GameObject* host = runtimeScene->CreateGameObject("Host");
|
|
MeshFilterComponent* meshFilter = host->AddComponent<MeshFilterComponent>();
|
|
MeshRendererComponent* meshRenderer = host->AddComponent<MeshRendererComponent>();
|
|
ScriptComponent* component = AddScript(host, "Gameplay", "MeshComponentProbe");
|
|
|
|
meshFilter->SetMeshPath("Meshes/initial.mesh");
|
|
meshRenderer->SetMaterialPath(0, "Materials/initial.mat");
|
|
meshRenderer->SetCastShadows(true);
|
|
meshRenderer->SetReceiveShadows(false);
|
|
meshRenderer->SetRenderLayer(7);
|
|
|
|
engine->OnRuntimeStart(runtimeScene);
|
|
engine->OnUpdate(0.016f);
|
|
|
|
bool hasMeshFilter = false;
|
|
bool hasMeshRenderer = false;
|
|
bool meshFilterLookupSucceeded = false;
|
|
bool meshRendererLookupSucceeded = false;
|
|
std::string observedInitialMeshPath;
|
|
std::string observedUpdatedMeshPath;
|
|
int32_t observedInitialMaterialCount = 0;
|
|
std::string observedInitialMaterial0Path;
|
|
bool observedInitialCastShadows = false;
|
|
bool observedInitialReceiveShadows = true;
|
|
int32_t observedInitialRenderLayer = 0;
|
|
int32_t observedUpdatedMaterialCount = 0;
|
|
std::string observedUpdatedMaterial1Path;
|
|
bool observedUpdatedCastShadows = true;
|
|
bool observedUpdatedReceiveShadows = false;
|
|
int32_t observedUpdatedRenderLayer = 0;
|
|
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "HasMeshFilter", hasMeshFilter));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "HasMeshRenderer", hasMeshRenderer));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "MeshFilterLookupSucceeded", meshFilterLookupSucceeded));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "MeshRendererLookupSucceeded", meshRendererLookupSucceeded));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedInitialMeshPath", observedInitialMeshPath));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedUpdatedMeshPath", observedUpdatedMeshPath));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedInitialMaterialCount", observedInitialMaterialCount));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedInitialMaterial0Path", observedInitialMaterial0Path));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedInitialCastShadows", observedInitialCastShadows));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedInitialReceiveShadows", observedInitialReceiveShadows));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedInitialRenderLayer", observedInitialRenderLayer));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedUpdatedMaterialCount", observedUpdatedMaterialCount));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedUpdatedMaterial1Path", observedUpdatedMaterial1Path));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedUpdatedCastShadows", observedUpdatedCastShadows));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedUpdatedReceiveShadows", observedUpdatedReceiveShadows));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedUpdatedRenderLayer", observedUpdatedRenderLayer));
|
|
|
|
EXPECT_TRUE(hasMeshFilter);
|
|
EXPECT_TRUE(hasMeshRenderer);
|
|
EXPECT_TRUE(meshFilterLookupSucceeded);
|
|
EXPECT_TRUE(meshRendererLookupSucceeded);
|
|
EXPECT_EQ(observedInitialMeshPath, "Meshes/initial.mesh");
|
|
EXPECT_EQ(observedUpdatedMeshPath, "Meshes/runtime_override.mesh");
|
|
EXPECT_EQ(observedInitialMaterialCount, 1);
|
|
EXPECT_EQ(observedInitialMaterial0Path, "Materials/initial.mat");
|
|
EXPECT_TRUE(observedInitialCastShadows);
|
|
EXPECT_FALSE(observedInitialReceiveShadows);
|
|
EXPECT_EQ(observedInitialRenderLayer, 7);
|
|
EXPECT_EQ(observedUpdatedMaterialCount, 2);
|
|
EXPECT_EQ(observedUpdatedMaterial1Path, "Materials/runtime_override.mat");
|
|
EXPECT_FALSE(observedUpdatedCastShadows);
|
|
EXPECT_TRUE(observedUpdatedReceiveShadows);
|
|
EXPECT_EQ(observedUpdatedRenderLayer, 11);
|
|
|
|
EXPECT_EQ(meshFilter->GetMeshPath(), "Meshes/runtime_override.mesh");
|
|
ASSERT_EQ(meshRenderer->GetMaterialCount(), 2u);
|
|
EXPECT_EQ(meshRenderer->GetMaterialPath(0), "Materials/initial.mat");
|
|
EXPECT_EQ(meshRenderer->GetMaterialPath(1), "Materials/runtime_override.mat");
|
|
EXPECT_FALSE(meshRenderer->GetCastShadows());
|
|
EXPECT_TRUE(meshRenderer->GetReceiveShadows());
|
|
EXPECT_EQ(meshRenderer->GetRenderLayer(), 11u);
|
|
}
|
|
|
|
TEST_F(MonoScriptRuntimeTest, ManagedMeshRendererWrapperHandlesClearAndBoundaryCases) {
|
|
Scene* runtimeScene = CreateScene("MonoRuntimeScene");
|
|
GameObject* host = runtimeScene->CreateGameObject("Host");
|
|
MeshRendererComponent* meshRenderer = host->AddComponent<MeshRendererComponent>();
|
|
ScriptComponent* component = AddScript(host, "Gameplay", "MeshRendererEdgeCaseProbe");
|
|
|
|
meshRenderer->SetMaterialPath(0, "Materials/initial0.mat");
|
|
meshRenderer->SetMaterialPath(1, "Materials/initial1.mat");
|
|
meshRenderer->SetCastShadows(false);
|
|
meshRenderer->SetReceiveShadows(true);
|
|
meshRenderer->SetRenderLayer(9);
|
|
|
|
engine->OnRuntimeStart(runtimeScene);
|
|
engine->OnUpdate(0.016f);
|
|
|
|
int32_t observedInitialMaterialCount = 0;
|
|
std::string observedNegativeIndexPath;
|
|
std::string observedOutOfRangePathBeforeClear;
|
|
std::string observedMaterial0PathAfterNegativeWrite;
|
|
std::string observedMaterial1PathAfterNegativeWrite;
|
|
int32_t observedMaterialCountAfterNegativeWrite = 0;
|
|
int32_t observedRenderLayerAfterNegativeWrite = -1;
|
|
int32_t observedMaterialCountAfterClear = -1;
|
|
std::string observedMaterial0PathAfterClear;
|
|
std::string observedMaterial3PathAfterClear;
|
|
bool observedCastShadowsAfterClear = true;
|
|
bool observedReceiveShadowsAfterClear = false;
|
|
int32_t observedRenderLayerAfterClear = -1;
|
|
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedInitialMaterialCount", observedInitialMaterialCount));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedNegativeIndexPath", observedNegativeIndexPath));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedOutOfRangePathBeforeClear", observedOutOfRangePathBeforeClear));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedMaterial0PathAfterNegativeWrite", observedMaterial0PathAfterNegativeWrite));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedMaterial1PathAfterNegativeWrite", observedMaterial1PathAfterNegativeWrite));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedMaterialCountAfterNegativeWrite", observedMaterialCountAfterNegativeWrite));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedRenderLayerAfterNegativeWrite", observedRenderLayerAfterNegativeWrite));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedMaterialCountAfterClear", observedMaterialCountAfterClear));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedMaterial0PathAfterClear", observedMaterial0PathAfterClear));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedMaterial3PathAfterClear", observedMaterial3PathAfterClear));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedCastShadowsAfterClear", observedCastShadowsAfterClear));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedReceiveShadowsAfterClear", observedReceiveShadowsAfterClear));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedRenderLayerAfterClear", observedRenderLayerAfterClear));
|
|
|
|
EXPECT_EQ(observedInitialMaterialCount, 2);
|
|
EXPECT_EQ(observedNegativeIndexPath, "");
|
|
EXPECT_EQ(observedOutOfRangePathBeforeClear, "");
|
|
EXPECT_EQ(observedMaterial0PathAfterNegativeWrite, "Materials/initial0.mat");
|
|
EXPECT_EQ(observedMaterial1PathAfterNegativeWrite, "Materials/initial1.mat");
|
|
EXPECT_EQ(observedMaterialCountAfterNegativeWrite, 2);
|
|
EXPECT_EQ(observedRenderLayerAfterNegativeWrite, 0);
|
|
EXPECT_EQ(observedMaterialCountAfterClear, 0);
|
|
EXPECT_EQ(observedMaterial0PathAfterClear, "");
|
|
EXPECT_EQ(observedMaterial3PathAfterClear, "");
|
|
EXPECT_FALSE(observedCastShadowsAfterClear);
|
|
EXPECT_TRUE(observedReceiveShadowsAfterClear);
|
|
EXPECT_EQ(observedRenderLayerAfterClear, 0);
|
|
|
|
EXPECT_EQ(meshRenderer->GetMaterialCount(), 0u);
|
|
EXPECT_EQ(meshRenderer->GetMaterialPath(0), "");
|
|
EXPECT_EQ(meshRenderer->GetMaterialPath(3), "");
|
|
EXPECT_FALSE(meshRenderer->GetCastShadows());
|
|
EXPECT_TRUE(meshRenderer->GetReceiveShadows());
|
|
EXPECT_EQ(meshRenderer->GetRenderLayer(), 0u);
|
|
}
|
|
|
|
TEST_F(MonoScriptRuntimeTest, GameObjectAddComponentApiCreatesBuiltinComponentsAndAvoidsDuplicates) {
|
|
Scene* runtimeScene = CreateScene("MonoRuntimeScene");
|
|
GameObject* host = runtimeScene->CreateGameObject("Host");
|
|
ScriptComponent* component = AddScript(host, "Gameplay", "AddComponentProbe");
|
|
|
|
engine->OnRuntimeStart(runtimeScene);
|
|
engine->OnUpdate(0.016f);
|
|
|
|
bool initialHasCamera = true;
|
|
bool initialHasLight = true;
|
|
bool initialHasMeshFilter = true;
|
|
bool initialHasMeshRenderer = true;
|
|
bool addedTransform = false;
|
|
bool addedCamera = false;
|
|
bool addedLight = false;
|
|
bool addedMeshFilter = false;
|
|
bool addedMeshRenderer = false;
|
|
bool hasCameraAfterAdd = false;
|
|
bool hasLightAfterAdd = false;
|
|
bool hasMeshFilterAfterAdd = false;
|
|
bool hasMeshRendererAfterAdd = false;
|
|
bool cameraLookupSucceeded = false;
|
|
bool lightLookupSucceeded = false;
|
|
bool meshFilterLookupSucceeded = false;
|
|
bool meshRendererLookupSucceeded = false;
|
|
float observedCameraFieldOfView = 0.0f;
|
|
float observedLightIntensity = 0.0f;
|
|
std::string observedMeshPath;
|
|
int32_t observedMaterialCount = 0;
|
|
std::string observedMaterial0Path;
|
|
int32_t observedRenderLayer = 0;
|
|
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "InitialHasCamera", initialHasCamera));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "InitialHasLight", initialHasLight));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "InitialHasMeshFilter", initialHasMeshFilter));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "InitialHasMeshRenderer", initialHasMeshRenderer));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "AddedTransform", addedTransform));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "AddedCamera", addedCamera));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "AddedLight", addedLight));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "AddedMeshFilter", addedMeshFilter));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "AddedMeshRenderer", addedMeshRenderer));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "HasCameraAfterAdd", hasCameraAfterAdd));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "HasLightAfterAdd", hasLightAfterAdd));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "HasMeshFilterAfterAdd", hasMeshFilterAfterAdd));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "HasMeshRendererAfterAdd", hasMeshRendererAfterAdd));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "CameraLookupSucceeded", cameraLookupSucceeded));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "LightLookupSucceeded", lightLookupSucceeded));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "MeshFilterLookupSucceeded", meshFilterLookupSucceeded));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "MeshRendererLookupSucceeded", meshRendererLookupSucceeded));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedCameraFieldOfView", observedCameraFieldOfView));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedLightIntensity", observedLightIntensity));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedMeshPath", observedMeshPath));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedMaterialCount", observedMaterialCount));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedMaterial0Path", observedMaterial0Path));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedRenderLayer", observedRenderLayer));
|
|
|
|
EXPECT_FALSE(initialHasCamera);
|
|
EXPECT_FALSE(initialHasLight);
|
|
EXPECT_FALSE(initialHasMeshFilter);
|
|
EXPECT_FALSE(initialHasMeshRenderer);
|
|
EXPECT_TRUE(addedTransform);
|
|
EXPECT_TRUE(addedCamera);
|
|
EXPECT_TRUE(addedLight);
|
|
EXPECT_TRUE(addedMeshFilter);
|
|
EXPECT_TRUE(addedMeshRenderer);
|
|
EXPECT_TRUE(hasCameraAfterAdd);
|
|
EXPECT_TRUE(hasLightAfterAdd);
|
|
EXPECT_TRUE(hasMeshFilterAfterAdd);
|
|
EXPECT_TRUE(hasMeshRendererAfterAdd);
|
|
EXPECT_TRUE(cameraLookupSucceeded);
|
|
EXPECT_TRUE(lightLookupSucceeded);
|
|
EXPECT_TRUE(meshFilterLookupSucceeded);
|
|
EXPECT_TRUE(meshRendererLookupSucceeded);
|
|
EXPECT_FLOAT_EQ(observedCameraFieldOfView, 82.0f);
|
|
EXPECT_FLOAT_EQ(observedLightIntensity, 4.5f);
|
|
EXPECT_EQ(observedMeshPath, "Meshes/added.mesh");
|
|
EXPECT_EQ(observedMaterialCount, 1);
|
|
EXPECT_EQ(observedMaterial0Path, "Materials/added.mat");
|
|
EXPECT_EQ(observedRenderLayer, 6);
|
|
|
|
ASSERT_NE(host->GetTransform(), nullptr);
|
|
EXPECT_EQ(host->GetComponents<CameraComponent>().size(), 1u);
|
|
EXPECT_EQ(host->GetComponents<LightComponent>().size(), 1u);
|
|
EXPECT_EQ(host->GetComponents<MeshFilterComponent>().size(), 1u);
|
|
EXPECT_EQ(host->GetComponents<MeshRendererComponent>().size(), 1u);
|
|
|
|
CameraComponent* camera = host->GetComponent<CameraComponent>();
|
|
LightComponent* light = host->GetComponent<LightComponent>();
|
|
MeshFilterComponent* meshFilter = host->GetComponent<MeshFilterComponent>();
|
|
MeshRendererComponent* meshRenderer = host->GetComponent<MeshRendererComponent>();
|
|
|
|
ASSERT_NE(camera, nullptr);
|
|
ASSERT_NE(light, nullptr);
|
|
ASSERT_NE(meshFilter, nullptr);
|
|
ASSERT_NE(meshRenderer, nullptr);
|
|
|
|
EXPECT_FLOAT_EQ(camera->GetFieldOfView(), 82.0f);
|
|
EXPECT_FLOAT_EQ(light->GetIntensity(), 4.5f);
|
|
EXPECT_EQ(meshFilter->GetMeshPath(), "Meshes/added.mesh");
|
|
ASSERT_EQ(meshRenderer->GetMaterialCount(), 1u);
|
|
EXPECT_EQ(meshRenderer->GetMaterialPath(0), "Materials/added.mat");
|
|
EXPECT_EQ(meshRenderer->GetRenderLayer(), 6u);
|
|
}
|
|
|
|
TEST_F(MonoScriptRuntimeTest, TransformHierarchyApiExposesParentChildAndReparenting) {
|
|
Scene* runtimeScene = CreateScene("MonoRuntimeScene");
|
|
GameObject* root = runtimeScene->CreateGameObject("Root");
|
|
GameObject* host = runtimeScene->CreateGameObject("Host", root);
|
|
GameObject* child = runtimeScene->CreateGameObject("Child", host);
|
|
GameObject* reparentTarget = runtimeScene->CreateGameObject("ReparentTarget");
|
|
ScriptComponent* component = AddScript(host, "Gameplay", "HierarchyProbe");
|
|
|
|
component->GetFieldStorage().SetFieldValue("ReparentTarget", GameObjectReference{reparentTarget->GetUUID()});
|
|
|
|
engine->OnRuntimeStart(runtimeScene);
|
|
engine->OnUpdate(0.016f);
|
|
|
|
int32_t observedChildCount = 0;
|
|
bool parentLookupSucceeded = false;
|
|
bool childLookupSucceeded = false;
|
|
std::string observedParentName;
|
|
std::string observedFirstChildName;
|
|
std::string reparentedChildParentName;
|
|
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedChildCount", observedChildCount));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ParentLookupSucceeded", parentLookupSucceeded));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ChildLookupSucceeded", childLookupSucceeded));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedParentName", observedParentName));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedFirstChildName", observedFirstChildName));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ReparentedChildParentName", reparentedChildParentName));
|
|
|
|
EXPECT_TRUE(parentLookupSucceeded);
|
|
EXPECT_TRUE(childLookupSucceeded);
|
|
EXPECT_EQ(observedChildCount, 1);
|
|
EXPECT_EQ(observedParentName, "Root");
|
|
EXPECT_EQ(observedFirstChildName, "Child");
|
|
EXPECT_EQ(reparentedChildParentName, "ReparentTarget");
|
|
|
|
EXPECT_EQ(host->GetParent(), root);
|
|
EXPECT_EQ(host->GetChildCount(), 0u);
|
|
EXPECT_EQ(child->GetParent(), reparentTarget);
|
|
EXPECT_EQ(reparentTarget->GetChildCount(), 1u);
|
|
}
|
|
|
|
TEST_F(MonoScriptRuntimeTest, TransformSpaceApiReadsAndWritesWorldAndLocalValues) {
|
|
Scene* runtimeScene = CreateScene("MonoRuntimeScene");
|
|
GameObject* parent = runtimeScene->CreateGameObject("Parent");
|
|
GameObject* host = runtimeScene->CreateGameObject("Host", parent);
|
|
ScriptComponent* component = AddScript(host, "Gameplay", "TransformSpaceProbe");
|
|
|
|
parent->GetTransform()->SetLocalPosition(XCEngine::Math::Vector3(10.0f, 0.0f, 0.0f));
|
|
parent->GetTransform()->SetLocalScale(XCEngine::Math::Vector3(2.0f, 2.0f, 2.0f));
|
|
host->GetTransform()->SetLocalPosition(XCEngine::Math::Vector3(1.0f, 2.0f, 3.0f));
|
|
host->GetTransform()->SetLocalScale(XCEngine::Math::Vector3(1.0f, 1.0f, 1.0f));
|
|
|
|
engine->OnRuntimeStart(runtimeScene);
|
|
engine->OnUpdate(0.016f);
|
|
|
|
XCEngine::Math::Vector3 observedInitialWorldPosition;
|
|
XCEngine::Math::Vector3 observedInitialWorldScale;
|
|
XCEngine::Math::Vector3 observedInitialLocalEulerAngles;
|
|
XCEngine::Math::Vector3 observedEulerAfterSet;
|
|
XCEngine::Math::Vector3 observedWorldPositionAfterSet;
|
|
XCEngine::Math::Vector3 observedWorldScaleAfterSet;
|
|
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedInitialWorldPosition", observedInitialWorldPosition));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedInitialWorldScale", observedInitialWorldScale));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedInitialLocalEulerAngles", observedInitialLocalEulerAngles));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedEulerAfterSet", observedEulerAfterSet));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedWorldPositionAfterSet", observedWorldPositionAfterSet));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedWorldScaleAfterSet", observedWorldScaleAfterSet));
|
|
|
|
EXPECT_EQ(observedInitialWorldPosition, XCEngine::Math::Vector3(12.0f, 4.0f, 6.0f));
|
|
EXPECT_EQ(observedInitialWorldScale, XCEngine::Math::Vector3(2.0f, 2.0f, 2.0f));
|
|
EXPECT_EQ(observedInitialLocalEulerAngles, XCEngine::Math::Vector3(0.0f, 0.0f, 0.0f));
|
|
EXPECT_NEAR(observedEulerAfterSet.x, 0.0f, 0.001f);
|
|
EXPECT_NEAR(observedEulerAfterSet.y, 45.0f, 0.001f);
|
|
EXPECT_NEAR(observedEulerAfterSet.z, 0.0f, 0.001f);
|
|
EXPECT_EQ(observedWorldPositionAfterSet, XCEngine::Math::Vector3(20.0f, 6.0f, 10.0f));
|
|
EXPECT_EQ(observedWorldScaleAfterSet, XCEngine::Math::Vector3(6.0f, 8.0f, 10.0f));
|
|
|
|
EXPECT_EQ(host->GetTransform()->GetLocalPosition(), XCEngine::Math::Vector3(5.0f, 3.0f, 5.0f));
|
|
EXPECT_EQ(host->GetTransform()->GetPosition(), XCEngine::Math::Vector3(20.0f, 6.0f, 10.0f));
|
|
EXPECT_EQ(host->GetTransform()->GetLocalScale(), XCEngine::Math::Vector3(3.0f, 4.0f, 5.0f));
|
|
EXPECT_EQ(host->GetTransform()->GetScale(), XCEngine::Math::Vector3(6.0f, 8.0f, 10.0f));
|
|
|
|
const XCEngine::Math::Quaternion& localRotation = host->GetTransform()->GetLocalRotation();
|
|
EXPECT_FLOAT_EQ(localRotation.x, 0.0f);
|
|
EXPECT_FLOAT_EQ(localRotation.y, 0.5f);
|
|
EXPECT_FLOAT_EQ(localRotation.z, 0.0f);
|
|
EXPECT_FLOAT_EQ(localRotation.w, 0.8660254f);
|
|
}
|
|
|
|
TEST_F(MonoScriptRuntimeTest, TransformMotionApiExposesDirectionVectorsAndAppliesOperations) {
|
|
Scene* runtimeScene = CreateScene("MonoRuntimeScene");
|
|
GameObject* host = runtimeScene->CreateGameObject("Host");
|
|
ScriptComponent* component = AddScript(host, "Gameplay", "TransformMotionProbe");
|
|
|
|
engine->OnRuntimeStart(runtimeScene);
|
|
engine->OnUpdate(0.016f);
|
|
|
|
XCEngine::Math::Vector3 observedForward;
|
|
XCEngine::Math::Vector3 observedRight;
|
|
XCEngine::Math::Vector3 observedUp;
|
|
XCEngine::Math::Vector3 observedPositionAfterSelfTranslate;
|
|
XCEngine::Math::Vector3 observedPositionAfterWorldTranslate;
|
|
XCEngine::Math::Vector3 observedForwardAfterWorldRotate;
|
|
XCEngine::Math::Vector3 observedForwardAfterSelfRotate;
|
|
XCEngine::Math::Vector3 observedForwardAfterLookAt;
|
|
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedForward", observedForward));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedRight", observedRight));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedUp", observedUp));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedPositionAfterSelfTranslate", observedPositionAfterSelfTranslate));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedPositionAfterWorldTranslate", observedPositionAfterWorldTranslate));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedForwardAfterWorldRotate", observedForwardAfterWorldRotate));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedForwardAfterSelfRotate", observedForwardAfterSelfRotate));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedForwardAfterLookAt", observedForwardAfterLookAt));
|
|
|
|
ExpectVector3Near(observedForward, XCEngine::Math::Vector3(1.0f, 0.0f, 0.0f));
|
|
ExpectVector3Near(observedRight, XCEngine::Math::Vector3(0.0f, 0.0f, -1.0f));
|
|
ExpectVector3Near(observedUp, XCEngine::Math::Vector3(0.0f, 1.0f, 0.0f));
|
|
ExpectVector3Near(observedPositionAfterSelfTranslate, XCEngine::Math::Vector3(2.0f, 0.0f, 0.0f));
|
|
ExpectVector3Near(observedPositionAfterWorldTranslate, XCEngine::Math::Vector3(2.0f, 0.0f, 3.0f));
|
|
ExpectVector3Near(observedForwardAfterWorldRotate, XCEngine::Math::Vector3(0.0f, 0.0f, 1.0f));
|
|
ExpectVector3Near(observedForwardAfterSelfRotate, XCEngine::Math::Vector3(1.0f, 0.0f, 0.0f));
|
|
ExpectVector3Near(observedForwardAfterLookAt, XCEngine::Math::Vector3(0.0f, 0.0f, 1.0f));
|
|
|
|
ExpectVector3Near(host->GetTransform()->GetPosition(), XCEngine::Math::Vector3(2.0f, 0.0f, 3.0f));
|
|
ExpectVector3Near(host->GetTransform()->GetForward(), XCEngine::Math::Vector3(0.0f, 0.0f, 1.0f));
|
|
}
|
|
|
|
TEST_F(MonoScriptRuntimeTest, TransformConversionApiTransformsPointsAndDirectionsBetweenSpaces) {
|
|
Scene* runtimeScene = CreateScene("MonoRuntimeScene");
|
|
GameObject* host = runtimeScene->CreateGameObject("Host");
|
|
ScriptComponent* component = AddScript(host, "Gameplay", "TransformConversionProbe");
|
|
|
|
engine->OnRuntimeStart(runtimeScene);
|
|
engine->OnUpdate(0.016f);
|
|
|
|
XCEngine::Math::Vector3 observedWorldPoint;
|
|
XCEngine::Math::Vector3 observedLocalPoint;
|
|
XCEngine::Math::Vector3 observedWorldDirection;
|
|
XCEngine::Math::Vector3 observedLocalDirection;
|
|
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedWorldPoint", observedWorldPoint));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedLocalPoint", observedLocalPoint));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedWorldDirection", observedWorldDirection));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedLocalDirection", observedLocalDirection));
|
|
|
|
ExpectVector3Near(observedWorldPoint, XCEngine::Math::Vector3(7.0f, 0.0f, 1.0f));
|
|
ExpectVector3Near(observedLocalPoint, XCEngine::Math::Vector3(0.0f, 0.0f, 2.0f));
|
|
ExpectVector3Near(observedWorldDirection, XCEngine::Math::Vector3(1.0f, 0.0f, 0.0f));
|
|
ExpectVector3Near(observedLocalDirection, XCEngine::Math::Vector3(0.0f, 0.0f, 1.0f));
|
|
|
|
ExpectVector3Near(host->GetTransform()->TransformPoint(XCEngine::Math::Vector3(0.0f, 0.0f, 2.0f)), XCEngine::Math::Vector3(7.0f, 0.0f, 1.0f));
|
|
ExpectVector3Near(host->GetTransform()->InverseTransformDirection(XCEngine::Math::Vector3(1.0f, 0.0f, 0.0f)), XCEngine::Math::Vector3(0.0f, 0.0f, 1.0f));
|
|
}
|
|
|
|
TEST_F(MonoScriptRuntimeTest, TransformOrientationOverloadsSupportAxisAngleAndCustomUpVector) {
|
|
Scene* runtimeScene = CreateScene("MonoRuntimeScene");
|
|
GameObject* host = runtimeScene->CreateGameObject("Host");
|
|
ScriptComponent* component = AddScript(host, "Gameplay", "TransformOrientationProbe");
|
|
|
|
engine->OnRuntimeStart(runtimeScene);
|
|
engine->OnUpdate(0.016f);
|
|
|
|
XCEngine::Math::Vector3 observedForwardAfterAxisAngleRotate;
|
|
XCEngine::Math::Vector3 observedForwardAfterWorldAxisAngleRotate;
|
|
XCEngine::Math::Vector3 observedForwardAfterDefaultLookAt;
|
|
XCEngine::Math::Vector3 observedRightAfterDefaultLookAt;
|
|
XCEngine::Math::Vector3 observedUpAfterDefaultLookAt;
|
|
XCEngine::Math::Vector3 observedForwardAfterLookAtWithUp;
|
|
XCEngine::Math::Vector3 observedRightAfterLookAtWithUp;
|
|
XCEngine::Math::Vector3 observedUpAfterLookAtWithUp;
|
|
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedForwardAfterAxisAngleRotate", observedForwardAfterAxisAngleRotate));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedForwardAfterWorldAxisAngleRotate", observedForwardAfterWorldAxisAngleRotate));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedForwardAfterDefaultLookAt", observedForwardAfterDefaultLookAt));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedRightAfterDefaultLookAt", observedRightAfterDefaultLookAt));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedUpAfterDefaultLookAt", observedUpAfterDefaultLookAt));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedForwardAfterLookAtWithUp", observedForwardAfterLookAtWithUp));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedRightAfterLookAtWithUp", observedRightAfterLookAtWithUp));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedUpAfterLookAtWithUp", observedUpAfterLookAtWithUp));
|
|
|
|
ExpectVector3Near(observedForwardAfterAxisAngleRotate, XCEngine::Math::Vector3(1.0f, 0.0f, 0.0f));
|
|
ExpectVector3Near(observedForwardAfterWorldAxisAngleRotate, XCEngine::Math::Vector3(1.0f, 0.0f, 0.0f));
|
|
|
|
EXPECT_NEAR(observedForwardAfterDefaultLookAt.Magnitude(), 1.0f, 0.001f);
|
|
EXPECT_NEAR(observedRightAfterDefaultLookAt.Magnitude(), 1.0f, 0.001f);
|
|
EXPECT_NEAR(observedUpAfterDefaultLookAt.Magnitude(), 1.0f, 0.001f);
|
|
EXPECT_NEAR(observedForwardAfterLookAtWithUp.Magnitude(), 1.0f, 0.001f);
|
|
EXPECT_NEAR(observedRightAfterLookAtWithUp.Magnitude(), 1.0f, 0.001f);
|
|
EXPECT_NEAR(observedUpAfterLookAtWithUp.Magnitude(), 1.0f, 0.001f);
|
|
|
|
EXPECT_GT((observedRightAfterLookAtWithUp - observedRightAfterDefaultLookAt).Magnitude(), 0.5f);
|
|
EXPECT_GT((observedUpAfterLookAtWithUp - observedUpAfterDefaultLookAt).Magnitude(), 0.5f);
|
|
|
|
ExpectVector3Near(host->GetTransform()->GetForward(), observedForwardAfterLookAtWithUp);
|
|
ExpectVector3Near(host->GetTransform()->GetRight(), observedRightAfterLookAtWithUp);
|
|
ExpectVector3Near(host->GetTransform()->GetUp(), observedUpAfterLookAtWithUp);
|
|
}
|
|
|
|
TEST_F(MonoScriptRuntimeTest, ManagedBehaviourCanDisableItselfThroughEnabledProperty) {
|
|
Scene* runtimeScene = CreateScene("MonoRuntimeScene");
|
|
GameObject* host = runtimeScene->CreateGameObject("Host");
|
|
ScriptComponent* component = AddScript(host, "Gameplay", "LifecycleProbe");
|
|
|
|
component->GetFieldStorage().SetFieldValue("DisableSelfOnFirstUpdate", true);
|
|
|
|
engine->OnRuntimeStart(runtimeScene);
|
|
engine->OnUpdate(0.016f);
|
|
engine->OnLateUpdate(0.016f);
|
|
|
|
int32_t updateCount = 0;
|
|
int32_t lateUpdateCount = 0;
|
|
int32_t disableCount = 0;
|
|
bool observedEnabled = false;
|
|
bool observedIsActiveAndEnabled = false;
|
|
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "UpdateCount", updateCount));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "LateUpdateCount", lateUpdateCount));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "DisableCount", disableCount));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedEnabled", observedEnabled));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedIsActiveAndEnabled", observedIsActiveAndEnabled));
|
|
|
|
EXPECT_FALSE(component->IsEnabled());
|
|
EXPECT_EQ(updateCount, 1);
|
|
EXPECT_EQ(lateUpdateCount, 0);
|
|
EXPECT_EQ(disableCount, 1);
|
|
EXPECT_TRUE(observedEnabled);
|
|
EXPECT_TRUE(observedIsActiveAndEnabled);
|
|
|
|
engine->OnUpdate(0.016f);
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "UpdateCount", updateCount));
|
|
EXPECT_EQ(updateCount, 1);
|
|
}
|
|
|
|
TEST_F(MonoScriptRuntimeTest, ManagedScriptCanDeactivateItsHostGameObject) {
|
|
Scene* runtimeScene = CreateScene("MonoRuntimeScene");
|
|
GameObject* host = runtimeScene->CreateGameObject("Host");
|
|
ScriptComponent* component = AddScript(host, "Gameplay", "LifecycleProbe");
|
|
|
|
component->GetFieldStorage().SetFieldValue("DeactivateGameObjectOnFirstUpdate", true);
|
|
|
|
engine->OnRuntimeStart(runtimeScene);
|
|
engine->OnUpdate(0.016f);
|
|
engine->OnLateUpdate(0.016f);
|
|
|
|
int32_t updateCount = 0;
|
|
int32_t lateUpdateCount = 0;
|
|
int32_t disableCount = 0;
|
|
bool observedActiveSelf = false;
|
|
bool observedActiveInHierarchy = false;
|
|
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "UpdateCount", updateCount));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "LateUpdateCount", lateUpdateCount));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "DisableCount", disableCount));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedActiveSelf", observedActiveSelf));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedActiveInHierarchy", observedActiveInHierarchy));
|
|
|
|
EXPECT_FALSE(host->IsActive());
|
|
EXPECT_FALSE(host->IsActiveInHierarchy());
|
|
EXPECT_TRUE(component->IsEnabled());
|
|
EXPECT_EQ(updateCount, 1);
|
|
EXPECT_EQ(lateUpdateCount, 0);
|
|
EXPECT_EQ(disableCount, 1);
|
|
EXPECT_TRUE(observedActiveSelf);
|
|
EXPECT_TRUE(observedActiveInHierarchy);
|
|
|
|
engine->OnUpdate(0.016f);
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "UpdateCount", updateCount));
|
|
EXPECT_EQ(updateCount, 1);
|
|
}
|
|
|
|
TEST_F(MonoScriptRuntimeTest, DisableEnablePreservesSingleInstanceAndStartOnlyRunsOnce) {
|
|
Scene* runtimeScene = CreateScene("MonoRuntimeScene");
|
|
GameObject* host = runtimeScene->CreateGameObject("Host");
|
|
ScriptComponent* component = AddScript(host, "Gameplay", "LifecycleProbe");
|
|
|
|
engine->OnRuntimeStart(runtimeScene);
|
|
engine->OnUpdate(0.016f);
|
|
|
|
component->SetEnabled(false);
|
|
|
|
int32_t disableCount = 0;
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "DisableCount", disableCount));
|
|
EXPECT_EQ(disableCount, 1);
|
|
EXPECT_EQ(runtime->GetManagedInstanceCount(), 1u);
|
|
|
|
component->SetEnabled(true);
|
|
engine->OnUpdate(0.016f);
|
|
|
|
int32_t enableCount = 0;
|
|
int32_t startCount = 0;
|
|
int32_t updateCount = 0;
|
|
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "EnableCount", enableCount));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "StartCount", startCount));
|
|
EXPECT_TRUE(runtime->TryGetFieldValue(component, "UpdateCount", updateCount));
|
|
|
|
EXPECT_EQ(enableCount, 2);
|
|
EXPECT_EQ(startCount, 1);
|
|
EXPECT_EQ(updateCount, 2);
|
|
|
|
engine->OnRuntimeStop();
|
|
|
|
EXPECT_FALSE(runtime->HasManagedInstance(component));
|
|
EXPECT_EQ(runtime->GetManagedInstanceCount(), 0u);
|
|
}
|
|
|
|
} // namespace
|