mirror of
https://github.com/godotengine/godot.git
synced 2024-11-27 09:16:35 +08:00
Merge pull request #15346 from neikeq/properties-are-overrated
Mono: Add properties support in scripts
This commit is contained in:
commit
0f8ac21592
@ -913,19 +913,23 @@ bool CSharpInstance::set(const StringName &p_name, const Variant &p_value) {
|
||||
|
||||
ERR_FAIL_COND_V(!script.is_valid(), false);
|
||||
|
||||
MonoObject *mono_object = get_mono_object();
|
||||
ERR_FAIL_NULL_V(mono_object, false);
|
||||
|
||||
GDMonoClass *top = script->script_class;
|
||||
|
||||
while (top && top != script->native) {
|
||||
GDMonoField *field = script->script_class->get_field(p_name);
|
||||
|
||||
if (field) {
|
||||
MonoObject *mono_object = get_mono_object();
|
||||
field->set_value_from_variant(mono_object, p_value);
|
||||
return true;
|
||||
}
|
||||
|
||||
ERR_EXPLAIN("Reference has been garbage collected?");
|
||||
ERR_FAIL_NULL_V(mono_object, false);
|
||||
|
||||
field->set_value(mono_object, p_value);
|
||||
GDMonoProperty *property = script->script_class->get_property(p_name);
|
||||
|
||||
if (property) {
|
||||
property->set_value(mono_object, GDMonoMarshal::variant_to_mono_object(p_value));
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -934,16 +938,15 @@ bool CSharpInstance::set(const StringName &p_name, const Variant &p_value) {
|
||||
|
||||
// Call _set
|
||||
|
||||
Variant name = p_name;
|
||||
const Variant *args[2] = { &name, &p_value };
|
||||
|
||||
MonoObject *mono_object = get_mono_object();
|
||||
top = script->script_class;
|
||||
|
||||
while (top && top != script->native) {
|
||||
GDMonoMethod *method = top->get_method(CACHED_STRING_NAME(_set), 2);
|
||||
|
||||
if (method) {
|
||||
Variant name = p_name;
|
||||
const Variant *args[2] = { &name, &p_value };
|
||||
|
||||
MonoObject *ret = method->invoke(mono_object, args);
|
||||
|
||||
if (ret && GDMonoMarshal::unbox<MonoBoolean>(ret) == true)
|
||||
@ -960,31 +963,49 @@ bool CSharpInstance::get(const StringName &p_name, Variant &r_ret) const {
|
||||
|
||||
ERR_FAIL_COND_V(!script.is_valid(), false);
|
||||
|
||||
MonoObject *mono_object = get_mono_object();
|
||||
ERR_FAIL_NULL_V(mono_object, false);
|
||||
|
||||
GDMonoClass *top = script->script_class;
|
||||
|
||||
while (top && top != script->native) {
|
||||
GDMonoField *field = top->get_field(p_name);
|
||||
|
||||
if (field) {
|
||||
MonoObject *mono_object = get_mono_object();
|
||||
|
||||
ERR_EXPLAIN("Reference has been garbage collected?");
|
||||
ERR_FAIL_NULL_V(mono_object, false);
|
||||
|
||||
MonoObject *value = field->get_value(mono_object);
|
||||
r_ret = GDMonoMarshal::mono_object_to_variant(value, field->get_type());
|
||||
return true;
|
||||
}
|
||||
|
||||
// Call _get
|
||||
GDMonoProperty *property = top->get_property(p_name);
|
||||
|
||||
if (property) {
|
||||
MonoObject *exc = NULL;
|
||||
MonoObject *value = property->get_value(mono_object, &exc);
|
||||
if (exc) {
|
||||
r_ret = Variant();
|
||||
GDMonoUtils::print_unhandled_exception(exc);
|
||||
} else {
|
||||
r_ret = GDMonoMarshal::mono_object_to_variant(value, property->get_type());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
top = top->get_parent_class();
|
||||
}
|
||||
|
||||
// Call _get
|
||||
|
||||
top = script->script_class;
|
||||
|
||||
while (top && top != script->native) {
|
||||
GDMonoMethod *method = top->get_method(CACHED_STRING_NAME(_get), 1);
|
||||
|
||||
if (method) {
|
||||
Variant name = p_name;
|
||||
const Variant *args[1] = { &name };
|
||||
|
||||
MonoObject *ret = method->invoke(get_mono_object(), args);
|
||||
MonoObject *ret = method->invoke(mono_object, args);
|
||||
|
||||
if (ret) {
|
||||
r_ret = GDMonoMarshal::mono_object_to_variant(ret);
|
||||
@ -1186,6 +1207,20 @@ bool CSharpInstance::refcount_decremented() {
|
||||
return ref_dying;
|
||||
}
|
||||
|
||||
ScriptInstance::RPCMode CSharpInstance::_member_get_rpc_mode(GDMonoClassMember *p_member) const {
|
||||
|
||||
if (p_member->has_attribute(CACHED_CLASS(RemoteAttribute)))
|
||||
return RPC_MODE_REMOTE;
|
||||
if (p_member->has_attribute(CACHED_CLASS(SyncAttribute)))
|
||||
return RPC_MODE_SYNC;
|
||||
if (p_member->has_attribute(CACHED_CLASS(MasterAttribute)))
|
||||
return RPC_MODE_MASTER;
|
||||
if (p_member->has_attribute(CACHED_CLASS(SlaveAttribute)))
|
||||
return RPC_MODE_SLAVE;
|
||||
|
||||
return RPC_MODE_DISABLED;
|
||||
}
|
||||
|
||||
ScriptInstance::RPCMode CSharpInstance::get_rpc_mode(const StringName &p_method) const {
|
||||
|
||||
GDMonoClass *top = script->script_class;
|
||||
@ -1193,17 +1228,8 @@ ScriptInstance::RPCMode CSharpInstance::get_rpc_mode(const StringName &p_method)
|
||||
while (top && top != script->native) {
|
||||
GDMonoMethod *method = top->get_method(p_method);
|
||||
|
||||
if (method) { // TODO should we reject static methods?
|
||||
// TODO cache result
|
||||
if (method->has_attribute(CACHED_CLASS(RemoteAttribute)))
|
||||
return RPC_MODE_REMOTE;
|
||||
if (method->has_attribute(CACHED_CLASS(SyncAttribute)))
|
||||
return RPC_MODE_SYNC;
|
||||
if (method->has_attribute(CACHED_CLASS(MasterAttribute)))
|
||||
return RPC_MODE_MASTER;
|
||||
if (method->has_attribute(CACHED_CLASS(SlaveAttribute)))
|
||||
return RPC_MODE_SLAVE;
|
||||
}
|
||||
if (method && !method->is_static())
|
||||
return _member_get_rpc_mode(method);
|
||||
|
||||
top = top->get_parent_class();
|
||||
}
|
||||
@ -1218,17 +1244,13 @@ ScriptInstance::RPCMode CSharpInstance::get_rset_mode(const StringName &p_variab
|
||||
while (top && top != script->native) {
|
||||
GDMonoField *field = top->get_field(p_variable);
|
||||
|
||||
if (field) { // TODO should we reject static fields?
|
||||
// TODO cache result
|
||||
if (field->has_attribute(CACHED_CLASS(RemoteAttribute)))
|
||||
return RPC_MODE_REMOTE;
|
||||
if (field->has_attribute(CACHED_CLASS(SyncAttribute)))
|
||||
return RPC_MODE_SYNC;
|
||||
if (field->has_attribute(CACHED_CLASS(MasterAttribute)))
|
||||
return RPC_MODE_MASTER;
|
||||
if (field->has_attribute(CACHED_CLASS(SlaveAttribute)))
|
||||
return RPC_MODE_SLAVE;
|
||||
}
|
||||
if (field && !field->is_static())
|
||||
return _member_get_rpc_mode(field);
|
||||
|
||||
GDMonoProperty *property = top->get_property(p_variable);
|
||||
|
||||
if (property && !property->is_static())
|
||||
return _member_get_rpc_mode(property);
|
||||
|
||||
top = top->get_parent_class();
|
||||
}
|
||||
@ -1353,7 +1375,7 @@ bool CSharpScript::_update_exports() {
|
||||
// We are creating a temporary new instance of the class here to get the default value
|
||||
// TODO Workaround. Should be replaced with IL opcodes analysis
|
||||
|
||||
MonoObject *tmp_object = mono_object_new(SCRIPTS_DOMAIN, script_class->get_raw());
|
||||
MonoObject *tmp_object = mono_object_new(SCRIPTS_DOMAIN, script_class->get_mono_ptr());
|
||||
|
||||
if (tmp_object) {
|
||||
CACHED_FIELD(GodotObject, ptr)->set_value_raw(tmp_object, tmp_object); // FIXME WTF is this workaround
|
||||
@ -1376,65 +1398,55 @@ bool CSharpScript::_update_exports() {
|
||||
GDMonoClass *top = script_class;
|
||||
|
||||
while (top && top != native) {
|
||||
PropertyInfo prop_info;
|
||||
bool exported;
|
||||
|
||||
const Vector<GDMonoField *> &fields = top->get_all_fields();
|
||||
|
||||
for (int i = fields.size() - 1; i >= 0; i--) {
|
||||
GDMonoField *field = fields[i];
|
||||
|
||||
if (field->is_static()) {
|
||||
if (field->has_attribute(CACHED_CLASS(ExportAttribute)))
|
||||
ERR_PRINTS("Cannot export field because it is static: " + top->get_full_name() + "." + field->get_name());
|
||||
continue;
|
||||
}
|
||||
if (_get_member_export(top, field, prop_info, exported)) {
|
||||
StringName name = field->get_name();
|
||||
|
||||
String name = field->get_name();
|
||||
StringName cname = name;
|
||||
if (exported) {
|
||||
member_info[name] = prop_info;
|
||||
exported_members_cache.push_front(prop_info);
|
||||
|
||||
if (member_info.has(cname))
|
||||
continue;
|
||||
|
||||
ManagedType field_type = field->get_type();
|
||||
Variant::Type type = GDMonoMarshal::managed_to_variant_type(field_type);
|
||||
|
||||
if (field->has_attribute(CACHED_CLASS(ExportAttribute))) {
|
||||
// Field has Export attribute
|
||||
MonoObject *attr = field->get_attribute(CACHED_CLASS(ExportAttribute));
|
||||
|
||||
PropertyHint hint;
|
||||
String hint_string;
|
||||
|
||||
if (type == Variant::NIL) {
|
||||
ERR_PRINTS("Unknown type of exported field: " + top->get_full_name() + "." + field->get_name());
|
||||
continue;
|
||||
} else if (type == Variant::INT && field_type.type_encoding == MONO_TYPE_VALUETYPE && mono_class_is_enum(field_type.type_class->get_raw())) {
|
||||
type = Variant::INT;
|
||||
hint = PROPERTY_HINT_ENUM;
|
||||
|
||||
Vector<MonoClassField *> fields = field_type.type_class->get_enum_fields();
|
||||
|
||||
for (int i = 0; i < fields.size(); i++) {
|
||||
if (i > 0)
|
||||
hint_string += ",";
|
||||
hint_string += mono_field_get_name(fields[i]);
|
||||
if (tmp_object) {
|
||||
exported_members_defval_cache[name] = GDMonoMarshal::mono_object_to_variant(field->get_value(tmp_object));
|
||||
}
|
||||
} else if (type == Variant::OBJECT && CACHED_CLASS(GodotReference)->is_assignable_from(field_type.type_class)) {
|
||||
hint = PROPERTY_HINT_RESOURCE_TYPE;
|
||||
hint_string = NATIVE_GDMONOCLASS_NAME(field_type.type_class);
|
||||
} else {
|
||||
hint = PropertyHint(CACHED_FIELD(ExportAttribute, hint)->get_int_value(attr));
|
||||
hint_string = CACHED_FIELD(ExportAttribute, hintString)->get_string_value(attr);
|
||||
member_info[name] = prop_info;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PropertyInfo prop_info = PropertyInfo(type, name, hint, hint_string, PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE);
|
||||
const Vector<GDMonoProperty *> &properties = top->get_all_properties();
|
||||
|
||||
member_info[cname] = prop_info;
|
||||
exported_members_cache.push_front(prop_info);
|
||||
for (int i = properties.size() - 1; i >= 0; i--) {
|
||||
GDMonoProperty *property = properties[i];
|
||||
|
||||
if (tmp_object) {
|
||||
exported_members_defval_cache[cname] = GDMonoMarshal::mono_object_to_variant(field->get_value(tmp_object));
|
||||
if (_get_member_export(top, property, prop_info, exported)) {
|
||||
StringName name = property->get_name();
|
||||
|
||||
if (exported) {
|
||||
member_info[name] = prop_info;
|
||||
exported_members_cache.push_front(prop_info);
|
||||
|
||||
if (tmp_object) {
|
||||
MonoObject *exc = NULL;
|
||||
MonoObject *ret = property->get_value(tmp_object, &exc);
|
||||
if (exc) {
|
||||
exported_members_defval_cache[name] = Variant();
|
||||
GDMonoUtils::print_unhandled_exception(exc);
|
||||
} else {
|
||||
exported_members_defval_cache[name] = GDMonoMarshal::mono_object_to_variant(ret);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
member_info[name] = prop_info;
|
||||
}
|
||||
} else {
|
||||
member_info[cname] = PropertyInfo(type, name, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_SCRIPT_VARIABLE);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1458,6 +1470,77 @@ bool CSharpScript::_update_exports() {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CSharpScript::_get_member_export(GDMonoClass *p_class, GDMonoClassMember *p_member, PropertyInfo &r_prop_info, bool &r_exported) {
|
||||
|
||||
StringName name = p_member->get_name();
|
||||
|
||||
if (p_member->is_static()) {
|
||||
if (p_member->has_attribute(CACHED_CLASS(ExportAttribute)))
|
||||
ERR_PRINTS("Cannot export member because it is static: " + p_class->get_full_name() + "." + name.operator String());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (member_info.has(name))
|
||||
return false;
|
||||
|
||||
ManagedType type;
|
||||
|
||||
if (p_member->get_member_type() == GDMonoClassMember::MEMBER_TYPE_FIELD) {
|
||||
type = static_cast<GDMonoField *>(p_member)->get_type();
|
||||
} else if (p_member->get_member_type() == GDMonoClassMember::MEMBER_TYPE_PROPERTY) {
|
||||
type = static_cast<GDMonoProperty *>(p_member)->get_type();
|
||||
} else {
|
||||
CRASH_NOW();
|
||||
}
|
||||
|
||||
Variant::Type variant_type = GDMonoMarshal::managed_to_variant_type(type);
|
||||
|
||||
if (p_member->has_attribute(CACHED_CLASS(ExportAttribute))) {
|
||||
if (p_member->get_member_type() == GDMonoClassMember::MEMBER_TYPE_PROPERTY) {
|
||||
GDMonoProperty *property = static_cast<GDMonoProperty *>(p_member);
|
||||
if (!property->has_getter() || !property->has_setter()) {
|
||||
ERR_PRINTS("Cannot export property because it does not provide a getter or a setter: " + p_class->get_full_name() + "." + name.operator String());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
MonoObject *attr = p_member->get_attribute(CACHED_CLASS(ExportAttribute));
|
||||
|
||||
PropertyHint hint;
|
||||
String hint_string;
|
||||
|
||||
if (variant_type == Variant::NIL) {
|
||||
ERR_PRINTS("Unknown type of exported member: " + p_class->get_full_name() + "." + name.operator String());
|
||||
return false;
|
||||
} else if (variant_type == Variant::INT && type.type_encoding == MONO_TYPE_VALUETYPE && mono_class_is_enum(type.type_class->get_mono_ptr())) {
|
||||
variant_type = Variant::INT;
|
||||
hint = PROPERTY_HINT_ENUM;
|
||||
|
||||
Vector<MonoClassField *> fields = type.type_class->get_enum_fields();
|
||||
|
||||
for (int i = 0; i < fields.size(); i++) {
|
||||
if (i > 0)
|
||||
hint_string += ",";
|
||||
hint_string += mono_field_get_name(fields[i]);
|
||||
}
|
||||
} else if (variant_type == Variant::OBJECT && CACHED_CLASS(GodotReference)->is_assignable_from(type.type_class)) {
|
||||
hint = PROPERTY_HINT_RESOURCE_TYPE;
|
||||
hint_string = NATIVE_GDMONOCLASS_NAME(type.type_class);
|
||||
} else {
|
||||
hint = PropertyHint(CACHED_FIELD(ExportAttribute, hint)->get_int_value(attr));
|
||||
hint_string = CACHED_FIELD(ExportAttribute, hintString)->get_string_value(attr);
|
||||
}
|
||||
|
||||
r_prop_info = PropertyInfo(variant_type, name.operator String(), hint, hint_string, PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE);
|
||||
r_exported = true;
|
||||
} else {
|
||||
r_prop_info = PropertyInfo(variant_type, name.operator String(), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_SCRIPT_VARIABLE);
|
||||
r_exported = false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CSharpScript::_clear() {
|
||||
|
||||
tool = false;
|
||||
@ -1626,7 +1709,7 @@ CSharpInstance *CSharpScript::_create_instance(const Variant **p_args, int p_arg
|
||||
|
||||
/* STEP 2, INITIALIZE AND CONSTRUCT */
|
||||
|
||||
MonoObject *mono_object = mono_object_new(SCRIPTS_DOMAIN, script_class->get_raw());
|
||||
MonoObject *mono_object = mono_object_new(SCRIPTS_DOMAIN, script_class->get_mono_ptr());
|
||||
|
||||
if (!mono_object) {
|
||||
instance->script = Ref<CSharpScript>();
|
||||
|
@ -104,6 +104,8 @@ class CSharpScript : public Script {
|
||||
void _clear();
|
||||
|
||||
bool _update_exports();
|
||||
bool _get_member_export(GDMonoClass *p_class, GDMonoClassMember *p_member, PropertyInfo &r_prop_info, bool &r_exported);
|
||||
|
||||
CSharpInstance *_create_instance(const Variant **p_args, int p_argcount, Object *p_owner, bool p_isref, Variant::CallError &r_error);
|
||||
Variant _new(const Variant **p_args, int p_argcount, Variant::CallError &r_error);
|
||||
|
||||
@ -178,6 +180,8 @@ class CSharpInstance : public ScriptInstance {
|
||||
|
||||
void _call_multilevel(MonoObject *p_mono_object, const StringName &p_method, const Variant **p_args, int p_argcount);
|
||||
|
||||
RPCMode _member_get_rpc_mode(GDMonoClassMember *p_member) const;
|
||||
|
||||
public:
|
||||
MonoObject *get_mono_object() const;
|
||||
|
||||
|
@ -446,7 +446,7 @@ void GodotSharpBuilds::BuildProcess::start(bool p_blocking) {
|
||||
|
||||
GDMonoClass *klass = GDMono::get_singleton()->get_editor_tools_assembly()->get_class("GodotSharpTools.Build", "BuildInstance");
|
||||
|
||||
MonoObject *mono_object = mono_object_new(mono_domain_get(), klass->get_raw());
|
||||
MonoObject *mono_object = mono_object_new(mono_domain_get(), klass->get_mono_ptr());
|
||||
|
||||
// Construct
|
||||
|
||||
|
@ -62,7 +62,7 @@ MonoDevelopInstance::MonoDevelopInstance(const String &p_solution) {
|
||||
|
||||
GDMonoClass *klass = GDMono::get_singleton()->get_editor_tools_assembly()->get_class("GodotSharpTools.Editor", "MonoDevelopInstance");
|
||||
|
||||
MonoObject *obj = mono_object_new(TOOLS_DOMAIN, klass->get_raw());
|
||||
MonoObject *obj = mono_object_new(TOOLS_DOMAIN, klass->get_mono_ptr());
|
||||
|
||||
GDMonoMethod *ctor = klass->get_method(".ctor", 1);
|
||||
MonoObject *ex = NULL;
|
||||
|
@ -52,8 +52,7 @@ void gdmono_unhandled_exception_hook(MonoObject *exc, void *user_data) {
|
||||
|
||||
(void)user_data; // UNUSED
|
||||
|
||||
ERR_PRINT(GDMonoUtils::get_exception_name_and_message(exc).utf8());
|
||||
mono_print_unhandled_exception(exc);
|
||||
GDMonoUtils::print_unhandled_exception(exc);
|
||||
abort();
|
||||
}
|
||||
|
||||
|
@ -112,14 +112,6 @@ public:
|
||||
#endif
|
||||
#endif
|
||||
|
||||
enum MemberVisibility {
|
||||
PRIVATE,
|
||||
PROTECTED_AND_INTERNAL, // FAM_AND_ASSEM
|
||||
INTERNAL, // ASSEMBLY
|
||||
PROTECTED, // FAMILY
|
||||
PUBLIC
|
||||
};
|
||||
|
||||
static GDMono *get_singleton() { return singleton; }
|
||||
|
||||
// Do not use these, unless you know what you're doing
|
||||
|
@ -318,7 +318,7 @@ GDMonoClass *GDMonoAssembly::get_object_derived_class(const StringName &p_class)
|
||||
void *iter = NULL;
|
||||
|
||||
while (true) {
|
||||
MonoClass *raw_nested = mono_class_get_nested_types(current_nested->get_raw(), &iter);
|
||||
MonoClass *raw_nested = mono_class_get_nested_types(current_nested->get_mono_ptr(), &iter);
|
||||
|
||||
if (!raw_nested)
|
||||
break;
|
||||
|
@ -35,7 +35,7 @@
|
||||
|
||||
MonoType *GDMonoClass::get_raw_type(GDMonoClass *p_class) {
|
||||
|
||||
return mono_class_get_type(p_class->get_raw());
|
||||
return mono_class_get_type(p_class->get_mono_ptr());
|
||||
}
|
||||
|
||||
bool GDMonoClass::is_assignable_from(GDMonoClass *p_from) const {
|
||||
@ -74,7 +74,7 @@ Vector<MonoClassField *> GDMonoClass::get_enum_fields() {
|
||||
|
||||
void *iter = NULL;
|
||||
MonoClassField *raw_field = NULL;
|
||||
while ((raw_field = mono_class_get_fields(get_raw(), &iter)) != NULL) {
|
||||
while ((raw_field = mono_class_get_fields(get_mono_ptr(), &iter)) != NULL) {
|
||||
uint32_t field_flags = mono_field_get_flags(raw_field);
|
||||
|
||||
// Enums have an instance field named value__ which holds the value of the enum.
|
||||
@ -105,7 +105,7 @@ bool GDMonoClass::has_attribute(GDMonoClass *p_attr_class) {
|
||||
if (!attributes)
|
||||
return false;
|
||||
|
||||
return mono_custom_attrs_has_attr(attributes, p_attr_class->get_raw());
|
||||
return mono_custom_attrs_has_attr(attributes, p_attr_class->get_mono_ptr());
|
||||
}
|
||||
|
||||
MonoObject *GDMonoClass::get_attribute(GDMonoClass *p_attr_class) {
|
||||
@ -120,14 +120,14 @@ MonoObject *GDMonoClass::get_attribute(GDMonoClass *p_attr_class) {
|
||||
if (!attributes)
|
||||
return NULL;
|
||||
|
||||
return mono_custom_attrs_get_attr(attributes, p_attr_class->get_raw());
|
||||
return mono_custom_attrs_get_attr(attributes, p_attr_class->get_mono_ptr());
|
||||
}
|
||||
|
||||
void GDMonoClass::fetch_attributes() {
|
||||
|
||||
ERR_FAIL_COND(attributes != NULL);
|
||||
|
||||
attributes = mono_custom_attrs_from_class(get_raw());
|
||||
attributes = mono_custom_attrs_from_class(get_mono_ptr());
|
||||
attrs_fetched = true;
|
||||
}
|
||||
|
||||
@ -140,7 +140,7 @@ void GDMonoClass::fetch_methods_with_godot_api_checks(GDMonoClass *p_native_base
|
||||
|
||||
void *iter = NULL;
|
||||
MonoMethod *raw_method = NULL;
|
||||
while ((raw_method = mono_class_get_methods(get_raw(), &iter)) != NULL) {
|
||||
while ((raw_method = mono_class_get_methods(get_mono_ptr(), &iter)) != NULL) {
|
||||
StringName name = mono_method_get_name(raw_method);
|
||||
|
||||
GDMonoMethod *method = get_method(raw_method, name);
|
||||
@ -334,7 +334,7 @@ const Vector<GDMonoField *> &GDMonoClass::get_all_fields() {
|
||||
|
||||
void *iter = NULL;
|
||||
MonoClassField *raw_field = NULL;
|
||||
while ((raw_field = mono_class_get_fields(get_raw(), &iter)) != NULL) {
|
||||
while ((raw_field = mono_class_get_fields(mono_class, &iter)) != NULL) {
|
||||
StringName name = mono_field_get_name(raw_field);
|
||||
|
||||
Map<StringName, GDMonoField *>::Element *match = fields.find(name);
|
||||
@ -353,6 +353,54 @@ const Vector<GDMonoField *> &GDMonoClass::get_all_fields() {
|
||||
return fields_list;
|
||||
}
|
||||
|
||||
GDMonoProperty *GDMonoClass::get_property(const StringName &p_name) {
|
||||
|
||||
Map<StringName, GDMonoProperty *>::Element *result = properties.find(p_name);
|
||||
|
||||
if (result)
|
||||
return result->value();
|
||||
|
||||
if (properties_fetched)
|
||||
return NULL;
|
||||
|
||||
MonoProperty *raw_property = mono_class_get_property_from_name(mono_class, String(p_name).utf8().get_data());
|
||||
|
||||
if (raw_property) {
|
||||
GDMonoProperty *property = memnew(GDMonoProperty(raw_property, this));
|
||||
properties.insert(p_name, property);
|
||||
|
||||
return property;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const Vector<GDMonoProperty *> &GDMonoClass::get_all_properties() {
|
||||
|
||||
if (properties_fetched)
|
||||
return properties_list;
|
||||
|
||||
void *iter = NULL;
|
||||
MonoProperty *raw_property = NULL;
|
||||
while ((raw_property = mono_class_get_properties(mono_class, &iter)) != NULL) {
|
||||
StringName name = mono_property_get_name(raw_property);
|
||||
|
||||
Map<StringName, GDMonoProperty *>::Element *match = properties.find(name);
|
||||
|
||||
if (match) {
|
||||
properties_list.push_back(match->get());
|
||||
} else {
|
||||
GDMonoProperty *property = memnew(GDMonoProperty(raw_property, this));
|
||||
properties.insert(name, property);
|
||||
properties_list.push_back(property);
|
||||
}
|
||||
}
|
||||
|
||||
properties_fetched = true;
|
||||
|
||||
return properties_list;
|
||||
}
|
||||
|
||||
GDMonoClass::GDMonoClass(const StringName &p_namespace, const StringName &p_name, MonoClass *p_class, GDMonoAssembly *p_assembly) {
|
||||
|
||||
namespace_name = p_namespace;
|
||||
@ -365,6 +413,7 @@ GDMonoClass::GDMonoClass(const StringName &p_namespace, const StringName &p_name
|
||||
|
||||
methods_fetched = false;
|
||||
fields_fetched = false;
|
||||
properties_fetched = false;
|
||||
}
|
||||
|
||||
GDMonoClass::~GDMonoClass() {
|
||||
@ -377,6 +426,10 @@ GDMonoClass::~GDMonoClass() {
|
||||
memdelete(E->value());
|
||||
}
|
||||
|
||||
for (Map<StringName, GDMonoProperty *>::Element *E = properties.front(); E; E = E->next()) {
|
||||
memdelete(E->value());
|
||||
}
|
||||
|
||||
{
|
||||
// Ugly workaround...
|
||||
// We may have duplicated values, because we redirect snake_case methods to PascalCasel (only Godot API methods).
|
||||
|
@ -38,6 +38,7 @@
|
||||
#include "gd_mono_field.h"
|
||||
#include "gd_mono_header.h"
|
||||
#include "gd_mono_method.h"
|
||||
#include "gd_mono_property.h"
|
||||
#include "gd_mono_utils.h"
|
||||
|
||||
class GDMonoClass {
|
||||
@ -84,6 +85,10 @@ class GDMonoClass {
|
||||
Map<StringName, GDMonoField *> fields;
|
||||
Vector<GDMonoField *> fields_list;
|
||||
|
||||
bool properties_fetched;
|
||||
Map<StringName, GDMonoProperty *> properties;
|
||||
Vector<GDMonoProperty *> properties_list;
|
||||
|
||||
friend class GDMonoAssembly;
|
||||
GDMonoClass(const StringName &p_namespace, const StringName &p_name, MonoClass *p_class, GDMonoAssembly *p_assembly);
|
||||
|
||||
@ -95,7 +100,7 @@ public:
|
||||
_FORCE_INLINE_ StringName get_namespace() const { return namespace_name; }
|
||||
_FORCE_INLINE_ StringName get_name() const { return class_name; }
|
||||
|
||||
_FORCE_INLINE_ MonoClass *get_raw() const { return mono_class; }
|
||||
_FORCE_INLINE_ MonoClass *get_mono_ptr() const { return mono_class; }
|
||||
_FORCE_INLINE_ const GDMonoAssembly *get_assembly() const { return assembly; }
|
||||
|
||||
String get_full_name() const;
|
||||
@ -124,6 +129,9 @@ public:
|
||||
GDMonoField *get_field(const StringName &p_name);
|
||||
const Vector<GDMonoField *> &get_all_fields();
|
||||
|
||||
GDMonoProperty *get_property(const StringName &p_name);
|
||||
const Vector<GDMonoProperty *> &get_all_properties();
|
||||
|
||||
~GDMonoClass();
|
||||
};
|
||||
|
||||
|
67
modules/mono/mono_gd/gd_mono_class_member.h
Normal file
67
modules/mono/mono_gd/gd_mono_class_member.h
Normal file
@ -0,0 +1,67 @@
|
||||
/*************************************************************************/
|
||||
/* gd_mono_class_member.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
#ifndef GD_MONO_CLASS_MEMBER_H
|
||||
#define GD_MONO_CLASS_MEMBER_H
|
||||
|
||||
#include "gd_mono_header.h"
|
||||
|
||||
#include <mono/metadata/object.h>
|
||||
|
||||
class GDMonoClassMember {
|
||||
public:
|
||||
enum Visibility {
|
||||
PRIVATE,
|
||||
PROTECTED_AND_INTERNAL, // FAM_AND_ASSEM
|
||||
INTERNAL, // ASSEMBLY
|
||||
PROTECTED, // FAMILY
|
||||
PUBLIC
|
||||
};
|
||||
|
||||
enum MemberType {
|
||||
MEMBER_TYPE_FIELD,
|
||||
MEMBER_TYPE_PROPERTY,
|
||||
MEMBER_TYPE_METHOD
|
||||
};
|
||||
|
||||
virtual ~GDMonoClassMember() {}
|
||||
|
||||
virtual MemberType get_member_type() = 0;
|
||||
|
||||
virtual StringName get_name() = 0;
|
||||
|
||||
virtual bool is_static() = 0;
|
||||
|
||||
virtual Visibility get_visibility() = 0;
|
||||
|
||||
virtual bool has_attribute(GDMonoClass *p_attr_class) = 0;
|
||||
virtual MonoObject *get_attribute(GDMonoClass *p_attr_class) = 0;
|
||||
};
|
||||
|
||||
#endif // GD_MONO_CLASS_MEMBER_H
|
@ -38,7 +38,7 @@ void GDMonoField::set_value_raw(MonoObject *p_object, void *p_ptr) {
|
||||
mono_field_set_value(p_object, mono_field, &p_ptr);
|
||||
}
|
||||
|
||||
void GDMonoField::set_value(MonoObject *p_object, const Variant &p_value) {
|
||||
void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_value) {
|
||||
#define SET_FROM_STRUCT_AND_BREAK(m_type) \
|
||||
{ \
|
||||
const m_type &val = p_value.operator ::m_type(); \
|
||||
@ -138,7 +138,7 @@ void GDMonoField::set_value(MonoObject *p_object, const Variant &p_value) {
|
||||
if (tclass == CACHED_CLASS(Plane))
|
||||
SET_FROM_STRUCT_AND_BREAK(Plane);
|
||||
|
||||
if (mono_class_is_enum(tclass->get_raw()))
|
||||
if (mono_class_is_enum(tclass->get_mono_ptr()))
|
||||
SET_FROM_PRIMITIVE(signed int);
|
||||
|
||||
ERR_EXPLAIN(String() + "Attempted to set the value of a field of unmarshallable type: " + tclass->get_name());
|
||||
@ -264,7 +264,7 @@ void GDMonoField::set_value(MonoObject *p_object, const Variant &p_value) {
|
||||
} break;
|
||||
|
||||
case MONO_TYPE_GENERICINST: {
|
||||
if (CACHED_RAW_MONO_CLASS(Dictionary) == type.type_class->get_raw()) {
|
||||
if (CACHED_RAW_MONO_CLASS(Dictionary) == type.type_class->get_mono_ptr()) {
|
||||
MonoObject *managed = GDMonoMarshal::Dictionary_to_mono_object(p_value.operator Dictionary());
|
||||
mono_field_set_value(p_object, mono_field, managed);
|
||||
break;
|
||||
@ -280,6 +280,10 @@ void GDMonoField::set_value(MonoObject *p_object, const Variant &p_value) {
|
||||
#undef SET_FROM_PRIMITIVE
|
||||
}
|
||||
|
||||
MonoObject *GDMonoField::get_value(MonoObject *p_object) {
|
||||
return mono_field_get_value_object(mono_domain_get(), mono_field, p_object);
|
||||
}
|
||||
|
||||
bool GDMonoField::get_bool_value(MonoObject *p_object) {
|
||||
return (bool)GDMonoMarshal::unbox<MonoBoolean>(get_value(p_object));
|
||||
}
|
||||
@ -302,7 +306,7 @@ bool GDMonoField::has_attribute(GDMonoClass *p_attr_class) {
|
||||
if (!attributes)
|
||||
return false;
|
||||
|
||||
return mono_custom_attrs_has_attr(attributes, p_attr_class->get_raw());
|
||||
return mono_custom_attrs_has_attr(attributes, p_attr_class->get_mono_ptr());
|
||||
}
|
||||
|
||||
MonoObject *GDMonoField::get_attribute(GDMonoClass *p_attr_class) {
|
||||
@ -314,12 +318,12 @@ MonoObject *GDMonoField::get_attribute(GDMonoClass *p_attr_class) {
|
||||
if (!attributes)
|
||||
return NULL;
|
||||
|
||||
return mono_custom_attrs_get_attr(attributes, p_attr_class->get_raw());
|
||||
return mono_custom_attrs_get_attr(attributes, p_attr_class->get_mono_ptr());
|
||||
}
|
||||
|
||||
void GDMonoField::fetch_attributes() {
|
||||
ERR_FAIL_COND(attributes != NULL);
|
||||
attributes = mono_custom_attrs_from_field(owner->get_raw(), get_raw());
|
||||
attributes = mono_custom_attrs_from_field(owner->get_mono_ptr(), mono_field);
|
||||
attrs_fetched = true;
|
||||
}
|
||||
|
||||
@ -327,26 +331,26 @@ bool GDMonoField::is_static() {
|
||||
return mono_field_get_flags(mono_field) & MONO_FIELD_ATTR_STATIC;
|
||||
}
|
||||
|
||||
GDMono::MemberVisibility GDMonoField::get_visibility() {
|
||||
GDMonoClassMember::Visibility GDMonoField::get_visibility() {
|
||||
switch (mono_field_get_flags(mono_field) & MONO_FIELD_ATTR_FIELD_ACCESS_MASK) {
|
||||
case MONO_FIELD_ATTR_PRIVATE:
|
||||
return GDMono::PRIVATE;
|
||||
return GDMonoClassMember::PRIVATE;
|
||||
case MONO_FIELD_ATTR_FAM_AND_ASSEM:
|
||||
return GDMono::PROTECTED_AND_INTERNAL;
|
||||
return GDMonoClassMember::PROTECTED_AND_INTERNAL;
|
||||
case MONO_FIELD_ATTR_ASSEMBLY:
|
||||
return GDMono::INTERNAL;
|
||||
return GDMonoClassMember::INTERNAL;
|
||||
case MONO_FIELD_ATTR_FAMILY:
|
||||
return GDMono::PROTECTED;
|
||||
return GDMonoClassMember::PROTECTED;
|
||||
case MONO_FIELD_ATTR_PUBLIC:
|
||||
return GDMono::PUBLIC;
|
||||
return GDMonoClassMember::PUBLIC;
|
||||
default:
|
||||
ERR_FAIL_V(GDMono::PRIVATE);
|
||||
ERR_FAIL_V(GDMonoClassMember::PRIVATE);
|
||||
}
|
||||
}
|
||||
|
||||
GDMonoField::GDMonoField(MonoClassField *p_raw_field, GDMonoClass *p_owner) {
|
||||
GDMonoField::GDMonoField(MonoClassField *p_mono_field, GDMonoClass *p_owner) {
|
||||
owner = p_owner;
|
||||
mono_field = p_raw_field;
|
||||
mono_field = p_mono_field;
|
||||
name = mono_field_get_name(mono_field);
|
||||
MonoType *field_type = mono_field_get_type(mono_field);
|
||||
type.type_encoding = mono_type_get_type(field_type);
|
||||
|
@ -31,43 +31,44 @@
|
||||
#define GDMONOFIELD_H
|
||||
|
||||
#include "gd_mono.h"
|
||||
#include "gd_mono_class_member.h"
|
||||
#include "gd_mono_header.h"
|
||||
|
||||
class GDMonoField {
|
||||
class GDMonoField : public GDMonoClassMember {
|
||||
|
||||
GDMonoClass *owner;
|
||||
MonoClassField *mono_field;
|
||||
|
||||
String name;
|
||||
StringName name;
|
||||
ManagedType type;
|
||||
|
||||
bool attrs_fetched;
|
||||
MonoCustomAttrInfo *attributes;
|
||||
|
||||
public:
|
||||
_FORCE_INLINE_ String get_name() const { return name; }
|
||||
virtual MemberType get_member_type() { return MEMBER_TYPE_FIELD; }
|
||||
|
||||
virtual StringName get_name() { return name; }
|
||||
|
||||
virtual bool is_static();
|
||||
virtual Visibility get_visibility();
|
||||
|
||||
virtual bool has_attribute(GDMonoClass *p_attr_class);
|
||||
virtual MonoObject *get_attribute(GDMonoClass *p_attr_class);
|
||||
void fetch_attributes();
|
||||
|
||||
_FORCE_INLINE_ ManagedType get_type() const { return type; }
|
||||
|
||||
_FORCE_INLINE_ MonoClassField *get_raw() const { return mono_field; }
|
||||
|
||||
void set_value_raw(MonoObject *p_object, void *p_ptr);
|
||||
void set_value(MonoObject *p_object, const Variant &p_value);
|
||||
void set_value_from_variant(MonoObject *p_object, const Variant &p_value);
|
||||
|
||||
_FORCE_INLINE_ MonoObject *get_value(MonoObject *p_object) {
|
||||
return mono_field_get_value_object(mono_domain_get(), mono_field, p_object);
|
||||
}
|
||||
_FORCE_INLINE_ MonoObject *get_value(MonoObject *p_object);
|
||||
|
||||
bool get_bool_value(MonoObject *p_object);
|
||||
int get_int_value(MonoObject *p_object);
|
||||
String get_string_value(MonoObject *p_object);
|
||||
|
||||
bool has_attribute(GDMonoClass *p_attr_class);
|
||||
MonoObject *get_attribute(GDMonoClass *p_attr_class);
|
||||
void fetch_attributes();
|
||||
|
||||
bool is_static();
|
||||
GDMono::MemberVisibility get_visibility();
|
||||
|
||||
GDMonoField(MonoClassField *p_raw_field, GDMonoClass *p_owner);
|
||||
GDMonoField(MonoClassField *p_mono_field, GDMonoClass *p_owner);
|
||||
~GDMonoField();
|
||||
};
|
||||
|
||||
|
@ -34,8 +34,10 @@
|
||||
|
||||
class GDMonoAssembly;
|
||||
class GDMonoClass;
|
||||
class GDMonoMethod;
|
||||
class GDMonoClassMember;
|
||||
class GDMonoField;
|
||||
class GDMonoProperty;
|
||||
class GDMonoMethod;
|
||||
|
||||
struct ManagedType {
|
||||
int type_encoding;
|
||||
|
@ -113,7 +113,7 @@ Variant::Type managed_to_variant_type(const ManagedType &p_type) {
|
||||
if (tclass == CACHED_CLASS(Plane))
|
||||
return Variant::PLANE;
|
||||
|
||||
if (mono_class_is_enum(tclass->get_raw()))
|
||||
if (mono_class_is_enum(tclass->get_mono_ptr()))
|
||||
return Variant::INT;
|
||||
} break;
|
||||
|
||||
@ -164,7 +164,7 @@ Variant::Type managed_to_variant_type(const ManagedType &p_type) {
|
||||
} break;
|
||||
|
||||
case MONO_TYPE_GENERICINST: {
|
||||
if (CACHED_RAW_MONO_CLASS(Dictionary) == p_type.type_class->get_raw()) {
|
||||
if (CACHED_RAW_MONO_CLASS(Dictionary) == p_type.type_class->get_mono_ptr()) {
|
||||
return Variant::DICTIONARY;
|
||||
}
|
||||
} break;
|
||||
@ -306,9 +306,9 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty
|
||||
if (tclass == CACHED_CLASS(Plane))
|
||||
RETURN_BOXED_STRUCT(Plane, p_var);
|
||||
|
||||
if (mono_class_is_enum(tclass->get_raw())) {
|
||||
if (mono_class_is_enum(tclass->get_mono_ptr())) {
|
||||
int val = p_var->operator signed int();
|
||||
return BOX_ENUM(tclass->get_raw(), val);
|
||||
return BOX_ENUM(tclass->get_mono_ptr(), val);
|
||||
}
|
||||
} break;
|
||||
|
||||
@ -432,7 +432,7 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty
|
||||
}
|
||||
break;
|
||||
case MONO_TYPE_GENERICINST: {
|
||||
if (CACHED_RAW_MONO_CLASS(Dictionary) == p_type.type_class->get_raw()) {
|
||||
if (CACHED_RAW_MONO_CLASS(Dictionary) == p_type.type_class->get_mono_ptr()) {
|
||||
return Dictionary_to_mono_object(p_var->operator Dictionary());
|
||||
}
|
||||
} break;
|
||||
@ -528,7 +528,7 @@ Variant mono_object_to_variant(MonoObject *p_obj, const ManagedType &p_type) {
|
||||
if (tclass == CACHED_CLASS(Plane))
|
||||
RETURN_UNBOXED_STRUCT(Plane, p_obj);
|
||||
|
||||
if (mono_class_is_enum(tclass->get_raw()))
|
||||
if (mono_class_is_enum(tclass->get_mono_ptr()))
|
||||
return unbox<int32_t>(p_obj);
|
||||
} break;
|
||||
|
||||
@ -585,7 +585,7 @@ Variant mono_object_to_variant(MonoObject *p_obj, const ManagedType &p_type) {
|
||||
} break;
|
||||
|
||||
case MONO_TYPE_GENERICINST: {
|
||||
if (CACHED_RAW_MONO_CLASS(Dictionary) == p_type.type_class->get_raw()) {
|
||||
if (CACHED_RAW_MONO_CLASS(Dictionary) == p_type.type_class->get_mono_ptr()) {
|
||||
return mono_object_to_Dictionary(p_obj);
|
||||
}
|
||||
} break;
|
||||
|
@ -32,6 +32,8 @@
|
||||
#include "gd_mono_class.h"
|
||||
#include "gd_mono_marshal.h"
|
||||
|
||||
#include <mono/metadata/attrdefs.h>
|
||||
|
||||
void GDMonoMethod::_update_signature() {
|
||||
// Apparently MonoMethodSignature needs not to be freed.
|
||||
// mono_method_signature caches the result, we don't need to cache it ourselves.
|
||||
@ -41,7 +43,6 @@ void GDMonoMethod::_update_signature() {
|
||||
}
|
||||
|
||||
void GDMonoMethod::_update_signature(MonoMethodSignature *p_method_sig) {
|
||||
is_instance = mono_signature_is_instance(p_method_sig);
|
||||
params_count = mono_signature_get_param_count(p_method_sig);
|
||||
|
||||
MonoType *ret_type = mono_signature_get_return_type(p_method_sig);
|
||||
@ -61,15 +62,34 @@ void GDMonoMethod::_update_signature(MonoMethodSignature *p_method_sig) {
|
||||
|
||||
param_type.type_encoding = mono_type_get_type(param_raw_type);
|
||||
|
||||
if (param_type.type_encoding != MONO_TYPE_VOID) {
|
||||
MonoClass *param_type_class = mono_class_from_mono_type(param_raw_type);
|
||||
param_type.type_class = GDMono::get_singleton()->get_class(param_type_class);
|
||||
}
|
||||
MonoClass *param_type_class = mono_class_from_mono_type(param_raw_type);
|
||||
param_type.type_class = GDMono::get_singleton()->get_class(param_type_class);
|
||||
|
||||
param_types.push_back(param_type);
|
||||
}
|
||||
}
|
||||
|
||||
bool GDMonoMethod::is_static() {
|
||||
return mono_method_get_flags(mono_method, NULL) & MONO_METHOD_ATTR_STATIC;
|
||||
}
|
||||
|
||||
GDMonoClassMember::Visibility GDMonoMethod::get_visibility() {
|
||||
switch (mono_method_get_flags(mono_method, NULL) & MONO_METHOD_ATTR_ACCESS_MASK) {
|
||||
case MONO_METHOD_ATTR_PRIVATE:
|
||||
return GDMonoClassMember::PRIVATE;
|
||||
case MONO_METHOD_ATTR_FAM_AND_ASSEM:
|
||||
return GDMonoClassMember::PROTECTED_AND_INTERNAL;
|
||||
case MONO_METHOD_ATTR_ASSEM:
|
||||
return GDMonoClassMember::INTERNAL;
|
||||
case MONO_METHOD_ATTR_FAMILY:
|
||||
return GDMonoClassMember::PROTECTED;
|
||||
case MONO_METHOD_ATTR_PUBLIC:
|
||||
return GDMonoClassMember::PUBLIC;
|
||||
default:
|
||||
ERR_FAIL_V(GDMonoClassMember::PRIVATE);
|
||||
}
|
||||
}
|
||||
|
||||
void *GDMonoMethod::get_thunk() {
|
||||
return mono_method_get_unmanaged_thunk(mono_method);
|
||||
}
|
||||
@ -87,11 +107,11 @@ MonoObject *GDMonoMethod::invoke(MonoObject *p_object, const Variant **p_params,
|
||||
MonoObject *ret = mono_runtime_invoke_array(mono_method, p_object, params, &exc);
|
||||
|
||||
if (exc) {
|
||||
ret = NULL;
|
||||
if (r_exc) {
|
||||
*r_exc = exc;
|
||||
} else {
|
||||
ERR_PRINT(GDMonoUtils::get_exception_name_and_message(exc).utf8());
|
||||
mono_print_unhandled_exception(exc);
|
||||
GDMonoUtils::print_unhandled_exception(exc);
|
||||
}
|
||||
}
|
||||
|
||||
@ -104,8 +124,7 @@ MonoObject *GDMonoMethod::invoke(MonoObject *p_object, const Variant **p_params,
|
||||
if (r_exc) {
|
||||
*r_exc = exc;
|
||||
} else {
|
||||
ERR_PRINT(GDMonoUtils::get_exception_name_and_message(exc).utf8());
|
||||
mono_print_unhandled_exception(exc);
|
||||
GDMonoUtils::print_unhandled_exception(exc);
|
||||
}
|
||||
}
|
||||
|
||||
@ -123,11 +142,11 @@ MonoObject *GDMonoMethod::invoke_raw(MonoObject *p_object, void **p_params, Mono
|
||||
MonoObject *ret = mono_runtime_invoke(mono_method, p_object, p_params, &exc);
|
||||
|
||||
if (exc) {
|
||||
ret = NULL;
|
||||
if (r_exc) {
|
||||
*r_exc = exc;
|
||||
} else {
|
||||
ERR_PRINT(GDMonoUtils::get_exception_name_and_message(exc).utf8());
|
||||
mono_print_unhandled_exception(exc);
|
||||
GDMonoUtils::print_unhandled_exception(exc);
|
||||
}
|
||||
}
|
||||
|
||||
@ -143,7 +162,7 @@ bool GDMonoMethod::has_attribute(GDMonoClass *p_attr_class) {
|
||||
if (!attributes)
|
||||
return false;
|
||||
|
||||
return mono_custom_attrs_has_attr(attributes, p_attr_class->get_raw());
|
||||
return mono_custom_attrs_has_attr(attributes, p_attr_class->get_mono_ptr());
|
||||
}
|
||||
|
||||
MonoObject *GDMonoMethod::get_attribute(GDMonoClass *p_attr_class) {
|
||||
@ -155,7 +174,7 @@ MonoObject *GDMonoMethod::get_attribute(GDMonoClass *p_attr_class) {
|
||||
if (!attributes)
|
||||
return NULL;
|
||||
|
||||
return mono_custom_attrs_get_attr(attributes, p_attr_class->get_raw());
|
||||
return mono_custom_attrs_get_attr(attributes, p_attr_class->get_mono_ptr());
|
||||
}
|
||||
|
||||
void GDMonoMethod::fetch_attributes() {
|
||||
|
@ -31,13 +31,13 @@
|
||||
#define GD_MONO_METHOD_H
|
||||
|
||||
#include "gd_mono.h"
|
||||
#include "gd_mono_class_member.h"
|
||||
#include "gd_mono_header.h"
|
||||
|
||||
class GDMonoMethod {
|
||||
class GDMonoMethod : public GDMonoClassMember {
|
||||
|
||||
StringName name;
|
||||
|
||||
bool is_instance;
|
||||
int params_count;
|
||||
ManagedType return_type;
|
||||
Vector<ManagedType> param_types;
|
||||
@ -53,9 +53,18 @@ class GDMonoMethod {
|
||||
MonoMethod *mono_method;
|
||||
|
||||
public:
|
||||
_FORCE_INLINE_ StringName get_name() { return name; }
|
||||
virtual MemberType get_member_type() { return MEMBER_TYPE_METHOD; }
|
||||
|
||||
virtual StringName get_name() { return name; }
|
||||
|
||||
virtual bool is_static();
|
||||
|
||||
virtual Visibility get_visibility();
|
||||
|
||||
virtual bool has_attribute(GDMonoClass *p_attr_class);
|
||||
virtual MonoObject *get_attribute(GDMonoClass *p_attr_class);
|
||||
virtual void fetch_attributes();
|
||||
|
||||
_FORCE_INLINE_ bool is_static() { return !is_instance; }
|
||||
_FORCE_INLINE_ int get_parameters_count() { return params_count; }
|
||||
_FORCE_INLINE_ ManagedType get_return_type() { return return_type; }
|
||||
|
||||
@ -65,10 +74,6 @@ public:
|
||||
MonoObject *invoke(MonoObject *p_object, MonoObject **r_exc = NULL);
|
||||
MonoObject *invoke_raw(MonoObject *p_object, void **p_params, MonoObject **r_exc = NULL);
|
||||
|
||||
bool has_attribute(GDMonoClass *p_attr_class);
|
||||
MonoObject *get_attribute(GDMonoClass *p_attr_class);
|
||||
void fetch_attributes();
|
||||
|
||||
String get_full_name(bool p_signature = false) const;
|
||||
String get_full_name_no_class() const;
|
||||
String get_ret_type_full_name() const;
|
||||
|
199
modules/mono/mono_gd/gd_mono_property.cpp
Normal file
199
modules/mono/mono_gd/gd_mono_property.cpp
Normal file
@ -0,0 +1,199 @@
|
||||
/*************************************************************************/
|
||||
/* gd_mono_property.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
#include "gd_mono_property.h"
|
||||
|
||||
#include "gd_mono_class.h"
|
||||
#include "gd_mono_marshal.h"
|
||||
|
||||
#include <mono/metadata/attrdefs.h>
|
||||
|
||||
GDMonoProperty::GDMonoProperty(MonoProperty *p_mono_property, GDMonoClass *p_owner) {
|
||||
owner = p_owner;
|
||||
mono_property = p_mono_property;
|
||||
name = mono_property_get_name(mono_property);
|
||||
|
||||
MonoMethod *prop_method = mono_property_get_get_method(mono_property);
|
||||
|
||||
if (prop_method) {
|
||||
MonoMethodSignature *getter_sig = mono_method_signature(prop_method);
|
||||
|
||||
MonoType *ret_type = mono_signature_get_return_type(getter_sig);
|
||||
|
||||
type.type_encoding = mono_type_get_type(ret_type);
|
||||
MonoClass *ret_type_class = mono_class_from_mono_type(ret_type);
|
||||
type.type_class = GDMono::get_singleton()->get_class(ret_type_class);
|
||||
} else {
|
||||
prop_method = mono_property_get_set_method(mono_property);
|
||||
|
||||
MonoMethodSignature *setter_sig = mono_method_signature(prop_method);
|
||||
|
||||
void *iter = NULL;
|
||||
MonoType *param_raw_type = mono_signature_get_params(setter_sig, &iter);
|
||||
|
||||
type.type_encoding = mono_type_get_type(param_raw_type);
|
||||
MonoClass *param_type_class = mono_class_from_mono_type(param_raw_type);
|
||||
type.type_class = GDMono::get_singleton()->get_class(param_type_class);
|
||||
}
|
||||
|
||||
attrs_fetched = false;
|
||||
attributes = NULL;
|
||||
}
|
||||
|
||||
GDMonoProperty::~GDMonoProperty() {
|
||||
if (attributes) {
|
||||
mono_custom_attrs_free(attributes);
|
||||
}
|
||||
}
|
||||
|
||||
bool GDMonoProperty::is_static() {
|
||||
MonoMethod *prop_method = mono_property_get_get_method(mono_property);
|
||||
if (prop_method == NULL)
|
||||
prop_method = mono_property_get_set_method(mono_property);
|
||||
return mono_method_get_flags(prop_method, NULL) & MONO_METHOD_ATTR_STATIC;
|
||||
}
|
||||
|
||||
GDMonoClassMember::Visibility GDMonoProperty::get_visibility() {
|
||||
MonoMethod *prop_method = mono_property_get_get_method(mono_property);
|
||||
if (prop_method == NULL)
|
||||
prop_method = mono_property_get_set_method(mono_property);
|
||||
|
||||
switch (mono_method_get_flags(prop_method, NULL) & MONO_METHOD_ATTR_ACCESS_MASK) {
|
||||
case MONO_METHOD_ATTR_PRIVATE:
|
||||
return GDMonoClassMember::PRIVATE;
|
||||
case MONO_METHOD_ATTR_FAM_AND_ASSEM:
|
||||
return GDMonoClassMember::PROTECTED_AND_INTERNAL;
|
||||
case MONO_METHOD_ATTR_ASSEM:
|
||||
return GDMonoClassMember::INTERNAL;
|
||||
case MONO_METHOD_ATTR_FAMILY:
|
||||
return GDMonoClassMember::PROTECTED;
|
||||
case MONO_METHOD_ATTR_PUBLIC:
|
||||
return GDMonoClassMember::PUBLIC;
|
||||
default:
|
||||
ERR_FAIL_V(GDMonoClassMember::PRIVATE);
|
||||
}
|
||||
}
|
||||
|
||||
bool GDMonoProperty::has_attribute(GDMonoClass *p_attr_class) {
|
||||
ERR_FAIL_NULL_V(p_attr_class, false);
|
||||
|
||||
if (!attrs_fetched)
|
||||
fetch_attributes();
|
||||
|
||||
if (!attributes)
|
||||
return false;
|
||||
|
||||
return mono_custom_attrs_has_attr(attributes, p_attr_class->get_mono_ptr());
|
||||
}
|
||||
|
||||
MonoObject *GDMonoProperty::get_attribute(GDMonoClass *p_attr_class) {
|
||||
ERR_FAIL_NULL_V(p_attr_class, NULL);
|
||||
|
||||
if (!attrs_fetched)
|
||||
fetch_attributes();
|
||||
|
||||
if (!attributes)
|
||||
return NULL;
|
||||
|
||||
return mono_custom_attrs_get_attr(attributes, p_attr_class->get_mono_ptr());
|
||||
}
|
||||
|
||||
void GDMonoProperty::fetch_attributes() {
|
||||
ERR_FAIL_COND(attributes != NULL);
|
||||
attributes = mono_custom_attrs_from_property(owner->get_mono_ptr(), mono_property);
|
||||
attrs_fetched = true;
|
||||
}
|
||||
|
||||
bool GDMonoProperty::has_getter() {
|
||||
return mono_property_get_get_method(mono_property) != NULL;
|
||||
}
|
||||
|
||||
bool GDMonoProperty::has_setter() {
|
||||
return mono_property_get_set_method(mono_property) != NULL;
|
||||
}
|
||||
|
||||
void GDMonoProperty::set_value(MonoObject *p_object, MonoObject *p_value, MonoObject **r_exc) {
|
||||
MonoMethod *prop_method = mono_property_get_get_method(mono_property);
|
||||
|
||||
MonoArray *params = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(MonoObject), 1);
|
||||
mono_array_set(params, MonoObject *, 0, p_value);
|
||||
|
||||
MonoObject *exc = NULL;
|
||||
mono_runtime_invoke_array(prop_method, p_object, params, &exc);
|
||||
|
||||
if (exc) {
|
||||
if (r_exc) {
|
||||
*r_exc = exc;
|
||||
} else {
|
||||
GDMonoUtils::print_unhandled_exception(exc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GDMonoProperty::set_value(MonoObject *p_object, void **p_params, MonoObject **r_exc) {
|
||||
MonoObject *exc = NULL;
|
||||
mono_property_set_value(mono_property, p_object, p_params, &exc);
|
||||
|
||||
if (exc) {
|
||||
if (r_exc) {
|
||||
*r_exc = exc;
|
||||
} else {
|
||||
GDMonoUtils::print_unhandled_exception(exc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MonoObject *GDMonoProperty::get_value(MonoObject *p_object, MonoObject **r_exc) {
|
||||
MonoObject *exc = NULL;
|
||||
MonoObject *ret = mono_property_get_value(mono_property, p_object, NULL, &exc);
|
||||
|
||||
if (exc) {
|
||||
ret = NULL;
|
||||
if (r_exc) {
|
||||
*r_exc = exc;
|
||||
} else {
|
||||
GDMonoUtils::print_unhandled_exception(exc);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool GDMonoProperty::get_bool_value(MonoObject *p_object) {
|
||||
return (bool)GDMonoMarshal::unbox<MonoBoolean>(get_value(p_object));
|
||||
}
|
||||
|
||||
int GDMonoProperty::get_int_value(MonoObject *p_object) {
|
||||
return GDMonoMarshal::unbox<int32_t>(get_value(p_object));
|
||||
}
|
||||
|
||||
String GDMonoProperty::get_string_value(MonoObject *p_object) {
|
||||
MonoObject *val = get_value(p_object);
|
||||
return GDMonoMarshal::mono_string_to_godot((MonoString *)val);
|
||||
}
|
77
modules/mono/mono_gd/gd_mono_property.h
Normal file
77
modules/mono/mono_gd/gd_mono_property.h
Normal file
@ -0,0 +1,77 @@
|
||||
/*************************************************************************/
|
||||
/* gd_mono_property.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
#ifndef GD_MONO_PROPERTY_H
|
||||
#define GD_MONO_PROPERTY_H
|
||||
|
||||
#include "gd_mono.h"
|
||||
#include "gd_mono_class_member.h"
|
||||
#include "gd_mono_header.h"
|
||||
|
||||
class GDMonoProperty : public GDMonoClassMember {
|
||||
|
||||
GDMonoClass *owner;
|
||||
MonoProperty *mono_property;
|
||||
|
||||
StringName name;
|
||||
ManagedType type;
|
||||
|
||||
bool attrs_fetched;
|
||||
MonoCustomAttrInfo *attributes;
|
||||
|
||||
public:
|
||||
virtual MemberType get_member_type() { return MEMBER_TYPE_PROPERTY; }
|
||||
|
||||
virtual StringName get_name() { return name; }
|
||||
|
||||
virtual bool is_static();
|
||||
virtual Visibility get_visibility();
|
||||
|
||||
virtual bool has_attribute(GDMonoClass *p_attr_class);
|
||||
virtual MonoObject *get_attribute(GDMonoClass *p_attr_class);
|
||||
void fetch_attributes();
|
||||
|
||||
bool has_getter();
|
||||
bool has_setter();
|
||||
|
||||
_FORCE_INLINE_ ManagedType get_type() const { return type; }
|
||||
|
||||
void set_value(MonoObject *p_object, MonoObject *p_value, MonoObject **r_exc = NULL);
|
||||
void set_value(MonoObject *p_object, void **p_params, MonoObject **r_exc = NULL);
|
||||
MonoObject *get_value(MonoObject *p_object, MonoObject **r_exc = NULL);
|
||||
|
||||
bool get_bool_value(MonoObject *p_object);
|
||||
int get_int_value(MonoObject *p_object);
|
||||
String get_string_value(MonoObject *p_object);
|
||||
|
||||
GDMonoProperty(MonoProperty *p_mono_property, GDMonoClass *p_owner);
|
||||
~GDMonoProperty();
|
||||
};
|
||||
|
||||
#endif // GD_MONO_PROPERTY_H
|
@ -198,7 +198,7 @@ void update_godot_api_cache() {
|
||||
CACHE_RAW_MONO_CLASS_AND_CHECK(Dictionary, mono_class_from_mono_type(dict_type));
|
||||
}
|
||||
|
||||
MonoObject *task_scheduler = mono_object_new(SCRIPTS_DOMAIN, GODOT_API_CLASS(GodotTaskScheduler)->get_raw());
|
||||
MonoObject *task_scheduler = mono_object_new(SCRIPTS_DOMAIN, GODOT_API_CLASS(GodotTaskScheduler)->get_mono_ptr());
|
||||
mono_runtime_object_init(task_scheduler);
|
||||
mono_cache.task_scheduler_handle = MonoGCHandle::create_strong(task_scheduler);
|
||||
}
|
||||
@ -298,7 +298,7 @@ MonoObject *create_managed_for_godot_object(GDMonoClass *p_class, const StringNa
|
||||
ERR_FAIL_V(NULL);
|
||||
}
|
||||
|
||||
MonoObject *mono_object = mono_object_new(SCRIPTS_DOMAIN, p_class->get_raw());
|
||||
MonoObject *mono_object = mono_object_new(SCRIPTS_DOMAIN, p_class->get_mono_ptr());
|
||||
ERR_FAIL_NULL_V(mono_object, NULL);
|
||||
|
||||
CACHED_FIELD(GodotObject, ptr)->set_value_raw(mono_object, p_object);
|
||||
@ -364,4 +364,10 @@ String get_exception_name_and_message(MonoObject *p_ex) {
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void print_unhandled_exception(MonoObject *p_ex) {
|
||||
ERR_PRINT(GDMonoUtils::get_exception_name_and_message(p_ex).utf8());
|
||||
mono_print_unhandled_exception(p_ex);
|
||||
}
|
||||
|
||||
} // namespace GDMonoUtils
|
||||
|
@ -166,12 +166,14 @@ MonoDomain *create_domain(const String &p_friendly_name);
|
||||
|
||||
String get_exception_name_and_message(MonoObject *p_ex);
|
||||
|
||||
void print_unhandled_exception(MonoObject *p_ex);
|
||||
|
||||
} // namespace GDMonoUtils
|
||||
|
||||
#define NATIVE_GDMONOCLASS_NAME(m_class) (GDMonoMarshal::mono_string_to_godot((MonoString *)m_class->get_field(BINDINGS_NATIVE_NAME_FIELD)->get_value(NULL)))
|
||||
|
||||
#define CACHED_CLASS(m_class) (GDMonoUtils::mono_cache.class_##m_class)
|
||||
#define CACHED_CLASS_RAW(m_class) (GDMonoUtils::mono_cache.class_##m_class->get_raw())
|
||||
#define CACHED_CLASS_RAW(m_class) (GDMonoUtils::mono_cache.class_##m_class->get_mono_ptr())
|
||||
#define CACHED_NS_CLASS(m_ns, m_class) (GDMonoUtils::mono_cache.class_##m_ns##_##m_class)
|
||||
#define CACHED_RAW_MONO_CLASS(m_class) (GDMonoUtils::mono_cache.rawclass_##m_class)
|
||||
#define CACHED_FIELD(m_class, m_field) (GDMonoUtils::mono_cache.field_##m_class##_##m_field)
|
||||
|
Loading…
Reference in New Issue
Block a user