diff options
Diffstat (limited to 'modules/mono/csharp_script.cpp')
-rw-r--r-- | modules/mono/csharp_script.cpp | 168 |
1 files changed, 110 insertions, 58 deletions
diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp index 978093b7d5..0ceb45d425 100644 --- a/modules/mono/csharp_script.cpp +++ b/modules/mono/csharp_script.cpp @@ -43,8 +43,10 @@ #include "core/os/thread.h" #ifdef TOOLS_ENABLED +#include "core/os/keyboard.h" #include "editor/bindings_generator.h" #include "editor/editor_node.h" +#include "editor/editor_settings.h" #include "editor/node_dock.h" #endif @@ -311,22 +313,22 @@ void CSharpLanguage::get_reserved_words(List<String> *p_words) const { bool CSharpLanguage::is_control_flow_keyword(String p_keyword) const { return p_keyword == "break" || - p_keyword == "case" || - p_keyword == "catch" || - p_keyword == "continue" || - p_keyword == "default" || - p_keyword == "do" || - p_keyword == "else" || - p_keyword == "finally" || - p_keyword == "for" || - p_keyword == "foreach" || - p_keyword == "goto" || - p_keyword == "if" || - p_keyword == "return" || - p_keyword == "switch" || - p_keyword == "throw" || - p_keyword == "try" || - p_keyword == "while"; + p_keyword == "case" || + p_keyword == "catch" || + p_keyword == "continue" || + p_keyword == "default" || + p_keyword == "do" || + p_keyword == "else" || + p_keyword == "finally" || + p_keyword == "for" || + p_keyword == "foreach" || + p_keyword == "goto" || + p_keyword == "if" || + p_keyword == "return" || + p_keyword == "switch" || + p_keyword == "throw" || + p_keyword == "try" || + p_keyword == "while"; } void CSharpLanguage::get_comment_delimiters(List<String> *p_delimiters) const { @@ -337,7 +339,7 @@ void CSharpLanguage::get_comment_delimiters(List<String> *p_delimiters) const { void CSharpLanguage::get_string_delimiters(List<String> *p_delimiters) const { p_delimiters->push_back("' '"); // character literal p_delimiters->push_back("\" \""); // regular string literal - // Verbatim string literals (`@" "`) don't render correctly, so don't highlight them. + p_delimiters->push_back("@\" \""); // verbatim string literal // Generic string highlighting suffices as a workaround for now. } @@ -786,11 +788,7 @@ bool CSharpLanguage::is_assembly_reloading_needed() { GDMonoAssembly *proj_assembly = gdmono->get_project_assembly(); - String appname = ProjectSettings::get_singleton()->get("application/config/name"); - String appname_safe = OS::get_singleton()->get_safe_dir_name(appname); - if (appname_safe.is_empty()) { - appname_safe = "UnnamedProject"; - } + String appname_safe = ProjectSettings::get_singleton()->get_safe_project_name(); appname_safe += ".dll"; @@ -1353,6 +1351,7 @@ void CSharpLanguage::_editor_init_callback() { // Enable it as a plugin EditorNode::add_editor_plugin(godotsharp_editor); + ED_SHORTCUT("mono/build_solution", TTR("Build Solution"), KeyModifierMask::ALT | Key::B); godotsharp_editor->enable_plugin(); get_singleton()->godotsharp_editor = godotsharp_editor; @@ -1657,7 +1656,7 @@ bool CSharpInstance::set(const StringName &p_name, const Variant &p_value) { GDMonoProperty *property = top->get_property(p_name); if (property) { - property->set_value(mono_object, GDMonoMarshal::variant_to_mono_object(p_value, property->get_type())); + property->set_value_from_variant(mono_object, p_value); return true; } @@ -1810,8 +1809,9 @@ void CSharpInstance::get_event_signals_state_for_reloading(List<Pair<StringName, } void CSharpInstance::get_property_list(List<PropertyInfo> *p_properties) const { - for (const KeyValue<StringName, PropertyInfo> &E : script->member_info) { - p_properties->push_back(E.value); + List<PropertyInfo> props; + for (OrderedHashMap<StringName, PropertyInfo>::ConstElement E = script->member_info.front(); E; E = E.next()) { + props.push_front(E.value()); } // Call _get_property_list @@ -1834,9 +1834,8 @@ void CSharpInstance::get_property_list(List<PropertyInfo> *p_properties) const { if (ret) { Array array = Array(GDMonoMarshal::mono_object_to_variant(ret)); for (int i = 0, size = array.size(); i < size; i++) { - p_properties->push_back(PropertyInfo::from_dict(array.get(i))); + props.push_back(PropertyInfo::from_dict(array.get(i))); } - return; } break; @@ -1844,6 +1843,10 @@ void CSharpInstance::get_property_list(List<PropertyInfo> *p_properties) const { top = top->get_parent_class(); } + + for (const PropertyInfo &prop : props) { + p_properties->push_back(prop); + } } Variant::Type CSharpInstance::get_property_type(const StringName &p_name, bool *r_is_valid) const { @@ -1861,6 +1864,29 @@ Variant::Type CSharpInstance::get_property_type(const StringName &p_name, bool * return Variant::NIL; } +void CSharpInstance::get_method_list(List<MethodInfo> *p_list) const { + if (!script->is_valid() || !script->script_class) { + return; + } + + GD_MONO_SCOPE_THREAD_ATTACH; + + // TODO: We're filtering out constructors but there may be other methods unsuitable for explicit calls. + GDMonoClass *top = script->script_class; + + while (top && top != script->native) { + const Vector<GDMonoMethod *> &methods = top->get_all_methods(); + for (int i = 0; i < methods.size(); ++i) { + MethodInfo minfo = methods[i]->get_method_info(); + if (minfo.name != CACHED_STRING_NAME(dotctor)) { + p_list->push_back(minfo); + } + } + + top = top->get_parent_class(); + } +} + bool CSharpInstance::has_method(const StringName &p_method) const { if (!script.is_valid()) { return false; @@ -2124,7 +2150,7 @@ bool CSharpInstance::refcount_decremented() { return ref_dying; } -const Vector<MultiplayerAPI::RPCConfig> CSharpInstance::get_rpc_methods() const { +const Vector<Multiplayer::RPCConfig> CSharpInstance::get_rpc_methods() const { return script->get_rpc_methods(); } @@ -2866,12 +2892,24 @@ int CSharpScript::_try_get_member_export_hint(IMonoClassMember *p_member, Manage ERR_FAIL_COND_V_MSG(elem_variant_type == Variant::NIL, -1, "Unknown array element type."); - int hint_res = _try_get_member_export_hint(p_member, elem_type, elem_variant_type, /* allow_generics: */ false, elem_hint, elem_hint_string); + bool preset_hint = false; + if (elem_variant_type == Variant::STRING) { + MonoObject *attr = p_member->get_attribute(CACHED_CLASS(ExportAttribute)); + if (PropertyHint(CACHED_FIELD(ExportAttribute, hint)->get_int_value(attr)) == PROPERTY_HINT_ENUM) { + r_hint_string = itos(elem_variant_type) + "/" + itos(PROPERTY_HINT_ENUM) + ":" + CACHED_FIELD(ExportAttribute, hintString)->get_string_value(attr); + preset_hint = true; + } + } + + if (!preset_hint) { + int hint_res = _try_get_member_export_hint(p_member, elem_type, elem_variant_type, /* allow_generics: */ false, elem_hint, elem_hint_string); - ERR_FAIL_COND_V_MSG(hint_res == -1, -1, "Error while trying to determine information about the array element type."); + ERR_FAIL_COND_V_MSG(hint_res == -1, -1, "Error while trying to determine information about the array element type."); + + // Format: type/hint:hint_string + r_hint_string = itos(elem_variant_type) + "/" + itos(elem_hint) + ":" + elem_hint_string; + } - // Format: type/hint:hint_string - r_hint_string = itos(elem_variant_type) + "/" + itos(elem_hint) + ":" + elem_hint_string; r_hint = PROPERTY_HINT_TYPE_STRING; } else if (p_allow_generics && p_variant_type == Variant::DICTIONARY) { @@ -2939,7 +2977,7 @@ bool CSharpScript::_set(const StringName &p_name, const Variant &p_value) { } void CSharpScript::_get_property_list(List<PropertyInfo> *p_properties) const { - p_properties->push_back(PropertyInfo(Variant::STRING, CSharpLanguage::singleton->string_names._script_source, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL)); + p_properties->push_back(PropertyInfo(Variant::STRING, CSharpLanguage::singleton->string_names._script_source, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL)); } void CSharpScript::_bind_methods() { @@ -3034,13 +3072,13 @@ void CSharpScript::update_script_class_info(Ref<CSharpScript> p_script) { Vector<GDMonoMethod *> methods = top->get_all_methods(); for (int i = 0; i < methods.size(); i++) { if (!methods[i]->is_static()) { - MultiplayerAPI::RPCMode mode = p_script->_member_get_rpc_mode(methods[i]); - if (MultiplayerAPI::RPC_MODE_DISABLED != mode) { - MultiplayerAPI::RPCConfig nd; + Multiplayer::RPCMode mode = p_script->_member_get_rpc_mode(methods[i]); + if (Multiplayer::RPC_MODE_DISABLED != mode) { + Multiplayer::RPCConfig nd; nd.name = methods[i]->get_name(); nd.rpc_mode = mode; // TODO Transfer mode, channel - nd.transfer_mode = MultiplayerPeer::TRANSFER_MODE_RELIABLE; + nd.transfer_mode = Multiplayer::TRANSFER_MODE_RELIABLE; nd.channel = 0; if (-1 == p_script->rpc_functions.find(nd)) { p_script->rpc_functions.push_back(nd); @@ -3054,7 +3092,7 @@ void CSharpScript::update_script_class_info(Ref<CSharpScript> p_script) { } // Sort so we are 100% that they are always the same. - p_script->rpc_functions.sort_custom<MultiplayerAPI::SortRPCConfig>(); + p_script->rpc_functions.sort_custom<Multiplayer::SortRPCConfig>(); p_script->load_script_signals(p_script->script_class, p_script->native); } @@ -3228,8 +3266,7 @@ ScriptInstance *CSharpScript::instance_create(Object *p_this) { "Script inherits from native type '" + String(native_name) + "', so it can't be instantiated in object of type: '" + p_this->get_class() + "'"); } - ERR_FAIL_V_MSG(nullptr, "Script inherits from native type '" + String(native_name) + - "', so it can't be instantiated in object of type: '" + p_this->get_class() + "'."); + ERR_FAIL_V_MSG(nullptr, "Script inherits from native type '" + String(native_name) + "', so it can't be instantiated in object of type: '" + p_this->get_class() + "'."); } } @@ -3280,10 +3317,19 @@ void CSharpScript::get_script_method_list(List<MethodInfo> *p_list) const { GD_MONO_SCOPE_THREAD_ATTACH; - // TODO: Filter out things unsuitable for explicit calls, like constructors. - const Vector<GDMonoMethod *> &methods = script_class->get_all_methods(); - for (int i = 0; i < methods.size(); ++i) { - p_list->push_back(methods[i]->get_method_info()); + // TODO: We're filtering out constructors but there may be other methods unsuitable for explicit calls. + GDMonoClass *top = script_class; + + while (top && top != native) { + const Vector<GDMonoMethod *> &methods = top->get_all_methods(); + for (int i = 0; i < methods.size(); ++i) { + MethodInfo minfo = methods[i]->get_method_info(); + if (minfo.name != CACHED_STRING_NAME(dotctor)) { + p_list->push_back(methods[i]->get_method_info()); + } + } + + top = top->get_parent_class(); } } @@ -3453,9 +3499,15 @@ Ref<Script> CSharpScript::get_base_script() const { return Ref<Script>(); } -void CSharpScript::get_script_property_list(List<PropertyInfo> *p_list) const { - for (const KeyValue<StringName, PropertyInfo> &E : member_info) { - p_list->push_back(E.value); +void CSharpScript::get_script_property_list(List<PropertyInfo> *r_list) const { + List<PropertyInfo> props; + + for (OrderedHashMap<StringName, PropertyInfo>::ConstElement E = member_info.front(); E; E = E.next()) { + props.push_front(E.value()); + } + + for (const PropertyInfo &prop : props) { + r_list->push_back(prop); } } @@ -3464,18 +3516,18 @@ int CSharpScript::get_member_line(const StringName &p_member) const { return -1; } -MultiplayerAPI::RPCMode CSharpScript::_member_get_rpc_mode(IMonoClassMember *p_member) const { - if (p_member->has_attribute(CACHED_CLASS(RemoteAttribute))) { - return MultiplayerAPI::RPC_MODE_ANY; +Multiplayer::RPCMode CSharpScript::_member_get_rpc_mode(IMonoClassMember *p_member) const { + if (p_member->has_attribute(CACHED_CLASS(AnyPeerAttribute))) { + return Multiplayer::RPC_MODE_ANY_PEER; } - if (p_member->has_attribute(CACHED_CLASS(PuppetAttribute))) { - return MultiplayerAPI::RPC_MODE_AUTHORITY; + if (p_member->has_attribute(CACHED_CLASS(AuthorityAttribute))) { + return Multiplayer::RPC_MODE_AUTHORITY; } - return MultiplayerAPI::RPC_MODE_DISABLED; + return Multiplayer::RPC_MODE_DISABLED; } -const Vector<MultiplayerAPI::RPCConfig> CSharpScript::get_rpc_methods() const { +const Vector<Multiplayer::RPCConfig> CSharpScript::get_rpc_methods() const { return rpc_functions; } @@ -3483,10 +3535,10 @@ Error CSharpScript::load_source_code(const String &p_path) { Error ferr = read_all_file_utf8(p_path, source); ERR_FAIL_COND_V_MSG(ferr != OK, ferr, - ferr == ERR_INVALID_DATA ? - "Script '" + p_path + "' contains invalid unicode (UTF-8), so it was not loaded." - " Please ensure that scripts are saved in valid UTF-8 unicode." : - "Failed to read file: '" + p_path + "'."); + ferr == ERR_INVALID_DATA + ? "Script '" + p_path + "' contains invalid unicode (UTF-8), so it was not loaded." + " Please ensure that scripts are saved in valid UTF-8 unicode." + : "Failed to read file: '" + p_path + "'."); #ifdef TOOLS_ENABLED source_changed_cache = true; |