2026-03-27 13:07:39 +08:00
|
|
|
#include "Scripting/Mono/MonoScriptRuntime.h"
|
|
|
|
|
|
|
|
|
|
#include "Components/CameraComponent.h"
|
|
|
|
|
#include "Components/GameObject.h"
|
|
|
|
|
#include "Components/LightComponent.h"
|
2026-03-27 14:52:00 +08:00
|
|
|
#include "Components/MeshFilterComponent.h"
|
|
|
|
|
#include "Components/MeshRendererComponent.h"
|
2026-03-27 13:07:39 +08:00
|
|
|
#include "Components/TransformComponent.h"
|
|
|
|
|
#include "Debug/Logger.h"
|
|
|
|
|
#include "Scene/Scene.h"
|
|
|
|
|
#include "Scripting/ScriptComponent.h"
|
|
|
|
|
|
|
|
|
|
#include <mono/jit/jit.h>
|
|
|
|
|
#include <mono/metadata/appdomain.h>
|
|
|
|
|
#include <mono/metadata/assembly.h>
|
|
|
|
|
#include <mono/metadata/attrdefs.h>
|
|
|
|
|
#include <mono/metadata/blob.h>
|
|
|
|
|
#include <mono/metadata/class.h>
|
|
|
|
|
#include <mono/metadata/image.h>
|
|
|
|
|
#include <mono/metadata/loader.h>
|
|
|
|
|
#include <mono/metadata/metadata.h>
|
|
|
|
|
#include <mono/metadata/mono-config.h>
|
|
|
|
|
#include <mono/metadata/object.h>
|
|
|
|
|
#include <mono/metadata/reflection.h>
|
|
|
|
|
|
|
|
|
|
#include <algorithm>
|
|
|
|
|
#include <utility>
|
|
|
|
|
|
|
|
|
|
namespace XCEngine {
|
|
|
|
|
namespace Scripting {
|
|
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
|
|
struct MonoRootState {
|
|
|
|
|
MonoDomain* rootDomain = nullptr;
|
|
|
|
|
bool initialized = false;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
enum class ManagedComponentKind {
|
|
|
|
|
Unknown,
|
|
|
|
|
Transform,
|
|
|
|
|
Camera,
|
|
|
|
|
Light,
|
2026-03-27 14:52:00 +08:00
|
|
|
MeshFilter,
|
|
|
|
|
MeshRenderer,
|
2026-03-27 13:07:39 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
MonoRootState& GetMonoRootState() {
|
|
|
|
|
static MonoRootState state;
|
|
|
|
|
return state;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Components::Scene*& GetInternalCallScene() {
|
|
|
|
|
static Components::Scene* scene = nullptr;
|
|
|
|
|
return scene;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float& GetInternalCallDeltaTime() {
|
|
|
|
|
static float deltaTime = 0.0f;
|
|
|
|
|
return deltaTime;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool& GetInternalCallRegistrationState() {
|
|
|
|
|
static bool registered = false;
|
|
|
|
|
return registered;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string BuildFullClassName(const std::string& namespaceName, const std::string& className) {
|
|
|
|
|
return namespaceName.empty() ? className : namespaceName + "." + className;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string BuildClassKey(
|
|
|
|
|
const std::string& assemblyName,
|
|
|
|
|
const std::string& namespaceName,
|
|
|
|
|
const std::string& className) {
|
|
|
|
|
return assemblyName + "|" + BuildFullClassName(namespaceName, className);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string SafeString(const char* value) {
|
|
|
|
|
return value ? std::string(value) : std::string();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string MonoStringToUtf8(MonoString* stringObject) {
|
|
|
|
|
if (!stringObject) {
|
|
|
|
|
return std::string();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
char* utf8 = mono_string_to_utf8(stringObject);
|
|
|
|
|
std::string result = utf8 ? std::string(utf8) : std::string();
|
|
|
|
|
if (utf8) {
|
|
|
|
|
mono_free(utf8);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ManagedComponentKind ResolveManagedComponentKind(MonoReflectionType* reflectionType) {
|
|
|
|
|
if (!reflectionType) {
|
|
|
|
|
return ManagedComponentKind::Unknown;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MonoType* monoType = mono_reflection_type_get_type(reflectionType);
|
|
|
|
|
if (!monoType) {
|
|
|
|
|
return ManagedComponentKind::Unknown;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MonoClass* monoClass = mono_class_from_mono_type(monoType);
|
|
|
|
|
if (!monoClass) {
|
|
|
|
|
return ManagedComponentKind::Unknown;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const std::string namespaceName = SafeString(mono_class_get_namespace(monoClass));
|
|
|
|
|
const std::string className = SafeString(mono_class_get_name(monoClass));
|
|
|
|
|
if (namespaceName == "XCEngine" && className == "Transform") {
|
|
|
|
|
return ManagedComponentKind::Transform;
|
|
|
|
|
}
|
|
|
|
|
if (namespaceName == "XCEngine" && className == "Camera") {
|
|
|
|
|
return ManagedComponentKind::Camera;
|
|
|
|
|
}
|
|
|
|
|
if (namespaceName == "XCEngine" && className == "Light") {
|
|
|
|
|
return ManagedComponentKind::Light;
|
|
|
|
|
}
|
2026-03-27 14:52:00 +08:00
|
|
|
if (namespaceName == "XCEngine" && className == "MeshFilter") {
|
|
|
|
|
return ManagedComponentKind::MeshFilter;
|
|
|
|
|
}
|
|
|
|
|
if (namespaceName == "XCEngine" && className == "MeshRenderer") {
|
|
|
|
|
return ManagedComponentKind::MeshRenderer;
|
|
|
|
|
}
|
2026-03-27 13:07:39 +08:00
|
|
|
|
|
|
|
|
return ManagedComponentKind::Unknown;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Components::GameObject* FindGameObjectByUUIDRecursive(Components::GameObject* gameObject, uint64_t uuid) {
|
|
|
|
|
if (!gameObject) {
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (gameObject->GetUUID() == uuid) {
|
|
|
|
|
return gameObject;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (Components::GameObject* child : gameObject->GetChildren()) {
|
|
|
|
|
if (Components::GameObject* found = FindGameObjectByUUIDRecursive(child, uuid)) {
|
|
|
|
|
return found;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ScriptComponent* FindScriptComponentByUUIDRecursive(Components::GameObject* gameObject, uint64_t scriptComponentUUID) {
|
|
|
|
|
if (!gameObject || scriptComponentUUID == 0) {
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (ScriptComponent* component : gameObject->GetComponents<ScriptComponent>()) {
|
|
|
|
|
if (component && component->GetScriptComponentUUID() == scriptComponentUUID) {
|
|
|
|
|
return component;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (Components::GameObject* child : gameObject->GetChildren()) {
|
|
|
|
|
if (ScriptComponent* found = FindScriptComponentByUUIDRecursive(child, scriptComponentUUID)) {
|
|
|
|
|
return found;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Components::GameObject* FindGameObjectByUUID(uint64_t uuid) {
|
|
|
|
|
Components::Scene* scene = GetInternalCallScene();
|
|
|
|
|
if (!scene || uuid == 0) {
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (Components::GameObject* root : scene->GetRootGameObjects()) {
|
|
|
|
|
if (Components::GameObject* found = FindGameObjectByUUIDRecursive(root, uuid)) {
|
|
|
|
|
return found;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ScriptComponent* FindScriptComponentByUUID(uint64_t scriptComponentUUID) {
|
|
|
|
|
Components::Scene* scene = GetInternalCallScene();
|
|
|
|
|
if (!scene || scriptComponentUUID == 0) {
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (Components::GameObject* root : scene->GetRootGameObjects()) {
|
|
|
|
|
if (ScriptComponent* found = FindScriptComponentByUUIDRecursive(root, scriptComponentUUID)) {
|
|
|
|
|
return found;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool HasNativeComponent(Components::GameObject* gameObject, ManagedComponentKind componentKind) {
|
|
|
|
|
if (!gameObject) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (componentKind) {
|
|
|
|
|
case ManagedComponentKind::Transform:
|
|
|
|
|
return gameObject->GetTransform() != nullptr;
|
|
|
|
|
case ManagedComponentKind::Camera:
|
|
|
|
|
return gameObject->GetComponent<Components::CameraComponent>() != nullptr;
|
|
|
|
|
case ManagedComponentKind::Light:
|
|
|
|
|
return gameObject->GetComponent<Components::LightComponent>() != nullptr;
|
2026-03-27 14:52:00 +08:00
|
|
|
case ManagedComponentKind::MeshFilter:
|
|
|
|
|
return gameObject->GetComponent<Components::MeshFilterComponent>() != nullptr;
|
|
|
|
|
case ManagedComponentKind::MeshRenderer:
|
|
|
|
|
return gameObject->GetComponent<Components::MeshRendererComponent>() != nullptr;
|
2026-03-27 13:07:39 +08:00
|
|
|
case ManagedComponentKind::Unknown:
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Components::CameraComponent* FindCameraComponent(uint64_t gameObjectUUID) {
|
|
|
|
|
Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID);
|
|
|
|
|
return gameObject ? gameObject->GetComponent<Components::CameraComponent>() : nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Components::LightComponent* FindLightComponent(uint64_t gameObjectUUID) {
|
|
|
|
|
Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID);
|
|
|
|
|
return gameObject ? gameObject->GetComponent<Components::LightComponent>() : nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-27 14:52:00 +08:00
|
|
|
Components::MeshFilterComponent* FindMeshFilterComponent(uint64_t gameObjectUUID) {
|
|
|
|
|
Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID);
|
|
|
|
|
return gameObject ? gameObject->GetComponent<Components::MeshFilterComponent>() : nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Components::MeshRendererComponent* FindMeshRendererComponent(uint64_t gameObjectUUID) {
|
|
|
|
|
Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID);
|
|
|
|
|
return gameObject ? gameObject->GetComponent<Components::MeshRendererComponent>() : nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-27 13:07:39 +08:00
|
|
|
Components::Space ResolveManagedSpace(int32_t value) {
|
|
|
|
|
return value == static_cast<int32_t>(Components::Space::World)
|
|
|
|
|
? Components::Space::World
|
|
|
|
|
: Components::Space::Self;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void InternalCall_Debug_Log(MonoString* message) {
|
|
|
|
|
XCEngine::Debug::Logger::Get().Info(
|
|
|
|
|
XCEngine::Debug::LogCategory::Scripting,
|
|
|
|
|
XCEngine::Containers::String(MonoStringToUtf8(message).c_str()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void InternalCall_Debug_LogWarning(MonoString* message) {
|
|
|
|
|
XCEngine::Debug::Logger::Get().Warning(
|
|
|
|
|
XCEngine::Debug::LogCategory::Scripting,
|
|
|
|
|
XCEngine::Containers::String(MonoStringToUtf8(message).c_str()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void InternalCall_Debug_LogError(MonoString* message) {
|
|
|
|
|
XCEngine::Debug::Logger::Get().Error(
|
|
|
|
|
XCEngine::Debug::LogCategory::Scripting,
|
|
|
|
|
XCEngine::Containers::String(MonoStringToUtf8(message).c_str()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float InternalCall_Time_GetDeltaTime() {
|
|
|
|
|
return GetInternalCallDeltaTime();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MonoString* InternalCall_GameObject_GetName(uint64_t gameObjectUUID) {
|
|
|
|
|
Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID);
|
|
|
|
|
return mono_string_new(
|
|
|
|
|
mono_domain_get(),
|
|
|
|
|
gameObject ? gameObject->GetName().c_str() : "");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void InternalCall_GameObject_SetName(uint64_t gameObjectUUID, MonoString* name) {
|
|
|
|
|
Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID);
|
|
|
|
|
if (!gameObject) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gameObject->SetName(MonoStringToUtf8(name));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mono_bool InternalCall_GameObject_GetActiveSelf(uint64_t gameObjectUUID) {
|
|
|
|
|
Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID);
|
|
|
|
|
return (gameObject && gameObject->IsActive()) ? 1 : 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mono_bool InternalCall_GameObject_GetActiveInHierarchy(uint64_t gameObjectUUID) {
|
|
|
|
|
Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID);
|
|
|
|
|
return (gameObject && gameObject->IsActiveInHierarchy()) ? 1 : 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void InternalCall_GameObject_SetActive(uint64_t gameObjectUUID, mono_bool active) {
|
|
|
|
|
Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID);
|
|
|
|
|
if (!gameObject) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gameObject->SetActive(active != 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mono_bool InternalCall_GameObject_HasComponent(uint64_t gameObjectUUID, MonoReflectionType* componentType) {
|
|
|
|
|
Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID);
|
|
|
|
|
return HasNativeComponent(gameObject, ResolveManagedComponentKind(componentType)) ? 1 : 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint64_t InternalCall_GameObject_GetComponent(uint64_t gameObjectUUID, MonoReflectionType* componentType) {
|
|
|
|
|
Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID);
|
|
|
|
|
if (!HasNativeComponent(gameObject, ResolveManagedComponentKind(componentType))) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return gameObjectUUID;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mono_bool InternalCall_Behaviour_GetEnabled(uint64_t scriptComponentUUID) {
|
|
|
|
|
ScriptComponent* component = FindScriptComponentByUUID(scriptComponentUUID);
|
|
|
|
|
return (component && component->IsEnabled()) ? 1 : 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void InternalCall_Behaviour_SetEnabled(uint64_t scriptComponentUUID, mono_bool enabled) {
|
|
|
|
|
ScriptComponent* component = FindScriptComponentByUUID(scriptComponentUUID);
|
|
|
|
|
if (!component) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
component->SetEnabled(enabled != 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void InternalCall_Transform_GetLocalPosition(uint64_t gameObjectUUID, XCEngine::Math::Vector3* outPosition) {
|
|
|
|
|
if (!outPosition) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID);
|
|
|
|
|
if (!gameObject || !gameObject->GetTransform()) {
|
|
|
|
|
*outPosition = XCEngine::Math::Vector3::Zero();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*outPosition = gameObject->GetTransform()->GetLocalPosition();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void InternalCall_Transform_SetLocalPosition(uint64_t gameObjectUUID, XCEngine::Math::Vector3* position) {
|
|
|
|
|
if (!position) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID);
|
|
|
|
|
if (!gameObject || !gameObject->GetTransform()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gameObject->GetTransform()->SetLocalPosition(*position);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void InternalCall_Transform_GetLocalRotation(uint64_t gameObjectUUID, XCEngine::Math::Quaternion* outRotation) {
|
|
|
|
|
if (!outRotation) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID);
|
|
|
|
|
if (!gameObject || !gameObject->GetTransform()) {
|
|
|
|
|
*outRotation = XCEngine::Math::Quaternion::Identity();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*outRotation = gameObject->GetTransform()->GetLocalRotation();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void InternalCall_Transform_SetLocalRotation(uint64_t gameObjectUUID, XCEngine::Math::Quaternion* rotation) {
|
|
|
|
|
if (!rotation) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID);
|
|
|
|
|
if (!gameObject || !gameObject->GetTransform()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gameObject->GetTransform()->SetLocalRotation(*rotation);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void InternalCall_Transform_GetLocalScale(uint64_t gameObjectUUID, XCEngine::Math::Vector3* outScale) {
|
|
|
|
|
if (!outScale) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID);
|
|
|
|
|
if (!gameObject || !gameObject->GetTransform()) {
|
|
|
|
|
*outScale = XCEngine::Math::Vector3::One();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*outScale = gameObject->GetTransform()->GetLocalScale();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void InternalCall_Transform_SetLocalScale(uint64_t gameObjectUUID, XCEngine::Math::Vector3* scale) {
|
|
|
|
|
if (!scale) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID);
|
|
|
|
|
if (!gameObject || !gameObject->GetTransform()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gameObject->GetTransform()->SetLocalScale(*scale);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void InternalCall_Transform_GetLocalEulerAngles(uint64_t gameObjectUUID, XCEngine::Math::Vector3* outEulerAngles) {
|
|
|
|
|
if (!outEulerAngles) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID);
|
|
|
|
|
if (!gameObject || !gameObject->GetTransform()) {
|
|
|
|
|
*outEulerAngles = XCEngine::Math::Vector3::Zero();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*outEulerAngles = gameObject->GetTransform()->GetLocalEulerAngles();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void InternalCall_Transform_SetLocalEulerAngles(uint64_t gameObjectUUID, XCEngine::Math::Vector3* eulerAngles) {
|
|
|
|
|
if (!eulerAngles) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID);
|
|
|
|
|
if (!gameObject || !gameObject->GetTransform()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gameObject->GetTransform()->SetLocalEulerAngles(*eulerAngles);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void InternalCall_Transform_GetPosition(uint64_t gameObjectUUID, XCEngine::Math::Vector3* outPosition) {
|
|
|
|
|
if (!outPosition) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID);
|
|
|
|
|
if (!gameObject || !gameObject->GetTransform()) {
|
|
|
|
|
*outPosition = XCEngine::Math::Vector3::Zero();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*outPosition = gameObject->GetTransform()->GetPosition();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void InternalCall_Transform_SetPosition(uint64_t gameObjectUUID, XCEngine::Math::Vector3* position) {
|
|
|
|
|
if (!position) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID);
|
|
|
|
|
if (!gameObject || !gameObject->GetTransform()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gameObject->GetTransform()->SetPosition(*position);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void InternalCall_Transform_GetRotation(uint64_t gameObjectUUID, XCEngine::Math::Quaternion* outRotation) {
|
|
|
|
|
if (!outRotation) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID);
|
|
|
|
|
if (!gameObject || !gameObject->GetTransform()) {
|
|
|
|
|
*outRotation = XCEngine::Math::Quaternion::Identity();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*outRotation = gameObject->GetTransform()->GetRotation();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void InternalCall_Transform_SetRotation(uint64_t gameObjectUUID, XCEngine::Math::Quaternion* rotation) {
|
|
|
|
|
if (!rotation) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID);
|
|
|
|
|
if (!gameObject || !gameObject->GetTransform()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gameObject->GetTransform()->SetRotation(*rotation);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void InternalCall_Transform_GetScale(uint64_t gameObjectUUID, XCEngine::Math::Vector3* outScale) {
|
|
|
|
|
if (!outScale) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID);
|
|
|
|
|
if (!gameObject || !gameObject->GetTransform()) {
|
|
|
|
|
*outScale = XCEngine::Math::Vector3::One();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*outScale = gameObject->GetTransform()->GetScale();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void InternalCall_Transform_SetScale(uint64_t gameObjectUUID, XCEngine::Math::Vector3* scale) {
|
|
|
|
|
if (!scale) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID);
|
|
|
|
|
if (!gameObject || !gameObject->GetTransform()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gameObject->GetTransform()->SetScale(*scale);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void InternalCall_Transform_GetForward(uint64_t gameObjectUUID, XCEngine::Math::Vector3* outForward) {
|
|
|
|
|
if (!outForward) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID);
|
|
|
|
|
if (!gameObject || !gameObject->GetTransform()) {
|
|
|
|
|
*outForward = XCEngine::Math::Vector3::Forward();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*outForward = gameObject->GetTransform()->GetForward();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void InternalCall_Transform_GetRight(uint64_t gameObjectUUID, XCEngine::Math::Vector3* outRight) {
|
|
|
|
|
if (!outRight) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID);
|
|
|
|
|
if (!gameObject || !gameObject->GetTransform()) {
|
|
|
|
|
*outRight = XCEngine::Math::Vector3::Right();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*outRight = gameObject->GetTransform()->GetRight();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void InternalCall_Transform_GetUp(uint64_t gameObjectUUID, XCEngine::Math::Vector3* outUp) {
|
|
|
|
|
if (!outUp) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID);
|
|
|
|
|
if (!gameObject || !gameObject->GetTransform()) {
|
|
|
|
|
*outUp = XCEngine::Math::Vector3::Up();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*outUp = gameObject->GetTransform()->GetUp();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void InternalCall_Transform_Translate(uint64_t gameObjectUUID, XCEngine::Math::Vector3* translation, int32_t relativeTo) {
|
|
|
|
|
if (!translation) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID);
|
|
|
|
|
if (!gameObject || !gameObject->GetTransform()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gameObject->GetTransform()->Translate(*translation, ResolveManagedSpace(relativeTo));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void InternalCall_Transform_Rotate(uint64_t gameObjectUUID, XCEngine::Math::Vector3* eulers, int32_t relativeTo) {
|
|
|
|
|
if (!eulers) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID);
|
|
|
|
|
if (!gameObject || !gameObject->GetTransform()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gameObject->GetTransform()->Rotate(*eulers, ResolveManagedSpace(relativeTo));
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-27 14:39:19 +08:00
|
|
|
void InternalCall_Transform_RotateAxisAngle(
|
|
|
|
|
uint64_t gameObjectUUID,
|
|
|
|
|
XCEngine::Math::Vector3* axis,
|
|
|
|
|
float angle,
|
|
|
|
|
int32_t relativeTo) {
|
|
|
|
|
if (!axis) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID);
|
|
|
|
|
if (!gameObject || !gameObject->GetTransform()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gameObject->GetTransform()->Rotate(*axis, angle, ResolveManagedSpace(relativeTo));
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-27 13:07:39 +08:00
|
|
|
void InternalCall_Transform_LookAt(uint64_t gameObjectUUID, XCEngine::Math::Vector3* target) {
|
|
|
|
|
if (!target) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID);
|
|
|
|
|
if (!gameObject || !gameObject->GetTransform()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gameObject->GetTransform()->LookAt(*target);
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-27 14:39:19 +08:00
|
|
|
void InternalCall_Transform_LookAtWithUp(
|
|
|
|
|
uint64_t gameObjectUUID,
|
|
|
|
|
XCEngine::Math::Vector3* target,
|
|
|
|
|
XCEngine::Math::Vector3* up) {
|
|
|
|
|
if (!target || !up) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID);
|
|
|
|
|
if (!gameObject || !gameObject->GetTransform()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gameObject->GetTransform()->LookAt(*target, *up);
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-27 13:07:39 +08:00
|
|
|
void InternalCall_Transform_TransformPoint(uint64_t gameObjectUUID, XCEngine::Math::Vector3* point, XCEngine::Math::Vector3* outPoint) {
|
|
|
|
|
if (!point || !outPoint) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID);
|
|
|
|
|
if (!gameObject || !gameObject->GetTransform()) {
|
|
|
|
|
*outPoint = *point;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*outPoint = gameObject->GetTransform()->TransformPoint(*point);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void InternalCall_Transform_InverseTransformPoint(uint64_t gameObjectUUID, XCEngine::Math::Vector3* point, XCEngine::Math::Vector3* outPoint) {
|
|
|
|
|
if (!point || !outPoint) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID);
|
|
|
|
|
if (!gameObject || !gameObject->GetTransform()) {
|
|
|
|
|
*outPoint = *point;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*outPoint = gameObject->GetTransform()->InverseTransformPoint(*point);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void InternalCall_Transform_TransformDirection(uint64_t gameObjectUUID, XCEngine::Math::Vector3* direction, XCEngine::Math::Vector3* outDirection) {
|
|
|
|
|
if (!direction || !outDirection) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID);
|
|
|
|
|
if (!gameObject || !gameObject->GetTransform()) {
|
|
|
|
|
*outDirection = *direction;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*outDirection = gameObject->GetTransform()->TransformDirection(*direction);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void InternalCall_Transform_InverseTransformDirection(uint64_t gameObjectUUID, XCEngine::Math::Vector3* direction, XCEngine::Math::Vector3* outDirection) {
|
|
|
|
|
if (!direction || !outDirection) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID);
|
|
|
|
|
if (!gameObject || !gameObject->GetTransform()) {
|
|
|
|
|
*outDirection = *direction;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*outDirection = gameObject->GetTransform()->InverseTransformDirection(*direction);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint64_t InternalCall_Transform_GetParent(uint64_t gameObjectUUID) {
|
|
|
|
|
Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID);
|
|
|
|
|
if (!gameObject || !gameObject->GetParent()) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return gameObject->GetParent()->GetUUID();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void InternalCall_Transform_SetParent(uint64_t gameObjectUUID, uint64_t parentGameObjectUUID, mono_bool worldPositionStays) {
|
|
|
|
|
Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID);
|
|
|
|
|
if (!gameObject) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Components::GameObject* parent = parentGameObjectUUID != 0 ? FindGameObjectByUUID(parentGameObjectUUID) : nullptr;
|
|
|
|
|
gameObject->SetParent(parent, worldPositionStays != 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int32_t InternalCall_Transform_GetChildCount(uint64_t gameObjectUUID) {
|
|
|
|
|
Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID);
|
|
|
|
|
return gameObject ? static_cast<int32_t>(gameObject->GetChildCount()) : 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint64_t InternalCall_Transform_GetChild(uint64_t gameObjectUUID, int32_t index) {
|
|
|
|
|
Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID);
|
|
|
|
|
if (!gameObject || index < 0) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Components::GameObject* child = gameObject->GetChild(static_cast<size_t>(index));
|
|
|
|
|
return child ? child->GetUUID() : 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float InternalCall_Camera_GetFieldOfView(uint64_t gameObjectUUID) {
|
|
|
|
|
Components::CameraComponent* component = FindCameraComponent(gameObjectUUID);
|
|
|
|
|
return component ? component->GetFieldOfView() : 0.0f;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void InternalCall_Camera_SetFieldOfView(uint64_t gameObjectUUID, float value) {
|
|
|
|
|
Components::CameraComponent* component = FindCameraComponent(gameObjectUUID);
|
|
|
|
|
if (!component) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
component->SetFieldOfView(value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float InternalCall_Camera_GetNearClipPlane(uint64_t gameObjectUUID) {
|
|
|
|
|
Components::CameraComponent* component = FindCameraComponent(gameObjectUUID);
|
|
|
|
|
return component ? component->GetNearClipPlane() : 0.0f;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void InternalCall_Camera_SetNearClipPlane(uint64_t gameObjectUUID, float value) {
|
|
|
|
|
Components::CameraComponent* component = FindCameraComponent(gameObjectUUID);
|
|
|
|
|
if (!component) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
component->SetNearClipPlane(value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float InternalCall_Camera_GetFarClipPlane(uint64_t gameObjectUUID) {
|
|
|
|
|
Components::CameraComponent* component = FindCameraComponent(gameObjectUUID);
|
|
|
|
|
return component ? component->GetFarClipPlane() : 0.0f;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void InternalCall_Camera_SetFarClipPlane(uint64_t gameObjectUUID, float value) {
|
|
|
|
|
Components::CameraComponent* component = FindCameraComponent(gameObjectUUID);
|
|
|
|
|
if (!component) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
component->SetFarClipPlane(value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float InternalCall_Camera_GetDepth(uint64_t gameObjectUUID) {
|
|
|
|
|
Components::CameraComponent* component = FindCameraComponent(gameObjectUUID);
|
|
|
|
|
return component ? component->GetDepth() : 0.0f;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void InternalCall_Camera_SetDepth(uint64_t gameObjectUUID, float value) {
|
|
|
|
|
Components::CameraComponent* component = FindCameraComponent(gameObjectUUID);
|
|
|
|
|
if (!component) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
component->SetDepth(value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mono_bool InternalCall_Camera_GetPrimary(uint64_t gameObjectUUID) {
|
|
|
|
|
Components::CameraComponent* component = FindCameraComponent(gameObjectUUID);
|
|
|
|
|
return (component && component->IsPrimary()) ? 1 : 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void InternalCall_Camera_SetPrimary(uint64_t gameObjectUUID, mono_bool value) {
|
|
|
|
|
Components::CameraComponent* component = FindCameraComponent(gameObjectUUID);
|
|
|
|
|
if (!component) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
component->SetPrimary(value != 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float InternalCall_Light_GetIntensity(uint64_t gameObjectUUID) {
|
|
|
|
|
Components::LightComponent* component = FindLightComponent(gameObjectUUID);
|
|
|
|
|
return component ? component->GetIntensity() : 0.0f;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void InternalCall_Light_SetIntensity(uint64_t gameObjectUUID, float value) {
|
|
|
|
|
Components::LightComponent* component = FindLightComponent(gameObjectUUID);
|
|
|
|
|
if (!component) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
component->SetIntensity(value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float InternalCall_Light_GetRange(uint64_t gameObjectUUID) {
|
|
|
|
|
Components::LightComponent* component = FindLightComponent(gameObjectUUID);
|
|
|
|
|
return component ? component->GetRange() : 0.0f;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void InternalCall_Light_SetRange(uint64_t gameObjectUUID, float value) {
|
|
|
|
|
Components::LightComponent* component = FindLightComponent(gameObjectUUID);
|
|
|
|
|
if (!component) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
component->SetRange(value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float InternalCall_Light_GetSpotAngle(uint64_t gameObjectUUID) {
|
|
|
|
|
Components::LightComponent* component = FindLightComponent(gameObjectUUID);
|
|
|
|
|
return component ? component->GetSpotAngle() : 0.0f;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void InternalCall_Light_SetSpotAngle(uint64_t gameObjectUUID, float value) {
|
|
|
|
|
Components::LightComponent* component = FindLightComponent(gameObjectUUID);
|
|
|
|
|
if (!component) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
component->SetSpotAngle(value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mono_bool InternalCall_Light_GetCastsShadows(uint64_t gameObjectUUID) {
|
|
|
|
|
Components::LightComponent* component = FindLightComponent(gameObjectUUID);
|
|
|
|
|
return (component && component->GetCastsShadows()) ? 1 : 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void InternalCall_Light_SetCastsShadows(uint64_t gameObjectUUID, mono_bool value) {
|
|
|
|
|
Components::LightComponent* component = FindLightComponent(gameObjectUUID);
|
|
|
|
|
if (!component) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
component->SetCastsShadows(value != 0);
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-27 14:52:00 +08:00
|
|
|
MonoString* InternalCall_MeshFilter_GetMeshPath(uint64_t gameObjectUUID) {
|
|
|
|
|
Components::MeshFilterComponent* component = FindMeshFilterComponent(gameObjectUUID);
|
|
|
|
|
return mono_string_new(
|
|
|
|
|
mono_domain_get(),
|
|
|
|
|
component ? component->GetMeshPath().c_str() : "");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void InternalCall_MeshFilter_SetMeshPath(uint64_t gameObjectUUID, MonoString* path) {
|
|
|
|
|
Components::MeshFilterComponent* component = FindMeshFilterComponent(gameObjectUUID);
|
|
|
|
|
if (!component) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
component->SetMeshPath(MonoStringToUtf8(path));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int32_t InternalCall_MeshRenderer_GetMaterialCount(uint64_t gameObjectUUID) {
|
|
|
|
|
Components::MeshRendererComponent* component = FindMeshRendererComponent(gameObjectUUID);
|
|
|
|
|
return component ? static_cast<int32_t>(component->GetMaterialCount()) : 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MonoString* InternalCall_MeshRenderer_GetMaterialPath(uint64_t gameObjectUUID, int32_t index) {
|
|
|
|
|
Components::MeshRendererComponent* component = FindMeshRendererComponent(gameObjectUUID);
|
|
|
|
|
const std::string path =
|
|
|
|
|
(component && index >= 0) ? component->GetMaterialPath(static_cast<size_t>(index)) : std::string();
|
|
|
|
|
return mono_string_new(mono_domain_get(), path.c_str());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void InternalCall_MeshRenderer_SetMaterialPath(uint64_t gameObjectUUID, int32_t index, MonoString* path) {
|
|
|
|
|
Components::MeshRendererComponent* component = FindMeshRendererComponent(gameObjectUUID);
|
|
|
|
|
if (!component || index < 0) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
component->SetMaterialPath(static_cast<size_t>(index), MonoStringToUtf8(path));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void InternalCall_MeshRenderer_ClearMaterials(uint64_t gameObjectUUID) {
|
|
|
|
|
Components::MeshRendererComponent* component = FindMeshRendererComponent(gameObjectUUID);
|
|
|
|
|
if (!component) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
component->ClearMaterials();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mono_bool InternalCall_MeshRenderer_GetCastShadows(uint64_t gameObjectUUID) {
|
|
|
|
|
Components::MeshRendererComponent* component = FindMeshRendererComponent(gameObjectUUID);
|
|
|
|
|
return (component && component->GetCastShadows()) ? 1 : 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void InternalCall_MeshRenderer_SetCastShadows(uint64_t gameObjectUUID, mono_bool value) {
|
|
|
|
|
Components::MeshRendererComponent* component = FindMeshRendererComponent(gameObjectUUID);
|
|
|
|
|
if (!component) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
component->SetCastShadows(value != 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mono_bool InternalCall_MeshRenderer_GetReceiveShadows(uint64_t gameObjectUUID) {
|
|
|
|
|
Components::MeshRendererComponent* component = FindMeshRendererComponent(gameObjectUUID);
|
|
|
|
|
return (component && component->GetReceiveShadows()) ? 1 : 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void InternalCall_MeshRenderer_SetReceiveShadows(uint64_t gameObjectUUID, mono_bool value) {
|
|
|
|
|
Components::MeshRendererComponent* component = FindMeshRendererComponent(gameObjectUUID);
|
|
|
|
|
if (!component) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
component->SetReceiveShadows(value != 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int32_t InternalCall_MeshRenderer_GetRenderLayer(uint64_t gameObjectUUID) {
|
|
|
|
|
Components::MeshRendererComponent* component = FindMeshRendererComponent(gameObjectUUID);
|
|
|
|
|
return component ? static_cast<int32_t>(component->GetRenderLayer()) : 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void InternalCall_MeshRenderer_SetRenderLayer(uint64_t gameObjectUUID, int32_t value) {
|
|
|
|
|
Components::MeshRendererComponent* component = FindMeshRendererComponent(gameObjectUUID);
|
|
|
|
|
if (!component) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
component->SetRenderLayer(static_cast<uint32_t>(std::max(value, 0)));
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-27 13:07:39 +08:00
|
|
|
void RegisterInternalCalls() {
|
|
|
|
|
if (GetInternalCallRegistrationState()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mono_add_internal_call("XCEngine.InternalCalls::Debug_Log", reinterpret_cast<const void*>(&InternalCall_Debug_Log));
|
|
|
|
|
mono_add_internal_call("XCEngine.InternalCalls::Debug_LogWarning", reinterpret_cast<const void*>(&InternalCall_Debug_LogWarning));
|
|
|
|
|
mono_add_internal_call("XCEngine.InternalCalls::Debug_LogError", reinterpret_cast<const void*>(&InternalCall_Debug_LogError));
|
|
|
|
|
mono_add_internal_call("XCEngine.InternalCalls::Time_GetDeltaTime", reinterpret_cast<const void*>(&InternalCall_Time_GetDeltaTime));
|
|
|
|
|
mono_add_internal_call("XCEngine.InternalCalls::GameObject_GetName", reinterpret_cast<const void*>(&InternalCall_GameObject_GetName));
|
|
|
|
|
mono_add_internal_call("XCEngine.InternalCalls::GameObject_SetName", reinterpret_cast<const void*>(&InternalCall_GameObject_SetName));
|
|
|
|
|
mono_add_internal_call("XCEngine.InternalCalls::GameObject_GetActiveSelf", reinterpret_cast<const void*>(&InternalCall_GameObject_GetActiveSelf));
|
|
|
|
|
mono_add_internal_call("XCEngine.InternalCalls::GameObject_GetActiveInHierarchy", reinterpret_cast<const void*>(&InternalCall_GameObject_GetActiveInHierarchy));
|
|
|
|
|
mono_add_internal_call("XCEngine.InternalCalls::GameObject_SetActive", reinterpret_cast<const void*>(&InternalCall_GameObject_SetActive));
|
|
|
|
|
mono_add_internal_call("XCEngine.InternalCalls::GameObject_HasComponent", reinterpret_cast<const void*>(&InternalCall_GameObject_HasComponent));
|
|
|
|
|
mono_add_internal_call("XCEngine.InternalCalls::GameObject_GetComponent", reinterpret_cast<const void*>(&InternalCall_GameObject_GetComponent));
|
|
|
|
|
mono_add_internal_call("XCEngine.InternalCalls::Behaviour_GetEnabled", reinterpret_cast<const void*>(&InternalCall_Behaviour_GetEnabled));
|
|
|
|
|
mono_add_internal_call("XCEngine.InternalCalls::Behaviour_SetEnabled", reinterpret_cast<const void*>(&InternalCall_Behaviour_SetEnabled));
|
|
|
|
|
mono_add_internal_call("XCEngine.InternalCalls::Transform_GetLocalPosition", reinterpret_cast<const void*>(&InternalCall_Transform_GetLocalPosition));
|
|
|
|
|
mono_add_internal_call("XCEngine.InternalCalls::Transform_SetLocalPosition", reinterpret_cast<const void*>(&InternalCall_Transform_SetLocalPosition));
|
|
|
|
|
mono_add_internal_call("XCEngine.InternalCalls::Transform_GetLocalRotation", reinterpret_cast<const void*>(&InternalCall_Transform_GetLocalRotation));
|
|
|
|
|
mono_add_internal_call("XCEngine.InternalCalls::Transform_SetLocalRotation", reinterpret_cast<const void*>(&InternalCall_Transform_SetLocalRotation));
|
|
|
|
|
mono_add_internal_call("XCEngine.InternalCalls::Transform_GetLocalScale", reinterpret_cast<const void*>(&InternalCall_Transform_GetLocalScale));
|
|
|
|
|
mono_add_internal_call("XCEngine.InternalCalls::Transform_SetLocalScale", reinterpret_cast<const void*>(&InternalCall_Transform_SetLocalScale));
|
|
|
|
|
mono_add_internal_call("XCEngine.InternalCalls::Transform_GetLocalEulerAngles", reinterpret_cast<const void*>(&InternalCall_Transform_GetLocalEulerAngles));
|
|
|
|
|
mono_add_internal_call("XCEngine.InternalCalls::Transform_SetLocalEulerAngles", reinterpret_cast<const void*>(&InternalCall_Transform_SetLocalEulerAngles));
|
|
|
|
|
mono_add_internal_call("XCEngine.InternalCalls::Transform_GetPosition", reinterpret_cast<const void*>(&InternalCall_Transform_GetPosition));
|
|
|
|
|
mono_add_internal_call("XCEngine.InternalCalls::Transform_SetPosition", reinterpret_cast<const void*>(&InternalCall_Transform_SetPosition));
|
|
|
|
|
mono_add_internal_call("XCEngine.InternalCalls::Transform_GetRotation", reinterpret_cast<const void*>(&InternalCall_Transform_GetRotation));
|
|
|
|
|
mono_add_internal_call("XCEngine.InternalCalls::Transform_SetRotation", reinterpret_cast<const void*>(&InternalCall_Transform_SetRotation));
|
|
|
|
|
mono_add_internal_call("XCEngine.InternalCalls::Transform_GetScale", reinterpret_cast<const void*>(&InternalCall_Transform_GetScale));
|
|
|
|
|
mono_add_internal_call("XCEngine.InternalCalls::Transform_SetScale", reinterpret_cast<const void*>(&InternalCall_Transform_SetScale));
|
|
|
|
|
mono_add_internal_call("XCEngine.InternalCalls::Transform_GetForward", reinterpret_cast<const void*>(&InternalCall_Transform_GetForward));
|
|
|
|
|
mono_add_internal_call("XCEngine.InternalCalls::Transform_GetRight", reinterpret_cast<const void*>(&InternalCall_Transform_GetRight));
|
|
|
|
|
mono_add_internal_call("XCEngine.InternalCalls::Transform_GetUp", reinterpret_cast<const void*>(&InternalCall_Transform_GetUp));
|
|
|
|
|
mono_add_internal_call("XCEngine.InternalCalls::Transform_Translate", reinterpret_cast<const void*>(&InternalCall_Transform_Translate));
|
|
|
|
|
mono_add_internal_call("XCEngine.InternalCalls::Transform_Rotate", reinterpret_cast<const void*>(&InternalCall_Transform_Rotate));
|
2026-03-27 14:39:19 +08:00
|
|
|
mono_add_internal_call("XCEngine.InternalCalls::Transform_RotateAxisAngle", reinterpret_cast<const void*>(&InternalCall_Transform_RotateAxisAngle));
|
2026-03-27 13:07:39 +08:00
|
|
|
mono_add_internal_call("XCEngine.InternalCalls::Transform_LookAt", reinterpret_cast<const void*>(&InternalCall_Transform_LookAt));
|
2026-03-27 14:39:19 +08:00
|
|
|
mono_add_internal_call("XCEngine.InternalCalls::Transform_LookAtWithUp", reinterpret_cast<const void*>(&InternalCall_Transform_LookAtWithUp));
|
2026-03-27 13:07:39 +08:00
|
|
|
mono_add_internal_call("XCEngine.InternalCalls::Transform_TransformPoint", reinterpret_cast<const void*>(&InternalCall_Transform_TransformPoint));
|
|
|
|
|
mono_add_internal_call("XCEngine.InternalCalls::Transform_InverseTransformPoint", reinterpret_cast<const void*>(&InternalCall_Transform_InverseTransformPoint));
|
|
|
|
|
mono_add_internal_call("XCEngine.InternalCalls::Transform_TransformDirection", reinterpret_cast<const void*>(&InternalCall_Transform_TransformDirection));
|
|
|
|
|
mono_add_internal_call("XCEngine.InternalCalls::Transform_InverseTransformDirection", reinterpret_cast<const void*>(&InternalCall_Transform_InverseTransformDirection));
|
|
|
|
|
mono_add_internal_call("XCEngine.InternalCalls::Transform_GetParent", reinterpret_cast<const void*>(&InternalCall_Transform_GetParent));
|
|
|
|
|
mono_add_internal_call("XCEngine.InternalCalls::Transform_SetParent", reinterpret_cast<const void*>(&InternalCall_Transform_SetParent));
|
|
|
|
|
mono_add_internal_call("XCEngine.InternalCalls::Transform_GetChildCount", reinterpret_cast<const void*>(&InternalCall_Transform_GetChildCount));
|
|
|
|
|
mono_add_internal_call("XCEngine.InternalCalls::Transform_GetChild", reinterpret_cast<const void*>(&InternalCall_Transform_GetChild));
|
|
|
|
|
mono_add_internal_call("XCEngine.InternalCalls::Camera_GetFieldOfView", reinterpret_cast<const void*>(&InternalCall_Camera_GetFieldOfView));
|
|
|
|
|
mono_add_internal_call("XCEngine.InternalCalls::Camera_SetFieldOfView", reinterpret_cast<const void*>(&InternalCall_Camera_SetFieldOfView));
|
|
|
|
|
mono_add_internal_call("XCEngine.InternalCalls::Camera_GetNearClipPlane", reinterpret_cast<const void*>(&InternalCall_Camera_GetNearClipPlane));
|
|
|
|
|
mono_add_internal_call("XCEngine.InternalCalls::Camera_SetNearClipPlane", reinterpret_cast<const void*>(&InternalCall_Camera_SetNearClipPlane));
|
|
|
|
|
mono_add_internal_call("XCEngine.InternalCalls::Camera_GetFarClipPlane", reinterpret_cast<const void*>(&InternalCall_Camera_GetFarClipPlane));
|
|
|
|
|
mono_add_internal_call("XCEngine.InternalCalls::Camera_SetFarClipPlane", reinterpret_cast<const void*>(&InternalCall_Camera_SetFarClipPlane));
|
|
|
|
|
mono_add_internal_call("XCEngine.InternalCalls::Camera_GetDepth", reinterpret_cast<const void*>(&InternalCall_Camera_GetDepth));
|
|
|
|
|
mono_add_internal_call("XCEngine.InternalCalls::Camera_SetDepth", reinterpret_cast<const void*>(&InternalCall_Camera_SetDepth));
|
|
|
|
|
mono_add_internal_call("XCEngine.InternalCalls::Camera_GetPrimary", reinterpret_cast<const void*>(&InternalCall_Camera_GetPrimary));
|
|
|
|
|
mono_add_internal_call("XCEngine.InternalCalls::Camera_SetPrimary", reinterpret_cast<const void*>(&InternalCall_Camera_SetPrimary));
|
|
|
|
|
mono_add_internal_call("XCEngine.InternalCalls::Light_GetIntensity", reinterpret_cast<const void*>(&InternalCall_Light_GetIntensity));
|
|
|
|
|
mono_add_internal_call("XCEngine.InternalCalls::Light_SetIntensity", reinterpret_cast<const void*>(&InternalCall_Light_SetIntensity));
|
|
|
|
|
mono_add_internal_call("XCEngine.InternalCalls::Light_GetRange", reinterpret_cast<const void*>(&InternalCall_Light_GetRange));
|
|
|
|
|
mono_add_internal_call("XCEngine.InternalCalls::Light_SetRange", reinterpret_cast<const void*>(&InternalCall_Light_SetRange));
|
|
|
|
|
mono_add_internal_call("XCEngine.InternalCalls::Light_GetSpotAngle", reinterpret_cast<const void*>(&InternalCall_Light_GetSpotAngle));
|
|
|
|
|
mono_add_internal_call("XCEngine.InternalCalls::Light_SetSpotAngle", reinterpret_cast<const void*>(&InternalCall_Light_SetSpotAngle));
|
|
|
|
|
mono_add_internal_call("XCEngine.InternalCalls::Light_GetCastsShadows", reinterpret_cast<const void*>(&InternalCall_Light_GetCastsShadows));
|
|
|
|
|
mono_add_internal_call("XCEngine.InternalCalls::Light_SetCastsShadows", reinterpret_cast<const void*>(&InternalCall_Light_SetCastsShadows));
|
2026-03-27 14:52:00 +08:00
|
|
|
mono_add_internal_call("XCEngine.InternalCalls::MeshFilter_GetMeshPath", reinterpret_cast<const void*>(&InternalCall_MeshFilter_GetMeshPath));
|
|
|
|
|
mono_add_internal_call("XCEngine.InternalCalls::MeshFilter_SetMeshPath", reinterpret_cast<const void*>(&InternalCall_MeshFilter_SetMeshPath));
|
|
|
|
|
mono_add_internal_call("XCEngine.InternalCalls::MeshRenderer_GetMaterialCount", reinterpret_cast<const void*>(&InternalCall_MeshRenderer_GetMaterialCount));
|
|
|
|
|
mono_add_internal_call("XCEngine.InternalCalls::MeshRenderer_GetMaterialPath", reinterpret_cast<const void*>(&InternalCall_MeshRenderer_GetMaterialPath));
|
|
|
|
|
mono_add_internal_call("XCEngine.InternalCalls::MeshRenderer_SetMaterialPath", reinterpret_cast<const void*>(&InternalCall_MeshRenderer_SetMaterialPath));
|
|
|
|
|
mono_add_internal_call("XCEngine.InternalCalls::MeshRenderer_ClearMaterials", reinterpret_cast<const void*>(&InternalCall_MeshRenderer_ClearMaterials));
|
|
|
|
|
mono_add_internal_call("XCEngine.InternalCalls::MeshRenderer_GetCastShadows", reinterpret_cast<const void*>(&InternalCall_MeshRenderer_GetCastShadows));
|
|
|
|
|
mono_add_internal_call("XCEngine.InternalCalls::MeshRenderer_SetCastShadows", reinterpret_cast<const void*>(&InternalCall_MeshRenderer_SetCastShadows));
|
|
|
|
|
mono_add_internal_call("XCEngine.InternalCalls::MeshRenderer_GetReceiveShadows", reinterpret_cast<const void*>(&InternalCall_MeshRenderer_GetReceiveShadows));
|
|
|
|
|
mono_add_internal_call("XCEngine.InternalCalls::MeshRenderer_SetReceiveShadows", reinterpret_cast<const void*>(&InternalCall_MeshRenderer_SetReceiveShadows));
|
|
|
|
|
mono_add_internal_call("XCEngine.InternalCalls::MeshRenderer_GetRenderLayer", reinterpret_cast<const void*>(&InternalCall_MeshRenderer_GetRenderLayer));
|
|
|
|
|
mono_add_internal_call("XCEngine.InternalCalls::MeshRenderer_SetRenderLayer", reinterpret_cast<const void*>(&InternalCall_MeshRenderer_SetRenderLayer));
|
2026-03-27 13:07:39 +08:00
|
|
|
|
|
|
|
|
GetInternalCallRegistrationState() = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
|
|
MonoScriptRuntime::MonoScriptRuntime(Settings settings)
|
|
|
|
|
: m_settings(std::move(settings)) {
|
|
|
|
|
ResolveSettings();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MonoScriptRuntime::~MonoScriptRuntime() {
|
|
|
|
|
Shutdown();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool MonoScriptRuntime::Initialize() {
|
|
|
|
|
ResolveSettings();
|
|
|
|
|
m_lastError.clear();
|
|
|
|
|
|
|
|
|
|
if (m_initialized) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!InitializeRootDomain()) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!CreateAppDomain()) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!LoadAssemblies()) {
|
|
|
|
|
DestroyAppDomain();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!DiscoverScriptClasses()) {
|
|
|
|
|
DestroyAppDomain();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_initialized = true;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MonoScriptRuntime::Shutdown() {
|
|
|
|
|
ClearManagedInstances();
|
|
|
|
|
ClearClassCache();
|
|
|
|
|
|
|
|
|
|
m_coreAssembly = nullptr;
|
|
|
|
|
m_appAssembly = nullptr;
|
|
|
|
|
m_coreImage = nullptr;
|
|
|
|
|
m_appImage = nullptr;
|
|
|
|
|
m_componentClass = nullptr;
|
|
|
|
|
m_behaviourClass = nullptr;
|
|
|
|
|
m_gameObjectClass = nullptr;
|
|
|
|
|
m_monoBehaviourClass = nullptr;
|
|
|
|
|
m_gameObjectConstructor = nullptr;
|
|
|
|
|
m_managedGameObjectUUIDField = nullptr;
|
|
|
|
|
m_gameObjectUUIDField = nullptr;
|
|
|
|
|
m_scriptComponentUUIDField = nullptr;
|
|
|
|
|
|
|
|
|
|
DestroyAppDomain();
|
|
|
|
|
|
|
|
|
|
m_activeScene = nullptr;
|
|
|
|
|
GetInternalCallScene() = nullptr;
|
|
|
|
|
GetInternalCallDeltaTime() = 0.0f;
|
|
|
|
|
m_initialized = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool MonoScriptRuntime::IsClassAvailable(
|
|
|
|
|
const std::string& assemblyName,
|
|
|
|
|
const std::string& namespaceName,
|
|
|
|
|
const std::string& className) const {
|
|
|
|
|
return FindClassMetadata(assemblyName, namespaceName, className) != nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::vector<std::string> MonoScriptRuntime::GetScriptClassNames(const std::string& assemblyName) const {
|
|
|
|
|
std::vector<std::string> classNames;
|
|
|
|
|
classNames.reserve(m_classes.size());
|
|
|
|
|
|
|
|
|
|
for (const auto& [key, metadata] : m_classes) {
|
|
|
|
|
(void)key;
|
|
|
|
|
if (!assemblyName.empty() && metadata.assemblyName != assemblyName) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
classNames.push_back(metadata.fullName);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::sort(classNames.begin(), classNames.end());
|
|
|
|
|
return classNames;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool MonoScriptRuntime::HasManagedInstance(const ScriptComponent* component) const {
|
|
|
|
|
const InstanceData* instanceData = FindInstance(component);
|
|
|
|
|
return instanceData != nullptr && GetManagedObject(*instanceData) != nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool MonoScriptRuntime::TryGetFieldValue(
|
|
|
|
|
const ScriptComponent* component,
|
|
|
|
|
const std::string& fieldName,
|
|
|
|
|
ScriptFieldValue& outValue) const {
|
|
|
|
|
const InstanceData* instanceData = FindInstance(component);
|
|
|
|
|
if (!instanceData || !instanceData->classMetadata) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const auto fieldIt = instanceData->classMetadata->fields.find(fieldName);
|
|
|
|
|
if (fieldIt == instanceData->classMetadata->fields.end()) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MonoObject* instance = GetManagedObject(*instanceData);
|
|
|
|
|
if (!instance) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return TryReadFieldValue(instance, fieldIt->second, outValue);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MonoScriptRuntime::OnRuntimeStart(Components::Scene* scene) {
|
|
|
|
|
m_activeScene = nullptr;
|
|
|
|
|
GetInternalCallDeltaTime() = 0.0f;
|
|
|
|
|
if (Initialize()) {
|
|
|
|
|
m_activeScene = scene;
|
|
|
|
|
GetInternalCallScene() = scene;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MonoScriptRuntime::OnRuntimeStop(Components::Scene* scene) {
|
|
|
|
|
(void)scene;
|
|
|
|
|
ClearManagedInstances();
|
|
|
|
|
m_activeScene = nullptr;
|
|
|
|
|
GetInternalCallScene() = nullptr;
|
|
|
|
|
GetInternalCallDeltaTime() = 0.0f;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool MonoScriptRuntime::CreateScriptInstance(const ScriptRuntimeContext& context) {
|
|
|
|
|
if (!context.component) {
|
|
|
|
|
SetError("Cannot create a managed script instance without a ScriptComponent.");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (FindInstance(context)) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!Initialize()) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const std::string assemblyName = context.component->GetAssemblyName().empty()
|
|
|
|
|
? m_settings.appAssemblyName
|
|
|
|
|
: context.component->GetAssemblyName();
|
|
|
|
|
|
|
|
|
|
const ClassMetadata* classMetadata = FindClassMetadata(
|
|
|
|
|
assemblyName,
|
|
|
|
|
context.component->GetNamespaceName(),
|
|
|
|
|
context.component->GetClassName());
|
|
|
|
|
if (!classMetadata) {
|
|
|
|
|
SetError("Managed script class was not found: " + assemblyName + "|" + context.component->GetFullClassName());
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SetCurrentDomain();
|
|
|
|
|
|
|
|
|
|
MonoObject* instance = mono_object_new(m_appDomain, classMetadata->monoClass);
|
|
|
|
|
if (!instance) {
|
|
|
|
|
SetError("Mono failed to allocate a managed object for " + classMetadata->fullName + ".");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mono_runtime_object_init(instance);
|
|
|
|
|
|
|
|
|
|
if (!ApplyContextFields(context, instance) || !ApplyStoredFields(context, *classMetadata, instance)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const uint32_t gcHandle = mono_gchandle_new(instance, false);
|
|
|
|
|
const InstanceKey key{context.gameObjectUUID, context.scriptComponentUUID};
|
|
|
|
|
m_instances[key] = InstanceData{classMetadata, gcHandle};
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MonoScriptRuntime::DestroyScriptInstance(const ScriptRuntimeContext& context) {
|
|
|
|
|
InstanceData* instanceData = FindInstance(context);
|
|
|
|
|
if (!instanceData) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (instanceData->gcHandle != 0) {
|
|
|
|
|
mono_gchandle_free(instanceData->gcHandle);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_instances.erase(InstanceKey{context.gameObjectUUID, context.scriptComponentUUID});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MonoScriptRuntime::InvokeMethod(
|
|
|
|
|
const ScriptRuntimeContext& context,
|
|
|
|
|
ScriptLifecycleMethod method,
|
|
|
|
|
float deltaTime) {
|
|
|
|
|
const InstanceData* instanceData = FindInstance(context);
|
|
|
|
|
if (!instanceData || !instanceData->classMetadata) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MonoMethod* managedMethod = instanceData->classMetadata->lifecycleMethods[static_cast<size_t>(method)];
|
|
|
|
|
if (!managedMethod) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MonoObject* instance = GetManagedObject(*instanceData);
|
|
|
|
|
if (!instance) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const float previousDeltaTime = GetInternalCallDeltaTime();
|
|
|
|
|
GetInternalCallDeltaTime() = deltaTime;
|
|
|
|
|
InvokeManagedMethod(instance, managedMethod);
|
|
|
|
|
GetInternalCallDeltaTime() = previousDeltaTime;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t MonoScriptRuntime::InstanceKeyHasher::operator()(const InstanceKey& key) const {
|
|
|
|
|
const size_t h1 = std::hash<uint64_t>{}(key.gameObjectUUID);
|
|
|
|
|
const size_t h2 = std::hash<uint64_t>{}(key.scriptComponentUUID);
|
|
|
|
|
return h1 ^ (h2 + 0x9e3779b97f4a7c15ULL + (h1 << 6) + (h1 >> 2));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MonoScriptRuntime::ResolveSettings() {
|
|
|
|
|
if (!m_settings.coreAssemblyPath.empty() && m_settings.assemblyDirectory.empty()) {
|
|
|
|
|
m_settings.assemblyDirectory = m_settings.coreAssemblyPath.parent_path();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!m_settings.appAssemblyPath.empty() && m_settings.assemblyDirectory.empty()) {
|
|
|
|
|
m_settings.assemblyDirectory = m_settings.appAssemblyPath.parent_path();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (m_settings.coreAssemblyPath.empty() && !m_settings.assemblyDirectory.empty()) {
|
|
|
|
|
m_settings.coreAssemblyPath = m_settings.assemblyDirectory / (m_settings.coreAssemblyName + ".dll");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (m_settings.appAssemblyPath.empty() && !m_settings.assemblyDirectory.empty()) {
|
|
|
|
|
m_settings.appAssemblyPath = m_settings.assemblyDirectory / (m_settings.appAssemblyName + ".dll");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (m_settings.corlibDirectory.empty()) {
|
|
|
|
|
if (!m_settings.assemblyDirectory.empty()) {
|
|
|
|
|
m_settings.corlibDirectory = m_settings.assemblyDirectory;
|
|
|
|
|
} else if (!m_settings.coreAssemblyPath.empty()) {
|
|
|
|
|
m_settings.corlibDirectory = m_settings.coreAssemblyPath.parent_path();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool MonoScriptRuntime::InitializeRootDomain() {
|
|
|
|
|
MonoRootState& rootState = GetMonoRootState();
|
|
|
|
|
if (rootState.initialized) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!m_settings.corlibDirectory.empty()) {
|
|
|
|
|
const std::string corlibDirectory = m_settings.corlibDirectory.string();
|
|
|
|
|
mono_set_assemblies_path(corlibDirectory.c_str());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mono_config_parse(nullptr);
|
|
|
|
|
|
|
|
|
|
rootState.rootDomain = mono_jit_init_version("XCEngineRootDomain", "v4.0.30319");
|
|
|
|
|
if (!rootState.rootDomain) {
|
|
|
|
|
SetError("Failed to initialize the Mono root domain.");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mono_domain_set(rootState.rootDomain, true);
|
|
|
|
|
RegisterInternalCalls();
|
|
|
|
|
rootState.initialized = true;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool MonoScriptRuntime::CreateAppDomain() {
|
|
|
|
|
if (m_appDomain) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MonoRootState& rootState = GetMonoRootState();
|
|
|
|
|
if (!rootState.rootDomain) {
|
|
|
|
|
SetError("Mono root domain is not initialized.");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mono_domain_set(rootState.rootDomain, true);
|
|
|
|
|
m_appDomain = mono_domain_create_appdomain(const_cast<char*>("XCEngineScriptDomain"), nullptr);
|
|
|
|
|
if (!m_appDomain) {
|
|
|
|
|
SetError("Failed to create the Mono app domain.");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mono_domain_set(m_appDomain, true);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MonoScriptRuntime::DestroyAppDomain() {
|
|
|
|
|
if (!m_appDomain) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MonoRootState& rootState = GetMonoRootState();
|
|
|
|
|
if (rootState.rootDomain) {
|
|
|
|
|
mono_domain_set(rootState.rootDomain, true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mono_domain_unload(m_appDomain);
|
|
|
|
|
m_appDomain = nullptr;
|
|
|
|
|
|
|
|
|
|
if (rootState.rootDomain) {
|
|
|
|
|
mono_domain_set(rootState.rootDomain, true);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MonoScriptRuntime::SetCurrentDomain() const {
|
|
|
|
|
if (m_appDomain) {
|
|
|
|
|
mono_domain_set(m_appDomain, true);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool MonoScriptRuntime::LoadAssemblies() {
|
|
|
|
|
if (m_settings.coreAssemblyPath.empty() || m_settings.appAssemblyPath.empty()) {
|
|
|
|
|
SetError("Managed assembly paths are not configured.");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!std::filesystem::exists(m_settings.coreAssemblyPath)) {
|
|
|
|
|
SetError("Script core assembly does not exist: " + m_settings.coreAssemblyPath.string());
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!std::filesystem::exists(m_settings.appAssemblyPath)) {
|
|
|
|
|
SetError("Game scripts assembly does not exist: " + m_settings.appAssemblyPath.string());
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SetCurrentDomain();
|
|
|
|
|
|
|
|
|
|
m_coreAssembly = mono_domain_assembly_open(m_appDomain, m_settings.coreAssemblyPath.string().c_str());
|
|
|
|
|
if (!m_coreAssembly) {
|
|
|
|
|
SetError("Failed to load script core assembly: " + m_settings.coreAssemblyPath.string());
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_coreImage = mono_assembly_get_image(m_coreAssembly);
|
|
|
|
|
if (!m_coreImage) {
|
|
|
|
|
SetError("Failed to access the script core image.");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_appAssembly = mono_domain_assembly_open(m_appDomain, m_settings.appAssemblyPath.string().c_str());
|
|
|
|
|
if (!m_appAssembly) {
|
|
|
|
|
SetError("Failed to load game scripts assembly: " + m_settings.appAssemblyPath.string());
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_appImage = mono_assembly_get_image(m_appAssembly);
|
|
|
|
|
if (!m_appImage) {
|
|
|
|
|
SetError("Failed to access the game scripts image.");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool MonoScriptRuntime::DiscoverScriptClasses() {
|
|
|
|
|
ClearClassCache();
|
|
|
|
|
|
|
|
|
|
m_componentClass = mono_class_from_name(
|
|
|
|
|
m_coreImage,
|
|
|
|
|
m_settings.baseNamespace.c_str(),
|
|
|
|
|
"Component");
|
|
|
|
|
if (!m_componentClass) {
|
|
|
|
|
SetError("Failed to locate the managed Component base type.");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_behaviourClass = mono_class_from_name(
|
|
|
|
|
m_coreImage,
|
|
|
|
|
m_settings.baseNamespace.c_str(),
|
|
|
|
|
"Behaviour");
|
|
|
|
|
if (!m_behaviourClass) {
|
|
|
|
|
SetError("Failed to locate the managed Behaviour base type.");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_gameObjectClass = mono_class_from_name(
|
|
|
|
|
m_coreImage,
|
|
|
|
|
m_settings.baseNamespace.c_str(),
|
|
|
|
|
"GameObject");
|
|
|
|
|
if (!m_gameObjectClass) {
|
|
|
|
|
SetError("Failed to locate the managed GameObject wrapper type.");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_gameObjectConstructor = mono_class_get_method_from_name(m_gameObjectClass, ".ctor", 1);
|
|
|
|
|
m_managedGameObjectUUIDField = mono_class_get_field_from_name(m_gameObjectClass, "m_uuid");
|
|
|
|
|
if (!m_gameObjectConstructor || !m_managedGameObjectUUIDField) {
|
|
|
|
|
SetError("Failed to locate the managed GameObject constructor or UUID field.");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_monoBehaviourClass = mono_class_from_name(
|
|
|
|
|
m_coreImage,
|
|
|
|
|
m_settings.baseNamespace.c_str(),
|
|
|
|
|
m_settings.baseClassName.c_str());
|
|
|
|
|
if (!m_monoBehaviourClass) {
|
|
|
|
|
SetError("Failed to locate the managed base type " + BuildFullClassName(m_settings.baseNamespace, m_settings.baseClassName) + ".");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_gameObjectUUIDField = mono_class_get_field_from_name(m_componentClass, "m_gameObjectUUID");
|
|
|
|
|
m_scriptComponentUUIDField = mono_class_get_field_from_name(m_behaviourClass, "m_scriptComponentUUID");
|
|
|
|
|
if (!m_gameObjectUUIDField || !m_scriptComponentUUIDField) {
|
|
|
|
|
SetError("Failed to locate the managed context fields for Component/Behaviour.");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DiscoverScriptClassesInImage(m_settings.appAssemblyName, m_appImage);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MonoScriptRuntime::DiscoverScriptClassesInImage(const std::string& assemblyName, MonoImage* image) {
|
|
|
|
|
if (!image) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const int typeCount = mono_image_get_table_rows(image, MONO_TABLE_TYPEDEF);
|
|
|
|
|
for (int index = 1; index <= typeCount; ++index) {
|
|
|
|
|
const uint32_t typeToken = mono_metadata_make_token(MONO_TABLE_TYPEDEF, index);
|
|
|
|
|
MonoClass* monoClass = mono_class_get(image, typeToken);
|
|
|
|
|
if (!monoClass || !IsMonoBehaviourSubclass(monoClass)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((mono_class_get_flags(monoClass) & MONO_TYPE_ATTR_ABSTRACT) != 0) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ClassMetadata metadata;
|
|
|
|
|
metadata.assemblyName = assemblyName;
|
|
|
|
|
metadata.namespaceName = SafeString(mono_class_get_namespace(monoClass));
|
|
|
|
|
metadata.className = SafeString(mono_class_get_name(monoClass));
|
|
|
|
|
metadata.fullName = BuildFullClassName(metadata.namespaceName, metadata.className);
|
|
|
|
|
metadata.monoClass = monoClass;
|
|
|
|
|
|
|
|
|
|
for (size_t methodIndex = 0; methodIndex < LifecycleMethodCount; ++methodIndex) {
|
|
|
|
|
metadata.lifecycleMethods[methodIndex] = mono_class_get_method_from_name(
|
|
|
|
|
monoClass,
|
|
|
|
|
ToLifecycleMethodName(static_cast<ScriptLifecycleMethod>(methodIndex)),
|
|
|
|
|
0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void* fieldIterator = nullptr;
|
|
|
|
|
while (MonoClassField* field = mono_class_get_fields(monoClass, &fieldIterator)) {
|
|
|
|
|
const uint32_t fieldFlags = mono_field_get_flags(field);
|
|
|
|
|
if ((fieldFlags & MONO_FIELD_ATTR_PUBLIC) == 0 || (fieldFlags & MONO_FIELD_ATTR_STATIC) != 0) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const ScriptFieldType fieldType = MapMonoFieldType(field);
|
|
|
|
|
if (fieldType == ScriptFieldType::None) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
metadata.fields.emplace(
|
|
|
|
|
mono_field_get_name(field),
|
|
|
|
|
FieldMetadata{fieldType, field});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_classes.emplace(
|
|
|
|
|
BuildClassKey(metadata.assemblyName, metadata.namespaceName, metadata.className),
|
|
|
|
|
std::move(metadata));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool MonoScriptRuntime::IsMonoBehaviourSubclass(MonoClass* monoClass) const {
|
|
|
|
|
if (!monoClass || !m_monoBehaviourClass || monoClass == m_monoBehaviourClass) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MonoClass* current = monoClass;
|
|
|
|
|
while (current) {
|
|
|
|
|
if (current == m_monoBehaviourClass) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
current = mono_class_get_parent(current);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ScriptFieldType MonoScriptRuntime::MapMonoFieldType(MonoClassField* field) const {
|
|
|
|
|
if (!field) {
|
|
|
|
|
return ScriptFieldType::None;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MonoType* monoType = mono_field_get_type(field);
|
|
|
|
|
if (!monoType) {
|
|
|
|
|
return ScriptFieldType::None;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (mono_type_get_type(monoType)) {
|
|
|
|
|
case MONO_TYPE_R4:
|
|
|
|
|
return ScriptFieldType::Float;
|
|
|
|
|
case MONO_TYPE_R8:
|
|
|
|
|
return ScriptFieldType::Double;
|
|
|
|
|
case MONO_TYPE_BOOLEAN:
|
|
|
|
|
return ScriptFieldType::Bool;
|
|
|
|
|
case MONO_TYPE_I4:
|
|
|
|
|
return ScriptFieldType::Int32;
|
|
|
|
|
case MONO_TYPE_U8:
|
|
|
|
|
return ScriptFieldType::UInt64;
|
|
|
|
|
case MONO_TYPE_STRING:
|
|
|
|
|
return ScriptFieldType::String;
|
|
|
|
|
case MONO_TYPE_CLASS: {
|
|
|
|
|
MonoClass* referenceClass = mono_class_from_mono_type(monoType);
|
|
|
|
|
if (!referenceClass) {
|
|
|
|
|
return ScriptFieldType::None;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const std::string namespaceName = SafeString(mono_class_get_namespace(referenceClass));
|
|
|
|
|
const std::string className = SafeString(mono_class_get_name(referenceClass));
|
|
|
|
|
if (namespaceName == m_settings.baseNamespace && className == "GameObject") {
|
|
|
|
|
return ScriptFieldType::GameObject;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ScriptFieldType::None;
|
|
|
|
|
}
|
|
|
|
|
case MONO_TYPE_VALUETYPE: {
|
|
|
|
|
MonoClass* valueTypeClass = mono_class_from_mono_type(monoType);
|
|
|
|
|
if (!valueTypeClass) {
|
|
|
|
|
return ScriptFieldType::None;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const std::string namespaceName = SafeString(mono_class_get_namespace(valueTypeClass));
|
|
|
|
|
const std::string className = SafeString(mono_class_get_name(valueTypeClass));
|
|
|
|
|
if (namespaceName != m_settings.baseNamespace) {
|
|
|
|
|
return ScriptFieldType::None;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (className == "Vector2") {
|
|
|
|
|
return ScriptFieldType::Vector2;
|
|
|
|
|
}
|
|
|
|
|
if (className == "Vector3") {
|
|
|
|
|
return ScriptFieldType::Vector3;
|
|
|
|
|
}
|
|
|
|
|
if (className == "Vector4") {
|
|
|
|
|
return ScriptFieldType::Vector4;
|
|
|
|
|
}
|
|
|
|
|
return ScriptFieldType::None;
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
return ScriptFieldType::None;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char* MonoScriptRuntime::ToLifecycleMethodName(ScriptLifecycleMethod method) {
|
|
|
|
|
switch (method) {
|
|
|
|
|
case ScriptLifecycleMethod::Awake: return "Awake";
|
|
|
|
|
case ScriptLifecycleMethod::OnEnable: return "OnEnable";
|
|
|
|
|
case ScriptLifecycleMethod::Start: return "Start";
|
|
|
|
|
case ScriptLifecycleMethod::FixedUpdate: return "FixedUpdate";
|
|
|
|
|
case ScriptLifecycleMethod::Update: return "Update";
|
|
|
|
|
case ScriptLifecycleMethod::LateUpdate: return "LateUpdate";
|
|
|
|
|
case ScriptLifecycleMethod::OnDisable: return "OnDisable";
|
|
|
|
|
case ScriptLifecycleMethod::OnDestroy: return "OnDestroy";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return "";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const MonoScriptRuntime::ClassMetadata* MonoScriptRuntime::FindClassMetadata(
|
|
|
|
|
const std::string& assemblyName,
|
|
|
|
|
const std::string& namespaceName,
|
|
|
|
|
const std::string& className) const {
|
|
|
|
|
const auto it = m_classes.find(BuildClassKey(assemblyName, namespaceName, className));
|
|
|
|
|
return it != m_classes.end() ? &it->second : nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MonoScriptRuntime::InstanceData* MonoScriptRuntime::FindInstance(const ScriptRuntimeContext& context) {
|
|
|
|
|
const auto it = m_instances.find(InstanceKey{context.gameObjectUUID, context.scriptComponentUUID});
|
|
|
|
|
return it != m_instances.end() ? &it->second : nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const MonoScriptRuntime::InstanceData* MonoScriptRuntime::FindInstance(const ScriptRuntimeContext& context) const {
|
|
|
|
|
const auto it = m_instances.find(InstanceKey{context.gameObjectUUID, context.scriptComponentUUID});
|
|
|
|
|
return it != m_instances.end() ? &it->second : nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const MonoScriptRuntime::InstanceData* MonoScriptRuntime::FindInstance(const ScriptComponent* component) const {
|
|
|
|
|
if (!component || !component->GetGameObject()) {
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const auto it = m_instances.find(InstanceKey{
|
|
|
|
|
component->GetGameObject()->GetUUID(),
|
|
|
|
|
component->GetScriptComponentUUID()
|
|
|
|
|
});
|
|
|
|
|
return it != m_instances.end() ? &it->second : nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MonoObject* MonoScriptRuntime::GetManagedObject(const InstanceData& instanceData) const {
|
|
|
|
|
if (instanceData.gcHandle == 0) {
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SetCurrentDomain();
|
|
|
|
|
return mono_gchandle_get_target(instanceData.gcHandle);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool MonoScriptRuntime::ApplyContextFields(const ScriptRuntimeContext& context, MonoObject* instance) {
|
|
|
|
|
if (!instance) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SetCurrentDomain();
|
|
|
|
|
|
|
|
|
|
if (m_gameObjectUUIDField) {
|
|
|
|
|
uint64_t gameObjectUUID = context.gameObjectUUID;
|
|
|
|
|
mono_field_set_value(instance, m_gameObjectUUIDField, &gameObjectUUID);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (m_scriptComponentUUIDField) {
|
|
|
|
|
uint64_t scriptComponentUUID = context.scriptComponentUUID;
|
|
|
|
|
mono_field_set_value(instance, m_scriptComponentUUIDField, &scriptComponentUUID);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool MonoScriptRuntime::ApplyStoredFields(
|
|
|
|
|
const ScriptRuntimeContext& context,
|
|
|
|
|
const ClassMetadata& metadata,
|
|
|
|
|
MonoObject* instance) {
|
|
|
|
|
if (!context.component || !instance) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const ScriptFieldStorage& fieldStorage = context.component->GetFieldStorage();
|
|
|
|
|
for (const std::string& fieldName : fieldStorage.GetFieldNames()) {
|
|
|
|
|
const StoredScriptField* storedField = fieldStorage.FindField(fieldName);
|
|
|
|
|
if (!storedField) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const auto metadataIt = metadata.fields.find(fieldName);
|
|
|
|
|
if (metadataIt == metadata.fields.end() || storedField->type != metadataIt->second.type) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!TrySetFieldValue(instance, metadataIt->second, storedField->value)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MonoObject* MonoScriptRuntime::CreateManagedGameObject(uint64_t gameObjectUUID) {
|
|
|
|
|
if (gameObjectUUID == 0 || !m_gameObjectClass || !m_gameObjectConstructor) {
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SetCurrentDomain();
|
|
|
|
|
|
|
|
|
|
MonoObject* managedObject = mono_object_new(m_appDomain, m_gameObjectClass);
|
|
|
|
|
if (!managedObject) {
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void* args[1];
|
|
|
|
|
uint64_t uuidArgument = gameObjectUUID;
|
|
|
|
|
args[0] = &uuidArgument;
|
|
|
|
|
|
|
|
|
|
MonoObject* exception = nullptr;
|
|
|
|
|
mono_runtime_invoke(m_gameObjectConstructor, managedObject, args, &exception);
|
|
|
|
|
if (exception) {
|
|
|
|
|
RecordException(exception);
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return managedObject;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool MonoScriptRuntime::TryExtractGameObjectReference(
|
|
|
|
|
MonoObject* managedObject,
|
|
|
|
|
GameObjectReference& outReference) const {
|
|
|
|
|
outReference = GameObjectReference{};
|
|
|
|
|
if (!managedObject) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!m_gameObjectClass || !m_managedGameObjectUUIDField) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (mono_object_get_class(managedObject) != m_gameObjectClass) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint64_t gameObjectUUID = 0;
|
|
|
|
|
mono_field_get_value(managedObject, m_managedGameObjectUUIDField, &gameObjectUUID);
|
|
|
|
|
outReference = GameObjectReference{gameObjectUUID};
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool MonoScriptRuntime::TrySetFieldValue(
|
|
|
|
|
MonoObject* instance,
|
|
|
|
|
const FieldMetadata& fieldMetadata,
|
|
|
|
|
const ScriptFieldValue& value) {
|
|
|
|
|
if (!instance || !fieldMetadata.field) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SetCurrentDomain();
|
|
|
|
|
|
|
|
|
|
switch (fieldMetadata.type) {
|
|
|
|
|
case ScriptFieldType::Float: {
|
|
|
|
|
float nativeValue = std::get<float>(value);
|
|
|
|
|
mono_field_set_value(instance, fieldMetadata.field, &nativeValue);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
case ScriptFieldType::Double: {
|
|
|
|
|
double nativeValue = std::get<double>(value);
|
|
|
|
|
mono_field_set_value(instance, fieldMetadata.field, &nativeValue);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
case ScriptFieldType::Bool: {
|
|
|
|
|
mono_bool nativeValue = std::get<bool>(value) ? 1 : 0;
|
|
|
|
|
mono_field_set_value(instance, fieldMetadata.field, &nativeValue);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
case ScriptFieldType::Int32: {
|
|
|
|
|
int32_t nativeValue = std::get<int32_t>(value);
|
|
|
|
|
mono_field_set_value(instance, fieldMetadata.field, &nativeValue);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
case ScriptFieldType::UInt64: {
|
|
|
|
|
uint64_t nativeValue = std::get<uint64_t>(value);
|
|
|
|
|
mono_field_set_value(instance, fieldMetadata.field, &nativeValue);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
case ScriptFieldType::String: {
|
|
|
|
|
MonoString* managedString = mono_string_new(m_appDomain, std::get<std::string>(value).c_str());
|
|
|
|
|
mono_field_set_value(instance, fieldMetadata.field, managedString);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
case ScriptFieldType::Vector2: {
|
|
|
|
|
Math::Vector2 nativeValue = std::get<Math::Vector2>(value);
|
|
|
|
|
mono_field_set_value(instance, fieldMetadata.field, &nativeValue);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
case ScriptFieldType::Vector3: {
|
|
|
|
|
Math::Vector3 nativeValue = std::get<Math::Vector3>(value);
|
|
|
|
|
mono_field_set_value(instance, fieldMetadata.field, &nativeValue);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
case ScriptFieldType::Vector4: {
|
|
|
|
|
Math::Vector4 nativeValue = std::get<Math::Vector4>(value);
|
|
|
|
|
mono_field_set_value(instance, fieldMetadata.field, &nativeValue);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
case ScriptFieldType::GameObject: {
|
|
|
|
|
const GameObjectReference reference = std::get<GameObjectReference>(value);
|
|
|
|
|
MonoObject* managedGameObject = CreateManagedGameObject(reference.gameObjectUUID);
|
|
|
|
|
if (reference.gameObjectUUID != 0 && !managedGameObject) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
mono_field_set_value(instance, fieldMetadata.field, managedGameObject);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
case ScriptFieldType::None:
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool MonoScriptRuntime::TryReadFieldValue(
|
|
|
|
|
MonoObject* instance,
|
|
|
|
|
const FieldMetadata& fieldMetadata,
|
|
|
|
|
ScriptFieldValue& outValue) const {
|
|
|
|
|
if (!instance || !fieldMetadata.field) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (fieldMetadata.type) {
|
|
|
|
|
case ScriptFieldType::Float: {
|
|
|
|
|
float nativeValue = 0.0f;
|
|
|
|
|
mono_field_get_value(instance, fieldMetadata.field, &nativeValue);
|
|
|
|
|
outValue = nativeValue;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
case ScriptFieldType::Double: {
|
|
|
|
|
double nativeValue = 0.0;
|
|
|
|
|
mono_field_get_value(instance, fieldMetadata.field, &nativeValue);
|
|
|
|
|
outValue = nativeValue;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
case ScriptFieldType::Bool: {
|
|
|
|
|
mono_bool nativeValue = 0;
|
|
|
|
|
mono_field_get_value(instance, fieldMetadata.field, &nativeValue);
|
|
|
|
|
outValue = (nativeValue != 0);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
case ScriptFieldType::Int32: {
|
|
|
|
|
int32_t nativeValue = 0;
|
|
|
|
|
mono_field_get_value(instance, fieldMetadata.field, &nativeValue);
|
|
|
|
|
outValue = nativeValue;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
case ScriptFieldType::UInt64: {
|
|
|
|
|
uint64_t nativeValue = 0;
|
|
|
|
|
mono_field_get_value(instance, fieldMetadata.field, &nativeValue);
|
|
|
|
|
outValue = nativeValue;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
case ScriptFieldType::String: {
|
|
|
|
|
MonoObject* managedObject = mono_field_get_value_object(m_appDomain, fieldMetadata.field, instance);
|
|
|
|
|
if (!managedObject) {
|
|
|
|
|
outValue = std::string();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MonoString* managedString = reinterpret_cast<MonoString*>(managedObject);
|
|
|
|
|
char* utf8 = mono_string_to_utf8(managedString);
|
|
|
|
|
outValue = utf8 ? std::string(utf8) : std::string();
|
|
|
|
|
if (utf8) {
|
|
|
|
|
mono_free(utf8);
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
case ScriptFieldType::Vector2: {
|
|
|
|
|
Math::Vector2 nativeValue;
|
|
|
|
|
mono_field_get_value(instance, fieldMetadata.field, &nativeValue);
|
|
|
|
|
outValue = nativeValue;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
case ScriptFieldType::Vector3: {
|
|
|
|
|
Math::Vector3 nativeValue;
|
|
|
|
|
mono_field_get_value(instance, fieldMetadata.field, &nativeValue);
|
|
|
|
|
outValue = nativeValue;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
case ScriptFieldType::Vector4: {
|
|
|
|
|
Math::Vector4 nativeValue;
|
|
|
|
|
mono_field_get_value(instance, fieldMetadata.field, &nativeValue);
|
|
|
|
|
outValue = nativeValue;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
case ScriptFieldType::GameObject: {
|
|
|
|
|
MonoObject* managedObject = mono_field_get_value_object(m_appDomain, fieldMetadata.field, instance);
|
|
|
|
|
GameObjectReference reference;
|
|
|
|
|
if (!TryExtractGameObjectReference(managedObject, reference)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
outValue = reference;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
case ScriptFieldType::None:
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MonoScriptRuntime::ClearManagedInstances() {
|
|
|
|
|
for (auto& [key, instanceData] : m_instances) {
|
|
|
|
|
(void)key;
|
|
|
|
|
if (instanceData.gcHandle != 0) {
|
|
|
|
|
mono_gchandle_free(instanceData.gcHandle);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_instances.clear();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MonoScriptRuntime::ClearClassCache() {
|
|
|
|
|
m_classes.clear();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool MonoScriptRuntime::InvokeManagedMethod(MonoObject* instance, MonoMethod* method) {
|
|
|
|
|
if (!instance || !method) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SetCurrentDomain();
|
|
|
|
|
|
|
|
|
|
MonoObject* exception = nullptr;
|
|
|
|
|
mono_runtime_invoke(method, instance, nullptr, &exception);
|
|
|
|
|
if (exception) {
|
|
|
|
|
RecordException(exception);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MonoScriptRuntime::RecordException(MonoObject* exception) {
|
|
|
|
|
m_lastError = "Managed exception";
|
|
|
|
|
if (!exception) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MonoObject* secondaryException = nullptr;
|
|
|
|
|
MonoString* exceptionString = mono_object_to_string(exception, &secondaryException);
|
|
|
|
|
if (!exceptionString || secondaryException) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
char* utf8 = mono_string_to_utf8(exceptionString);
|
|
|
|
|
if (!utf8) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_lastError = utf8;
|
|
|
|
|
mono_free(utf8);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MonoScriptRuntime::SetError(const std::string& error) {
|
|
|
|
|
m_lastError = error;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace Scripting
|
|
|
|
|
} // namespace XCEngine
|