Add enum script field support
This commit is contained in:
@@ -111,6 +111,8 @@ private:
|
||||
struct FieldMetadata {
|
||||
ScriptFieldType type = ScriptFieldType::None;
|
||||
MonoClassField* field = nullptr;
|
||||
bool isEnum = false;
|
||||
int32_t enumUnderlyingType = 0;
|
||||
};
|
||||
|
||||
struct ClassMetadata {
|
||||
@@ -153,7 +155,7 @@ private:
|
||||
void DiscoverScriptClassesInImage(const std::string& assemblyName, MonoImage* image);
|
||||
bool IsMonoBehaviourSubclass(MonoClass* monoClass) const;
|
||||
|
||||
ScriptFieldType MapMonoFieldType(MonoClassField* field) const;
|
||||
FieldMetadata BuildFieldMetadata(MonoClassField* field) const;
|
||||
|
||||
static const char* ToLifecycleMethodName(ScriptLifecycleMethod method);
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <mono/metadata/reflection.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
#include <utility>
|
||||
|
||||
namespace XCEngine {
|
||||
@@ -2267,14 +2268,12 @@ void MonoScriptRuntime::DiscoverScriptClassesInImage(const std::string& assembly
|
||||
continue;
|
||||
}
|
||||
|
||||
const ScriptFieldType fieldType = MapMonoFieldType(field);
|
||||
if (fieldType == ScriptFieldType::None) {
|
||||
FieldMetadata fieldMetadata = BuildFieldMetadata(field);
|
||||
if (fieldMetadata.type == ScriptFieldType::None) {
|
||||
continue;
|
||||
}
|
||||
|
||||
metadata.fields.emplace(
|
||||
mono_field_get_name(field),
|
||||
FieldMetadata{fieldType, field});
|
||||
metadata.fields.emplace(mono_field_get_name(field), std::move(fieldMetadata));
|
||||
}
|
||||
|
||||
m_classes.emplace(
|
||||
@@ -2300,68 +2299,101 @@ bool MonoScriptRuntime::IsMonoBehaviourSubclass(MonoClass* monoClass) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
ScriptFieldType MonoScriptRuntime::MapMonoFieldType(MonoClassField* field) const {
|
||||
MonoScriptRuntime::FieldMetadata MonoScriptRuntime::BuildFieldMetadata(MonoClassField* field) const {
|
||||
FieldMetadata metadata;
|
||||
metadata.field = field;
|
||||
if (!field) {
|
||||
return ScriptFieldType::None;
|
||||
return metadata;
|
||||
}
|
||||
|
||||
MonoType* monoType = mono_field_get_type(field);
|
||||
if (!monoType) {
|
||||
return ScriptFieldType::None;
|
||||
return metadata;
|
||||
}
|
||||
|
||||
switch (mono_type_get_type(monoType)) {
|
||||
case MONO_TYPE_R4:
|
||||
return ScriptFieldType::Float;
|
||||
metadata.type = ScriptFieldType::Float;
|
||||
return metadata;
|
||||
case MONO_TYPE_R8:
|
||||
return ScriptFieldType::Double;
|
||||
metadata.type = ScriptFieldType::Double;
|
||||
return metadata;
|
||||
case MONO_TYPE_BOOLEAN:
|
||||
return ScriptFieldType::Bool;
|
||||
metadata.type = ScriptFieldType::Bool;
|
||||
return metadata;
|
||||
case MONO_TYPE_I4:
|
||||
return ScriptFieldType::Int32;
|
||||
metadata.type = ScriptFieldType::Int32;
|
||||
return metadata;
|
||||
case MONO_TYPE_U8:
|
||||
return ScriptFieldType::UInt64;
|
||||
metadata.type = ScriptFieldType::UInt64;
|
||||
return metadata;
|
||||
case MONO_TYPE_STRING:
|
||||
return ScriptFieldType::String;
|
||||
metadata.type = ScriptFieldType::String;
|
||||
return metadata;
|
||||
case MONO_TYPE_CLASS: {
|
||||
MonoClass* referenceClass = mono_class_from_mono_type(monoType);
|
||||
if (!referenceClass) {
|
||||
return ScriptFieldType::None;
|
||||
return metadata;
|
||||
}
|
||||
|
||||
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;
|
||||
metadata.type = ScriptFieldType::GameObject;
|
||||
}
|
||||
|
||||
return ScriptFieldType::None;
|
||||
return metadata;
|
||||
}
|
||||
case MONO_TYPE_VALUETYPE: {
|
||||
MonoClass* valueTypeClass = mono_class_from_mono_type(monoType);
|
||||
if (!valueTypeClass) {
|
||||
return ScriptFieldType::None;
|
||||
return metadata;
|
||||
}
|
||||
|
||||
if (mono_class_is_enum(valueTypeClass) != 0) {
|
||||
MonoType* underlyingType = mono_class_enum_basetype(valueTypeClass);
|
||||
if (!underlyingType) {
|
||||
return metadata;
|
||||
}
|
||||
|
||||
switch (mono_type_get_type(underlyingType)) {
|
||||
case MONO_TYPE_I1:
|
||||
case MONO_TYPE_U1:
|
||||
case MONO_TYPE_I2:
|
||||
case MONO_TYPE_U2:
|
||||
case MONO_TYPE_I4:
|
||||
case MONO_TYPE_U4:
|
||||
metadata.type = ScriptFieldType::Int32;
|
||||
metadata.isEnum = true;
|
||||
metadata.enumUnderlyingType = static_cast<int32_t>(mono_type_get_type(underlyingType));
|
||||
return metadata;
|
||||
default:
|
||||
return metadata;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
return metadata;
|
||||
}
|
||||
|
||||
if (className == "Vector2") {
|
||||
return ScriptFieldType::Vector2;
|
||||
metadata.type = ScriptFieldType::Vector2;
|
||||
return metadata;
|
||||
}
|
||||
if (className == "Vector3") {
|
||||
return ScriptFieldType::Vector3;
|
||||
metadata.type = ScriptFieldType::Vector3;
|
||||
return metadata;
|
||||
}
|
||||
if (className == "Vector4") {
|
||||
return ScriptFieldType::Vector4;
|
||||
metadata.type = ScriptFieldType::Vector4;
|
||||
return metadata;
|
||||
}
|
||||
return ScriptFieldType::None;
|
||||
return metadata;
|
||||
}
|
||||
default:
|
||||
return ScriptFieldType::None;
|
||||
return metadata;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2623,6 +2655,70 @@ bool MonoScriptRuntime::TrySetFieldValue(
|
||||
|
||||
SetCurrentDomain();
|
||||
|
||||
if (fieldMetadata.isEnum) {
|
||||
if (!std::holds_alternative<int32_t>(value)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const int32_t storedValue = std::get<int32_t>(value);
|
||||
switch (fieldMetadata.enumUnderlyingType) {
|
||||
case MONO_TYPE_I1: {
|
||||
if (storedValue < std::numeric_limits<int8_t>::min()
|
||||
|| storedValue > std::numeric_limits<int8_t>::max()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int8_t nativeValue = static_cast<int8_t>(storedValue);
|
||||
mono_field_set_value(instance, fieldMetadata.field, &nativeValue);
|
||||
return true;
|
||||
}
|
||||
case MONO_TYPE_U1: {
|
||||
if (storedValue < 0 || storedValue > std::numeric_limits<uint8_t>::max()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t nativeValue = static_cast<uint8_t>(storedValue);
|
||||
mono_field_set_value(instance, fieldMetadata.field, &nativeValue);
|
||||
return true;
|
||||
}
|
||||
case MONO_TYPE_I2: {
|
||||
if (storedValue < std::numeric_limits<int16_t>::min()
|
||||
|| storedValue > std::numeric_limits<int16_t>::max()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int16_t nativeValue = static_cast<int16_t>(storedValue);
|
||||
mono_field_set_value(instance, fieldMetadata.field, &nativeValue);
|
||||
return true;
|
||||
}
|
||||
case MONO_TYPE_U2: {
|
||||
if (storedValue < 0 || storedValue > std::numeric_limits<uint16_t>::max()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint16_t nativeValue = static_cast<uint16_t>(storedValue);
|
||||
mono_field_set_value(instance, fieldMetadata.field, &nativeValue);
|
||||
return true;
|
||||
}
|
||||
case MONO_TYPE_I4: {
|
||||
int32_t nativeValue = storedValue;
|
||||
mono_field_set_value(instance, fieldMetadata.field, &nativeValue);
|
||||
return true;
|
||||
}
|
||||
case MONO_TYPE_U4: {
|
||||
if (storedValue < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t nativeValue = static_cast<uint32_t>(storedValue);
|
||||
mono_field_set_value(instance, fieldMetadata.field, &nativeValue);
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
switch (fieldMetadata.type) {
|
||||
case ScriptFieldType::Float: {
|
||||
float nativeValue = std::get<float>(value);
|
||||
@@ -2693,6 +2789,53 @@ bool MonoScriptRuntime::TryReadFieldValue(
|
||||
return false;
|
||||
}
|
||||
|
||||
if (fieldMetadata.isEnum) {
|
||||
switch (fieldMetadata.enumUnderlyingType) {
|
||||
case MONO_TYPE_I1: {
|
||||
int8_t nativeValue = 0;
|
||||
mono_field_get_value(instance, fieldMetadata.field, &nativeValue);
|
||||
outValue = static_cast<int32_t>(nativeValue);
|
||||
return true;
|
||||
}
|
||||
case MONO_TYPE_U1: {
|
||||
uint8_t nativeValue = 0;
|
||||
mono_field_get_value(instance, fieldMetadata.field, &nativeValue);
|
||||
outValue = static_cast<int32_t>(nativeValue);
|
||||
return true;
|
||||
}
|
||||
case MONO_TYPE_I2: {
|
||||
int16_t nativeValue = 0;
|
||||
mono_field_get_value(instance, fieldMetadata.field, &nativeValue);
|
||||
outValue = static_cast<int32_t>(nativeValue);
|
||||
return true;
|
||||
}
|
||||
case MONO_TYPE_U2: {
|
||||
uint16_t nativeValue = 0;
|
||||
mono_field_get_value(instance, fieldMetadata.field, &nativeValue);
|
||||
outValue = static_cast<int32_t>(nativeValue);
|
||||
return true;
|
||||
}
|
||||
case MONO_TYPE_I4: {
|
||||
int32_t nativeValue = 0;
|
||||
mono_field_get_value(instance, fieldMetadata.field, &nativeValue);
|
||||
outValue = nativeValue;
|
||||
return true;
|
||||
}
|
||||
case MONO_TYPE_U4: {
|
||||
uint32_t nativeValue = 0;
|
||||
mono_field_get_value(instance, fieldMetadata.field, &nativeValue);
|
||||
if (nativeValue > static_cast<uint32_t>(std::numeric_limits<int32_t>::max())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
outValue = static_cast<int32_t>(nativeValue);
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
switch (fieldMetadata.type) {
|
||||
case ScriptFieldType::Float: {
|
||||
float nativeValue = 0.0f;
|
||||
|
||||
Reference in New Issue
Block a user