diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..22666e0 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "files.associations": { + "bit": "cpp" + } +} \ No newline at end of file diff --git a/csharp_script.cpp b/csharp_script.cpp index 2fa7709..eb3422b 100644 --- a/csharp_script.cpp +++ b/csharp_script.cpp @@ -541,6 +541,37 @@ String CSharpLanguage::_get_indentation() const { return "\t"; } +bool CSharpLanguage::handles_global_class_type(const String &p_type) const { + return p_type == "CSharpScript"; +} + +String CSharpLanguage::get_global_class_name(const String &p_path, String *r_base_type, String *r_icon_path) const { + Ref script = ResourceLoader::load(p_path, "CSharpScript"); + if (script.is_valid()) { + String name = script->get_script_class_name(); + if (name.length()) { + if (r_base_type) { + StringName base_name = script->get_script_class_base(); + if (base_name != StringName()) { + *r_base_type = base_name; + } else { + *r_base_type = script->get_instance_base_type(); + } + } + if (r_icon_path) { + *r_icon_path = script->get_script_class_icon_path(); + } + return name; + } + } + + if (r_base_type) + *r_base_type = String(); + if (r_icon_path) + *r_icon_path = String(); + return String(); +} + String CSharpLanguage::debug_get_error() const { return _debug_error; } @@ -926,6 +957,11 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) { #endif script->signals_invalidated = true; +#ifdef TOOLS_ENABLED + EditorFileSystem::get_singleton()->remove_compiled_lang_script_class_file_cache(script->get_path()); + EditorNode::get_editor_data().script_class_set_icon_path(script->get_script_class_name(), script->get_script_class_icon_path()); +#endif + script->reload(p_soft_reload); script->update_exports(); @@ -1025,6 +1061,11 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) { to_reload_state.push_back(script); } +#ifdef TOOLS_ENABLED + ScriptServer::save_global_classes(); + EditorNode::get_editor_data().script_class_save_icon_paths(); +#endif + for (List>::Element *E = to_reload_state.front(); E; E = E->next()) { Ref script = E->get(); @@ -2620,7 +2661,9 @@ bool CSharpScript::_get_member_export(IMonoClassMember *p_member, bool p_inspect } #ifdef TOOLS_ENABLED - int hint_res = _try_get_member_export_hint(p_member, type, variant_type, /* allow_generics: */ true, hint, hint_string); + PropertyHint given_hint = PropertyHint(CACHED_FIELD(ExportAttribute, hint)->get_int_value(attr)); + String given_hint_string = CACHED_FIELD(ExportAttribute, hintString)->get_string_value(attr); + int hint_res = _try_get_member_export_hint(p_member, type, variant_type, given_hint, given_hint_string, /* allow_generics: */ true, hint, hint_string); ERR_FAIL_COND_V_MSG(hint_res == -1, false, "Error while trying to determine information about the exported member: '" + @@ -2641,7 +2684,7 @@ bool CSharpScript::_get_member_export(IMonoClassMember *p_member, bool p_inspect } #ifdef TOOLS_ENABLED -int CSharpScript::_try_get_member_export_hint(IMonoClassMember *p_member, ManagedType p_type, Variant::Type p_variant_type, bool p_allow_generics, PropertyHint &r_hint, String &r_hint_string) { +int CSharpScript::_try_get_member_export_hint(IMonoClassMember *p_member, ManagedType p_type, Variant::Type p_variant_type, PropertyHint p_given_hint, String p_given_hint_string, bool p_allow_generics, PropertyHint &r_hint, String &r_hint_string) { GD_MONO_ASSERT_THREAD_ATTACHED; if (p_variant_type == Variant::INT && p_type.type_encoding == MONO_TYPE_VALUETYPE && mono_class_is_enum(p_type.type_class->get_mono_ptr())) { @@ -2704,6 +2747,16 @@ int CSharpScript::_try_get_member_export_hint(IMonoClassMember *p_member, Manage r_hint = PROPERTY_HINT_RESOURCE_TYPE; r_hint_string = NATIVE_GDMONOCLASS_NAME(field_native_class); + + if (p_type.type_class->has_attribute(CACHED_CLASS(GlobalAttribute))) { + MonoObject *attr = p_type.type_class->get_attribute(CACHED_CLASS(GlobalAttribute)); + StringName script_class_name = CACHED_FIELD(GlobalAttribute, name)->get_string_value(attr); + if (script_class_name != StringName()) { + r_hint_string = script_class_name; + } + } else if (!p_given_hint_string.empty()) { + r_hint_string = p_given_hint_string; + } } else if (p_allow_generics && p_variant_type == Variant::ARRAY) { // Nested arrays are not supported in the inspector @@ -2729,7 +2782,7 @@ int CSharpScript::_try_get_member_export_hint(IMonoClassMember *p_member, Manage } 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); + int hint_res = _try_get_member_export_hint(p_member, elem_type, elem_variant_type, p_given_hint, p_given_hint_string, /* 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."); @@ -3248,6 +3301,16 @@ Error CSharpScript::reload(bool p_keep_state) { load_script_signals(script_class, native); _update_exports(); + + _update_global_script_class_settings(); +#ifdef TOOLS_ENABLED + if (Engine::get_singleton()->is_editor_hint()) { + // Force file cache update for compiled languages to update script class metadata + StringName n = script_class_name; + StringName b = script_class_base; + EditorFileSystem::get_singleton()->update_file_script_class_metadata(get_path(), n, b, get_language()->get_name(), script_class_icon_path); + } +#endif } return OK; @@ -3356,6 +3419,37 @@ Error CSharpScript::load_source_code(const String &p_path) { return OK; } +void CSharpScript::_update_global_script_class_settings() { + // Evaluate script's use of engine "Script Class" system. + if (script_class->has_attribute(CACHED_CLASS(GlobalAttribute))) { + MonoObject *attr = script_class->get_attribute(CACHED_CLASS(GlobalAttribute)); + script_class_name = CACHED_FIELD(GlobalAttribute, name)->get_string_value(attr); + script_class_icon_path = CACHED_FIELD(GlobalAttribute, iconPath)->get_string_value(attr); + if (script_class_name.empty()) { + script_class_name = script_class->get_name(); + } + } else { + script_class_name = String(); + script_class_icon_path = String(); + } + + GDMonoClass *parent = script_class->get_parent_class(); + while (parent) { + if (parent->has_attribute(CACHED_CLASS(GlobalAttribute))) { + MonoObject *attr = parent->get_attribute(CACHED_CLASS(GlobalAttribute)); + script_class_base = CACHED_FIELD(GlobalAttribute, name)->get_string_value(attr); + if (script_class_base.empty()) { + script_class_base = script_class->get_name(); + } + break; + } + parent = parent->get_parent_class(); + } + if (script_class_base.empty()) { + script_class_base = get_instance_base_type(); + } +} + StringName CSharpScript::get_script_name() const { return name; } diff --git a/csharp_script.h b/csharp_script.h index f482c48..7e06735 100644 --- a/csharp_script.h +++ b/csharp_script.h @@ -31,12 +31,12 @@ #ifndef CSHARP_SCRIPT_H #define CSHARP_SCRIPT_H +#include "core/containers/ordered_hash_map.h" +#include "core/containers/rb_set.h" +#include "core/containers/self_list.h" #include "core/io/resource_loader.h" #include "core/io/resource_saver.h" #include "core/object/script_language.h" -#include "core/containers/self_list.h" -#include "core/containers/rb_set.h" -#include "core/containers/ordered_hash_map.h" #include "mono_gc_handle.h" #include "mono_gd/gd_mono.h" @@ -105,6 +105,11 @@ class CSharpScript : public Script { String source; StringName name; + // For engine "Script Class" support, not affiliated with `GDMonoClass *script_class` property. + String script_class_name; + String script_class_base; + String script_class_icon_path; + SelfList script_list; struct Argument { @@ -142,7 +147,7 @@ class CSharpScript : public Script { bool _get_member_export(IMonoClassMember *p_member, bool p_inspect_export, PropertyInfo &r_prop_info, bool &r_exported); #ifdef TOOLS_ENABLED - static int _try_get_member_export_hint(IMonoClassMember *p_member, ManagedType p_type, Variant::Type p_variant_type, bool p_allow_generics, PropertyHint &r_hint, String &r_hint_string); + static int _try_get_member_export_hint(IMonoClassMember *p_member, ManagedType p_type, Variant::Type p_variant_type, PropertyHint p_given_hint, String p_given_hint_string, bool p_allow_generics, PropertyHint &r_hint, String &r_hint_string); #endif CSharpInstance *_create_instance(const Variant **p_args, int p_argcount, Object *p_owner, bool p_isref, Variant::CallError &r_error); @@ -204,6 +209,11 @@ public: Error load_source_code(const String &p_path); + String get_script_class_name() const { return script_class_name; } + String get_script_class_base() const { return script_class_base; } + String get_script_class_icon_path() const { return script_class_icon_path; } + void _update_global_script_class_settings(); + StringName get_script_name() const; CSharpScript(); @@ -421,6 +431,11 @@ public: virtual String _get_indentation() const; /* TODO? */ virtual void auto_indent_code(String &p_code, int p_from_line, int p_to_line) const {} /* TODO */ virtual void add_global_constant(const StringName &p_variable, const Variant &p_value) {} + virtual bool has_delayed_script_class_metadata() const override { return true; } + + /* SCRIPT CLASS FUNCTIONS */ + virtual bool handles_global_class_type(const String &p_type) const; + virtual String get_global_class_name(const String &p_path, String *r_base_type = NULL, String *r_icon_path = NULL) const; /* DEBUGGER FUNCTIONS */ virtual String debug_get_error() const; diff --git a/glue/GodotSharp/GodotSharp/Core/Attributes/ExportAttribute.cs b/glue/GodotSharp/GodotSharp/Core/Attributes/ExportAttribute.cs index 6adf044..e5e8955 100644 --- a/glue/GodotSharp/GodotSharp/Core/Attributes/ExportAttribute.cs +++ b/glue/GodotSharp/GodotSharp/Core/Attributes/ExportAttribute.cs @@ -13,5 +13,19 @@ namespace Godot this.hint = hint; this.hintString = hintString; } + + public ExportAttribute(string className) + { + if (ClassDB.ClassExists(className) || ScriptServer.IsGlobalClass(className)) + { + this.hint = PropertyHint.ResourceType; + this.hintString = className; + } + else + { + this.hint = PropertyHint.None; + this.hintString = ""; + } + } } } diff --git a/glue/GodotSharp/GodotSharp/Core/Attributes/GlobalAttribute.cs b/glue/GodotSharp/GodotSharp/Core/Attributes/GlobalAttribute.cs new file mode 100644 index 0000000..1ba8e0f --- /dev/null +++ b/glue/GodotSharp/GodotSharp/Core/Attributes/GlobalAttribute.cs @@ -0,0 +1,17 @@ +using System; + +namespace Godot +{ + [AttributeUsage(AttributeTargets.Class)] + public class GlobalAttribute : Attribute + { + private string name; + private string iconPath; + + public GlobalAttribute(string name = "", string iconPath = "") + { + this.name = name; + this.iconPath = iconPath; + } + } +} \ No newline at end of file diff --git a/glue/GodotSharp/GodotSharp/GodotSharp.csproj b/glue/GodotSharp/GodotSharp/GodotSharp.csproj index f53f49a..e3d26fd 100644 --- a/glue/GodotSharp/GodotSharp/GodotSharp.csproj +++ b/glue/GodotSharp/GodotSharp/GodotSharp.csproj @@ -15,6 +15,7 @@ + diff --git a/mono_gd/gd_mono_cache.cpp b/mono_gd/gd_mono_cache.cpp index 49c93fe..405a73d 100644 --- a/mono_gd/gd_mono_cache.cpp +++ b/mono_gd/gd_mono_cache.cpp @@ -139,6 +139,9 @@ void CachedData::clear_godot_api_cache() { class_ExportAttribute = NULL; field_ExportAttribute_hint = NULL; field_ExportAttribute_hintString = NULL; + class_GlobalAttribute = NULL; + field_GlobalAttribute_name = NULL; + field_GlobalAttribute_iconPath = NULL; class_SignalAttribute = NULL; class_ToolAttribute = NULL; class_RemoteAttribute = NULL; @@ -263,6 +266,9 @@ void update_godot_api_cache() { CACHE_CLASS_AND_CHECK(ExportAttribute, GODOT_API_CLASS(ExportAttribute)); CACHE_FIELD_AND_CHECK(ExportAttribute, hint, CACHED_CLASS(ExportAttribute)->get_field("hint")); CACHE_FIELD_AND_CHECK(ExportAttribute, hintString, CACHED_CLASS(ExportAttribute)->get_field("hintString")); + CACHE_CLASS_AND_CHECK(GlobalAttribute, GODOT_API_CLASS(GlobalAttribute)); + CACHE_FIELD_AND_CHECK(GlobalAttribute, name, CACHED_CLASS(GlobalAttribute)->get_field("name")); + CACHE_FIELD_AND_CHECK(GlobalAttribute, iconPath, CACHED_CLASS(GlobalAttribute)->get_field("iconPath")); CACHE_CLASS_AND_CHECK(SignalAttribute, GODOT_API_CLASS(SignalAttribute)); CACHE_CLASS_AND_CHECK(ToolAttribute, GODOT_API_CLASS(ToolAttribute)); CACHE_CLASS_AND_CHECK(RemoteAttribute, GODOT_API_CLASS(RemoteAttribute)); diff --git a/mono_gd/gd_mono_cache.h b/mono_gd/gd_mono_cache.h index f4205dd..2811928 100644 --- a/mono_gd/gd_mono_cache.h +++ b/mono_gd/gd_mono_cache.h @@ -110,6 +110,9 @@ struct CachedData { GDMonoClass *class_ExportAttribute; GDMonoField *field_ExportAttribute_hint; GDMonoField *field_ExportAttribute_hintString; + GDMonoClass *class_GlobalAttribute; + GDMonoField *field_GlobalAttribute_name; + GDMonoField *field_GlobalAttribute_iconPath; GDMonoClass *class_SignalAttribute; GDMonoClass *class_ToolAttribute; GDMonoClass *class_RemoteAttribute;