Skip to content

Commit

Permalink
Trait System
Browse files Browse the repository at this point in the history
  • Loading branch information
SeremTitus committed Oct 7, 2024
1 parent e3213aa commit b49ce22
Show file tree
Hide file tree
Showing 31 changed files with 2,085 additions and 96 deletions.
1 change: 1 addition & 0 deletions core/object/object.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -932,6 +932,7 @@ void Object::set_script(const Variant &p_script) {
ERR_FAIL_COND_MSG(s.is_null(), "Cannot set object script. Parameter should be null or a reference to a valid script.");
ERR_FAIL_COND_MSG(s->is_abstract(), vformat("Cannot set object script. Script '%s' should not be abstract.", s->get_path()));
}
ERR_FAIL_COND_MSG(!s->is_attachable(), vformat("Cannot set object script. Script '%s' is not attachable.", s->get_path()));

script = p_script;

Expand Down
1 change: 1 addition & 0 deletions core/object/script_language.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ void Script::_bind_methods() {

ClassDB::bind_method(D_METHOD("is_tool"), &Script::is_tool);
ClassDB::bind_method(D_METHOD("is_abstract"), &Script::is_abstract);
ClassDB::bind_method(D_METHOD("is_attachable"), &Script::is_attachable);

ClassDB::bind_method(D_METHOD("get_rpc_config"), &Script::get_rpc_config);

Expand Down
2 changes: 2 additions & 0 deletions core/object/script_language.h
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ class Script : public Resource {
virtual bool is_tool() const = 0;
virtual bool is_valid() const = 0;
virtual bool is_abstract() const = 0;
virtual bool is_attachable() const { return true; }

virtual ScriptLanguage *get_language() const = 0;

Expand Down Expand Up @@ -214,6 +215,7 @@ class ScriptLanguage : public Object {
virtual void init() = 0;
virtual String get_type() const = 0;
virtual String get_extension() const = 0;
virtual bool is_language_script_attachable() const { return true; }
virtual void finish() = 0;

/* EDITOR FUNCTIONS */
Expand Down
8 changes: 7 additions & 1 deletion doc/classes/Script.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<description>
A class stored as a resource. A script extends the functionality of all objects that instantiate it.
This is the base class for all scripts and should not be used directly. Trying to create a new script with this class will result in an error.
The [code]new[/code] method of a script subclass creates a new instance. [method Object.set_script] extends an existing object, if that object's class matches one of the script's base classes.
The [code]new[/code] method of a script subclass creates a new instance. [method Object.set_script] extends an existing object, if that object's class matches one of the script's base classes and if script is attachable check by [method is_attachable].
</description>
<tutorials>
<link title="Scripting documentation index">$DOCS_URL/tutorials/scripting/index.html</link>
Expand Down Expand Up @@ -115,6 +115,12 @@
Returns [code]true[/code] if the script is an abstract script. An abstract script does not have a constructor and cannot be instantiated.
</description>
</method>
<method name="is_attachable" qualifiers="const">
<return type="bool" />
<description>
Returns [code]true[/code] if the script is able to be attached to [Object].
</description>
</method>
<method name="is_tool" qualifiers="const">
<return type="bool" />
<description>
Expand Down
22 changes: 16 additions & 6 deletions editor/script_create_dialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,10 +128,16 @@ void ScriptCreateDialog::_notification(int p_what) {
} break;

case NOTIFICATION_THEME_CHANGED: {
int skipped_lang = 0;
for (int i = 0; i < ScriptServer::get_language_count(); i++) {
Ref<Texture2D> language_icon = get_editor_theme_icon(ScriptServer::get_language(i)->get_type());
ScriptLanguage *lang = ScriptServer::get_language(i);
if (lang->is_language_script_attachable()) {
skipped_lang++;
continue;
}
Ref<Texture2D> language_icon = get_editor_theme_icon(lang->get_type());
if (language_icon.is_valid()) {
language_menu->set_item_icon(i, language_icon);
language_menu->set_item_icon(i - skipped_lang, language_icon);
}
}

Expand Down Expand Up @@ -855,11 +861,15 @@ ScriptCreateDialog::ScriptCreateDialog() {
gc->add_child(language_menu);

default_language = -1;
int add_lang_index = 0;
for (int i = 0; i < ScriptServer::get_language_count(); i++) {
String lang = ScriptServer::get_language(i)->get_name();
language_menu->add_item(lang);
if (lang == "GDScript") {
default_language = i;
ScriptLanguage *lang = ScriptServer::get_language(i);
if (lang->is_language_script_attachable()) {
language_menu->add_item(lang->get_name());
if (lang->get_name() == "GDScript") {
default_language = add_lang_index;
}
add_lang_index++;
}
}
if (default_language >= 0) {
Expand Down
4 changes: 4 additions & 0 deletions modules/gdscript/.editorconfig
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
[*.gd]
indent_size = 4
trim_trailing_whitespace = true

[*.gdt]
indent_size = 4
trim_trailing_whitespace = true
788 changes: 788 additions & 0 deletions modules/gdscript/doc_classes/@GDTrait.xml

Large diffs are not rendered by default.

13 changes: 13 additions & 0 deletions modules/gdscript/doc_classes/GDTrait.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="GDTrait" inherits="GDScript" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
A script implemented in the GDScript programming language.
</brief_description>
<description>
See [GDScript] or [@GDScript] instead.
Helper Script to store Traits for GDScript, its not attachable to objects [method Object.set_script].Saved with the [code].gdt[/code] extension, for GDScript programming language external Traits.
</description>
<tutorials>
<link title="GDScript documentation index">$DOCS_URL/tutorials/scripting/gdscript/index.html</link>
</tutorials>
</class>
1 change: 1 addition & 0 deletions modules/gdscript/editor/gdscript_docgen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ void GDScriptDocGen::_doctype_from_gdtype(const GDType &p_gdtype, String &r_type
}
r_type = "Object";
return;
case GDType::TRAIT:
case GDType::CLASS:
if (p_gdtype.is_meta_type) {
r_type = GDScript::get_class_static();
Expand Down
1 change: 1 addition & 0 deletions modules/gdscript/editor/gdscript_highlighter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -679,6 +679,7 @@ String GDScriptSyntaxHighlighter::_get_name() const {
PackedStringArray GDScriptSyntaxHighlighter::_get_supported_languages() const {
PackedStringArray languages;
languages.push_back("GDScript");
languages.push_back("GDTrait");
return languages;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ void GDScriptEditorTranslationParserPlugin::_traverse_class(const GDScriptParser
const GDScriptParser::ClassNode::Member &m = p_class->members[i];
// Other member types can't contain translatable strings.
switch (m.type) {
case GDScriptParser::ClassNode::Member::TRAIT:
case GDScriptParser::ClassNode::Member::CLASS:
_traverse_class(m.m_class);
break;
Expand Down
46 changes: 40 additions & 6 deletions modules/gdscript/gdscript.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2575,6 +2575,16 @@ void GDScriptLanguage::reload_scripts(const Array &p_scripts, bool p_soft_reload
for (Ref<GDScript> &scr : scripts) {
bool reload = p_scripts.has(scr) || to_reload.has(scr->get_base());

// Reload if saved scripts stores trait for script.
if (!reload) {
for (const Variant &saved_scr : p_scripts) {
reload = scr->traits_path.has(static_cast<Ref<GDScript>>(saved_scr)->get_path());
if (reload) {
break;
}
}
}

if (!reload) {
continue;
}
Expand Down Expand Up @@ -2741,7 +2751,9 @@ void GDScriptLanguage::get_reserved_words(List<String> *p_words) const {
"namespace", // Reserved for potential future use.
"signal",
"static",
"trait", // Reserved for potential future use.
"trait",
"trait_name",
"uses",
"var",
// Other keywords.
"await",
Expand Down Expand Up @@ -2797,7 +2809,7 @@ bool GDScriptLanguage::is_control_flow_keyword(const String &p_keyword) const {
}

bool GDScriptLanguage::handles_global_class_type(const String &p_type) const {
return p_type == "GDScript";
return p_type == "GDScript" || p_type == "GDTrait";
}

String GDScriptLanguage::get_global_class_name(const String &p_path, String *r_base_type, String *r_icon_path) const {
Expand Down Expand Up @@ -2868,7 +2880,7 @@ String GDScriptLanguage::get_global_class_name(const String &p_path, String *r_b
while (extend_classes.size() > 0) {
bool found = false;
for (int i = 0; i < subclass->members.size(); i++) {
if (subclass->members[i].type != GDScriptParser::ClassNode::Member::CLASS) {
if (subclass->members[i].type != GDScriptParser::ClassNode::Member::CLASS && subclass->members[i].type != GDScriptParser::ClassNode::Member::TRAIT) {
continue;
}

Expand Down Expand Up @@ -2908,8 +2920,12 @@ thread_local GDScriptLanguage::CallStack GDScriptLanguage::_call_stack;

GDScriptLanguage::GDScriptLanguage() {
calls = 0;
ERR_FAIL_COND(singleton);
singleton = this;

if (singleton == nullptr) {
// TODO: Need better solution. Its hack to allow GDTraitLanguage to share same singleton.
singleton = this;
}

strings._init = StaticCString::create("_init");
strings._static_init = StaticCString::create("_static_init");
strings._notification = StaticCString::create("_notification");
Expand Down Expand Up @@ -2993,6 +3009,19 @@ Ref<GDScript> GDScriptLanguage::get_script_by_fully_qualified_name(const String
return scr;
}

/* GDTRAIT */
String GDTraitLanguage::get_name() const {
return "GDTrait";
}

String GDTraitLanguage::get_type() const {
return "GDTrait";
}

String GDTraitLanguage::get_extension() const {
return "gdt";
}

/*************** RESOURCE ***************/

Ref<Resource> ResourceFormatLoaderGDScript::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
Expand All @@ -3015,18 +3044,22 @@ Ref<Resource> ResourceFormatLoaderGDScript::load(const String &p_path, const Str

void ResourceFormatLoaderGDScript::get_recognized_extensions(List<String> *p_extensions) const {
p_extensions->push_back("gd");
p_extensions->push_back("gdt");
p_extensions->push_back("gdc");
}

bool ResourceFormatLoaderGDScript::handles_type(const String &p_type) const {
return (p_type == "Script" || p_type == "GDScript");
return (p_type == "Script" || p_type == "GDScript" || p_type == "GDTrait");
}

String ResourceFormatLoaderGDScript::get_resource_type(const String &p_path) const {
String el = p_path.get_extension().to_lower();
if (el == "gd" || el == "gdc") {
return "GDScript";
}
if (el == "gdt") {
return "GDTrait";
}
return "";
}

Expand Down Expand Up @@ -3077,6 +3110,7 @@ Error ResourceFormatSaverGDScript::save(const Ref<Resource> &p_resource, const S
void ResourceFormatSaverGDScript::get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const {
if (Object::cast_to<GDScript>(*p_resource)) {
p_extensions->push_back("gd");
p_extensions->push_back("gdt");
}
}

Expand Down
17 changes: 17 additions & 0 deletions modules/gdscript/gdscript.h
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ class GDScript : public Script {
String fully_qualified_name;
String simplified_icon_path;
SelfList<GDScript> script_list;
Vector<String> traits_path; // File path from used traits for reload.

SelfList<GDScriptFunctionState>::List pending_func_states;

Expand Down Expand Up @@ -641,6 +642,22 @@ class GDScriptLanguage : public ScriptLanguage {
~GDScriptLanguage();
};

/* GDTRAIT */
class GDTrait : public GDScript {
GDCLASS(GDTrait, GDScript);

public:
virtual bool is_attachable() const override { return false; }
};

class GDTraitLanguage : public GDScriptLanguage {
public:
virtual String get_name() const override;
virtual String get_type() const override;
virtual String get_extension() const override;
virtual bool is_language_script_attachable() const override { return false; }
};

class ResourceFormatLoaderGDScript : public ResourceFormatLoader {
public:
virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE) override;
Expand Down
Loading

0 comments on commit b49ce22

Please sign in to comment.