feat(scripting): add runtime gameobject lifecycle api
This commit is contained in:
@@ -562,6 +562,146 @@ TEST_F(MonoScriptRuntimeTest, GameObjectAddComponentApiCreatesBuiltinComponentsA
|
||||
EXPECT_EQ(meshRenderer->GetRenderLayer(), 6u);
|
||||
}
|
||||
|
||||
TEST_F(MonoScriptRuntimeTest, GameObjectRuntimeApiCreatesFindsAndDestroysSceneObjects) {
|
||||
Scene* runtimeScene = CreateScene("MonoRuntimeScene");
|
||||
GameObject* host = runtimeScene->CreateGameObject("Host");
|
||||
ScriptComponent* component = AddScript(host, "Gameplay", "RuntimeGameObjectProbe");
|
||||
|
||||
engine->OnRuntimeStart(runtimeScene);
|
||||
engine->OnUpdate(0.016f);
|
||||
|
||||
bool missingBeforeCreate = false;
|
||||
bool createdRootSucceeded = false;
|
||||
bool createdChildSucceeded = false;
|
||||
bool foundRootSucceeded = false;
|
||||
bool foundChildSucceeded = false;
|
||||
std::string observedFoundRootName;
|
||||
std::string observedFoundChildParentName;
|
||||
int32_t observedRootChildCountBeforeDestroy = 0;
|
||||
bool cameraLookupSucceeded = false;
|
||||
bool meshFilterLookupSucceeded = false;
|
||||
bool meshRendererLookupSucceeded = false;
|
||||
float observedCameraFieldOfView = 0.0f;
|
||||
std::string observedMeshPath;
|
||||
int32_t observedMaterialCount = 0;
|
||||
std::string observedMaterial0Path;
|
||||
int32_t observedRenderLayer = 0;
|
||||
bool missingChildAfterDestroy = false;
|
||||
bool foundRootAfterDestroySucceeded = false;
|
||||
int32_t observedRootChildCountAfterDestroy = -1;
|
||||
|
||||
EXPECT_TRUE(runtime->TryGetFieldValue(component, "MissingBeforeCreate", missingBeforeCreate));
|
||||
EXPECT_TRUE(runtime->TryGetFieldValue(component, "CreatedRootSucceeded", createdRootSucceeded));
|
||||
EXPECT_TRUE(runtime->TryGetFieldValue(component, "CreatedChildSucceeded", createdChildSucceeded));
|
||||
EXPECT_TRUE(runtime->TryGetFieldValue(component, "FoundRootSucceeded", foundRootSucceeded));
|
||||
EXPECT_TRUE(runtime->TryGetFieldValue(component, "FoundChildSucceeded", foundChildSucceeded));
|
||||
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedFoundRootName", observedFoundRootName));
|
||||
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedFoundChildParentName", observedFoundChildParentName));
|
||||
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedRootChildCountBeforeDestroy", observedRootChildCountBeforeDestroy));
|
||||
EXPECT_TRUE(runtime->TryGetFieldValue(component, "CameraLookupSucceeded", cameraLookupSucceeded));
|
||||
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, "ObservedMeshPath", observedMeshPath));
|
||||
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedMaterialCount", observedMaterialCount));
|
||||
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedMaterial0Path", observedMaterial0Path));
|
||||
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedRenderLayer", observedRenderLayer));
|
||||
EXPECT_TRUE(runtime->TryGetFieldValue(component, "MissingChildAfterDestroy", missingChildAfterDestroy));
|
||||
EXPECT_TRUE(runtime->TryGetFieldValue(component, "FoundRootAfterDestroySucceeded", foundRootAfterDestroySucceeded));
|
||||
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedRootChildCountAfterDestroy", observedRootChildCountAfterDestroy));
|
||||
|
||||
EXPECT_TRUE(missingBeforeCreate);
|
||||
EXPECT_TRUE(createdRootSucceeded);
|
||||
EXPECT_TRUE(createdChildSucceeded);
|
||||
EXPECT_TRUE(foundRootSucceeded);
|
||||
EXPECT_TRUE(foundChildSucceeded);
|
||||
EXPECT_EQ(observedFoundRootName, "RuntimeCreatedRoot");
|
||||
EXPECT_EQ(observedFoundChildParentName, "RuntimeCreatedRoot");
|
||||
EXPECT_EQ(observedRootChildCountBeforeDestroy, 1);
|
||||
EXPECT_TRUE(cameraLookupSucceeded);
|
||||
EXPECT_TRUE(meshFilterLookupSucceeded);
|
||||
EXPECT_TRUE(meshRendererLookupSucceeded);
|
||||
EXPECT_FLOAT_EQ(observedCameraFieldOfView, 68.0f);
|
||||
EXPECT_EQ(observedMeshPath, "Meshes/runtime_created.mesh");
|
||||
EXPECT_EQ(observedMaterialCount, 1);
|
||||
EXPECT_EQ(observedMaterial0Path, "Materials/runtime_created.mat");
|
||||
EXPECT_EQ(observedRenderLayer, 4);
|
||||
EXPECT_TRUE(missingChildAfterDestroy);
|
||||
EXPECT_TRUE(foundRootAfterDestroySucceeded);
|
||||
EXPECT_EQ(observedRootChildCountAfterDestroy, 0);
|
||||
|
||||
GameObject* createdRoot = runtimeScene->Find("RuntimeCreatedRoot");
|
||||
ASSERT_NE(createdRoot, nullptr);
|
||||
EXPECT_EQ(runtimeScene->Find("RuntimeCreatedChild"), nullptr);
|
||||
EXPECT_EQ(createdRoot->GetParent(), nullptr);
|
||||
EXPECT_EQ(createdRoot->GetChildCount(), 0u);
|
||||
|
||||
CameraComponent* camera = createdRoot->GetComponent<CameraComponent>();
|
||||
MeshFilterComponent* meshFilter = createdRoot->GetComponent<MeshFilterComponent>();
|
||||
MeshRendererComponent* meshRenderer = createdRoot->GetComponent<MeshRendererComponent>();
|
||||
|
||||
ASSERT_NE(camera, nullptr);
|
||||
ASSERT_NE(meshFilter, nullptr);
|
||||
ASSERT_NE(meshRenderer, nullptr);
|
||||
EXPECT_FLOAT_EQ(camera->GetFieldOfView(), 68.0f);
|
||||
EXPECT_EQ(meshFilter->GetMeshPath(), "Meshes/runtime_created.mesh");
|
||||
ASSERT_EQ(meshRenderer->GetMaterialCount(), 1u);
|
||||
EXPECT_EQ(meshRenderer->GetMaterialPath(0), "Materials/runtime_created.mat");
|
||||
EXPECT_EQ(meshRenderer->GetRenderLayer(), 4u);
|
||||
}
|
||||
|
||||
TEST_F(MonoScriptRuntimeTest, RuntimeCreatedScriptComponentCreatesManagedInstanceAfterClassAssignment) {
|
||||
Scene* runtimeScene = CreateScene("MonoRuntimeScene");
|
||||
|
||||
engine->OnRuntimeStart(runtimeScene);
|
||||
|
||||
GameObject* spawned = runtimeScene->CreateGameObject("RuntimeSpawned");
|
||||
ScriptComponent* component = spawned->AddComponent<ScriptComponent>();
|
||||
component->GetFieldStorage().SetFieldValue("Label", "RuntimeConfigured");
|
||||
component->SetScriptClass("GameScripts", "Gameplay", "LifecycleProbe");
|
||||
|
||||
EXPECT_TRUE(runtime->HasManagedInstance(component));
|
||||
|
||||
engine->OnUpdate(0.016f);
|
||||
|
||||
int32_t awakeCount = 0;
|
||||
int32_t enableCount = 0;
|
||||
int32_t startCount = 0;
|
||||
int32_t updateCount = 0;
|
||||
std::string label;
|
||||
std::string observedGameObjectName;
|
||||
bool wasAwakened = false;
|
||||
bool observedEnabled = false;
|
||||
bool observedActiveSelf = false;
|
||||
bool observedActiveInHierarchy = false;
|
||||
bool observedIsActiveAndEnabled = false;
|
||||
|
||||
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, "UpdateCount", updateCount));
|
||||
EXPECT_TRUE(runtime->TryGetFieldValue(component, "Label", label));
|
||||
EXPECT_TRUE(runtime->TryGetFieldValue(component, "ObservedGameObjectName", observedGameObjectName));
|
||||
EXPECT_TRUE(runtime->TryGetFieldValue(component, "WasAwakened", wasAwakened));
|
||||
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_EQ(awakeCount, 1);
|
||||
EXPECT_EQ(enableCount, 1);
|
||||
EXPECT_EQ(startCount, 1);
|
||||
EXPECT_EQ(updateCount, 1);
|
||||
EXPECT_EQ(label, "RuntimeConfigured|Awake");
|
||||
EXPECT_EQ(observedGameObjectName, "RuntimeSpawned_Managed");
|
||||
EXPECT_TRUE(wasAwakened);
|
||||
EXPECT_TRUE(observedEnabled);
|
||||
EXPECT_TRUE(observedActiveSelf);
|
||||
EXPECT_TRUE(observedActiveInHierarchy);
|
||||
EXPECT_TRUE(observedIsActiveAndEnabled);
|
||||
EXPECT_EQ(spawned->GetName(), "RuntimeSpawned_Managed");
|
||||
}
|
||||
|
||||
TEST_F(MonoScriptRuntimeTest, TransformHierarchyApiExposesParentChildAndReparenting) {
|
||||
Scene* runtimeScene = CreateScene("MonoRuntimeScene");
|
||||
GameObject* root = runtimeScene->CreateGameObject("Root");
|
||||
|
||||
@@ -236,4 +236,34 @@ TEST_F(ScriptEngineTest, DestroyingGameObjectWhileRuntimeRunningDestroysTrackedS
|
||||
EXPECT_EQ(engine->GetTrackedScriptCount(), 0u);
|
||||
}
|
||||
|
||||
TEST_F(ScriptEngineTest, RuntimeCreatedScriptComponentIsTrackedImmediatelyAndStartsOnNextUpdate) {
|
||||
Scene* runtimeScene = CreateScene("RuntimeScene");
|
||||
|
||||
engine->OnRuntimeStart(runtimeScene);
|
||||
runtime.Clear();
|
||||
|
||||
GameObject* spawned = runtimeScene->CreateGameObject("Spawned");
|
||||
ScriptComponent* component = AddScriptComponent(spawned, "Gameplay", "RuntimeSpawned");
|
||||
|
||||
EXPECT_EQ(engine->GetTrackedScriptCount(), 1u);
|
||||
EXPECT_TRUE(engine->HasTrackedScriptComponent(component));
|
||||
EXPECT_TRUE(engine->HasRuntimeInstance(component));
|
||||
|
||||
const std::vector<std::string> expectedBeforeUpdate = {
|
||||
"Create:Spawned:Gameplay.RuntimeSpawned",
|
||||
"Awake:Spawned:Gameplay.RuntimeSpawned",
|
||||
"OnEnable:Spawned:Gameplay.RuntimeSpawned"
|
||||
};
|
||||
EXPECT_EQ(runtime.events, expectedBeforeUpdate);
|
||||
|
||||
runtime.Clear();
|
||||
engine->OnUpdate(0.016f);
|
||||
|
||||
const std::vector<std::string> expectedAfterUpdate = {
|
||||
"Start:Spawned:Gameplay.RuntimeSpawned",
|
||||
"Update:Spawned:Gameplay.RuntimeSpawned"
|
||||
};
|
||||
EXPECT_EQ(runtime.events, expectedAfterUpdate);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Reference in New Issue
Block a user