diff options
Diffstat (limited to 'modules/mono/csharp_script.cpp')
-rw-r--r-- | modules/mono/csharp_script.cpp | 187 |
1 files changed, 118 insertions, 69 deletions
diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp index b475782729..ba8c7df9cc 100644 --- a/modules/mono/csharp_script.cpp +++ b/modules/mono/csharp_script.cpp @@ -41,6 +41,7 @@ #include "editor/csharp_project.h" #include "editor/editor_node.h" #include "editor/godotsharp_editor.h" +#include "utils/string_utils.h" #endif #include "godotsharp_dirs.h" @@ -48,8 +49,9 @@ #include "mono_gd/gd_mono_marshal.h" #include "signal_awaiter_utils.h" -#define CACHED_STRING_NAME(m_var) (CSharpLanguage::get_singleton()->string_names.m_var) +#define CACHED_STRING_NAME(m_var) (CSharpLanguage::get_singleton()->get_string_names().m_var) +#ifdef TOOLS_ENABLED static bool _create_project_solution_if_needed() { String sln_path = GodotSharpDirs::get_project_sln_path(); @@ -64,6 +66,7 @@ static bool _create_project_solution_if_needed() { return true; } +#endif CSharpLanguage *CSharpLanguage::singleton = NULL; @@ -295,20 +298,88 @@ bool CSharpLanguage::has_named_classes() const { return true; } -String CSharpLanguage::make_function(const String &p_class, const String &p_name, const PoolStringArray &p_args) const { +static String variant_type_to_managed_name(const String &p_var_type_name) { + + if (p_var_type_name.empty()) + return "object"; + + if (!ClassDB::class_exists(p_var_type_name)) { + Variant::Type var_types[] = { + Variant::BOOL, + Variant::INT, + Variant::REAL, + Variant::STRING, + Variant::VECTOR2, + Variant::RECT2, + Variant::VECTOR3, + Variant::TRANSFORM2D, + Variant::PLANE, + Variant::QUAT, + Variant::RECT3, + Variant::BASIS, + Variant::TRANSFORM, + Variant::COLOR, + Variant::NODE_PATH, + Variant::_RID + }; + + for (int i = 0; i < sizeof(var_types) / sizeof(Variant::Type); i++) { + if (p_var_type_name == Variant::get_type_name(var_types[i])) + return p_var_type_name; + } + + if (p_var_type_name == "String") + return "string"; // I prefer this one >:[ + + // TODO these will be rewritten later into custom containers + + if (p_var_type_name == "Array") + return "object[]"; + + if (p_var_type_name == "Dictionary") + return "Dictionary<object, object>"; + if (p_var_type_name == "PoolByteArray") + return "byte[]"; + if (p_var_type_name == "PoolIntArray") + return "int[]"; + if (p_var_type_name == "PoolRealArray") + return "float[]"; + if (p_var_type_name == "PoolStringArray") + return "string[]"; + if (p_var_type_name == "PoolVector2Array") + return "Vector2[]"; + if (p_var_type_name == "PoolVector3Array") + return "Vector3[]"; + if (p_var_type_name == "PoolColorArray") + return "Color[]"; + + return "object"; + } + + return p_var_type_name; +} + +String CSharpLanguage::make_function(const String &p_class, const String &p_name, const PoolStringArray &p_args) const { +#ifdef TOOLS_ENABLED // FIXME - // Due to Godot's API limitation this just appends the function to the end of the file - // Another limitation is that the parameter types are not specified, so we must use System.Object + // - Due to Godot's API limitation this just appends the function to the end of the file + // - Use fully qualified name if there is ambiguity String s = "private void " + p_name + "("; for (int i = 0; i < p_args.size(); i++) { + const String &arg = p_args[i]; + if (i > 0) s += ", "; - s += "object " + p_args[i]; + + s += variant_type_to_managed_name(arg.get_slice(":", 1)) + " " + escape_csharp_keyword(arg.get_slice(":", 0)); } s += ")\n{\n // Replace with function body\n}\n"; return s; +#else + return String(); +#endif } void CSharpLanguage::frame() { @@ -903,46 +974,6 @@ Variant CSharpInstance::call(const StringName &p_method, const Variant **p_args, } else { return Variant(); } - } else if (p_method == CACHED_STRING_NAME(_awaited_signal_callback)) { - // shitty hack.. - // TODO move to its own function, thx - - if (p_argcount < 1) { - r_error.error = Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; - r_error.argument = 1; - return Variant(); - } - - Ref<SignalAwaiterHandle> awaiter = *p_args[p_argcount - 1]; - - if (awaiter.is_null()) { - r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_error.argument = p_argcount - 1; - r_error.expected = Variant::OBJECT; - return Variant(); - } - - awaiter->set_completed(true); - - int extra_argc = p_argcount - 1; - MonoArray *extra_args = mono_array_new(SCRIPTS_DOMAIN, CACHED_CLASS_RAW(MonoObject), extra_argc); - - for (int i = 0; i < extra_argc; i++) { - MonoObject *boxed = GDMonoMarshal::variant_to_mono_object(*p_args[i]); - mono_array_set(extra_args, MonoObject *, i, boxed); - } - - GDMonoUtils::GodotObject__AwaitedSignalCallback thunk = CACHED_METHOD_THUNK(GodotObject, _AwaitedSignalCallback); - - MonoObject *ex = NULL; - thunk(mono_object, &extra_args, awaiter->get_target(), &ex); - - if (ex) { - mono_print_unhandled_exception(ex); - ERR_FAIL_V(Variant()); - } - - return Variant(); } top = top->get_parent_class(); @@ -1239,8 +1270,11 @@ bool CSharpScript::_update_exports() { for (int i = 0; i < fields.size(); i++) { GDMonoField *field = fields[i]; - if (field->is_static() || field->get_visibility() != GDMono::PUBLIC) + 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; + } String name = field->get_name(); StringName cname = name; @@ -1248,17 +1282,39 @@ bool CSharpScript::_update_exports() { if (member_info.has(cname)) continue; - Variant::Type type = GDMonoMarshal::managed_to_variant_type(field->get_type()); + 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)); - // Field has Export attribute - int hint = CACHED_FIELD(ExportAttribute, hint)->get_int_value(attr); - String hint_string = CACHED_FIELD(ExportAttribute, hint_string)->get_string_value(attr); - int usage = CACHED_FIELD(ExportAttribute, usage)->get_int_value(attr); + 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]); + } + } 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, hint_string)->get_string_value(attr); + } - PropertyInfo prop_info = PropertyInfo(type, name, PropertyHint(hint), hint_string, PropertyUsageFlags(usage)); + PropertyInfo prop_info = PropertyInfo(type, name, hint, hint_string, PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE); member_info[cname] = prop_info; exported_members_cache.push_back(prop_info); @@ -1392,12 +1448,15 @@ bool CSharpScript::can_instance() const { #ifdef TOOLS_ENABLED if (Engine::get_singleton()->is_editor_hint()) { - if (_create_project_solution_if_needed()) { - CSharpProject::add_item(GodotSharpDirs::get_project_csproj_path(), - "Compile", - ProjectSettings::get_singleton()->globalize_path(get_path())); - } else { - ERR_PRINTS("Cannot add " + get_path() + " to the C# project because it could not be created."); + + if (get_path().find("::") == -1) { // Ignore if built-in script. Can happen if the file is deleted... + if (_create_project_solution_if_needed()) { + CSharpProject::add_item(GodotSharpDirs::get_project_csproj_path(), + "Compile", + ProjectSettings::get_singleton()->globalize_path(get_path())); + } else { + ERR_PRINTS("Cannot add " + get_path() + " to the C# project because it could not be created."); + } } } #endif @@ -1679,16 +1738,6 @@ void CSharpScript::update_exports() { #ifdef TOOLS_ENABLED _update_exports(); - - if (placeholders.size()) { - Map<StringName, Variant> values; - List<PropertyInfo> propnames; - _update_exports_values(values, propnames); - - for (Set<PlaceHolderScriptInstance *>::Element *E = placeholders.front(); E; E = E->next()) { - E->get()->update(propnames, values); - } - } #endif } @@ -1915,7 +1964,7 @@ bool ResourceFormatSaverCSharpScript::recognize(const RES &p_resource) const { CSharpLanguage::StringNameCache::StringNameCache() { - _awaited_signal_callback = StaticCString::create("_AwaitedSignalCallback"); + _signal_callback = StaticCString::create("_signal_callback"); _set = StaticCString::create("_set"); _get = StaticCString::create("_get"); _notification = StaticCString::create("_notification"); |