Skip to content

Commit c01de46

Browse files
committed
Trait System
1 parent c2ba0a8 commit c01de46

File tree

130 files changed

+3128
-225
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

130 files changed

+3128
-225
lines changed

core/io/resource_loader.cpp

+4-1
Original file line numberDiff line numberDiff line change
@@ -1525,7 +1525,10 @@ Vector<String> ResourceLoader::list_directory(const String &p_directory) {
15251525
d = d.substr(0, d.rfind_char('.'));
15261526
}
15271527

1528-
if (d.ends_with(".gdc")) {
1528+
if (d.ends_with(".t.gdc")) {
1529+
d = d.substr(0, d.rfind_char('.'));
1530+
d += ".gdt";
1531+
} else if (d.ends_with(".gdc")) {
15291532
d = d.substr(0, d.rfind_char('.'));
15301533
d += ".gd";
15311534
}

core/object/object.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -967,6 +967,7 @@ void Object::set_script(const Variant &p_script) {
967967
if (!p_script.is_null()) {
968968
ERR_FAIL_COND_MSG(s.is_null(), "Cannot set object script. Parameter should be null or a reference to a valid script.");
969969
ERR_FAIL_COND_MSG(s->is_abstract(), vformat("Cannot set object script. Script '%s' should not be abstract.", s->get_path()));
970+
ERR_FAIL_COND_MSG(!s->is_attachable(), vformat("Cannot set object script. Script '%s' is not attachable.", s->get_path()));
970971
}
971972

972973
script = p_script;

core/object/object.h

+3
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,9 @@ struct MethodInfo {
230230
Vector<Variant> default_arguments;
231231
int return_val_metadata = 0;
232232
Vector<int> arguments_metadata;
233+
#ifdef TOOLS_ENABLED
234+
String overridden_source_path;
235+
#endif
233236

234237
int get_argument_meta(int p_arg) const {
235238
ERR_FAIL_COND_V(p_arg < -1 || p_arg > arguments.size(), 0);

core/object/script_language.cpp

+20-3
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,7 @@ void Script::_bind_methods() {
171171

172172
ClassDB::bind_method(D_METHOD("is_tool"), &Script::is_tool);
173173
ClassDB::bind_method(D_METHOD("is_abstract"), &Script::is_abstract);
174+
ClassDB::bind_method(D_METHOD("is_attachable"), &Script::is_attachable);
174175

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

@@ -223,7 +224,7 @@ ScriptLanguage *ScriptServer::get_language_for_extension(const String &p_extensi
223224
MutexLock lock(languages_mutex);
224225

225226
for (int i = 0; i < _language_count; i++) {
226-
if (_languages[i] && _languages[i]->get_extension() == p_extension) {
227+
if (_languages[i] && _languages[i]->get_extensions().has(p_extension)) {
227228
return _languages[i];
228229
}
229230
}
@@ -237,9 +238,25 @@ Error ScriptServer::register_language(ScriptLanguage *p_language) {
237238
ERR_FAIL_COND_V_MSG(_language_count >= MAX_LANGUAGES, ERR_UNAVAILABLE, "Script languages limit has been reach, cannot register more.");
238239
for (int i = 0; i < _language_count; i++) {
239240
const ScriptLanguage *other_language = _languages[i];
240-
ERR_FAIL_COND_V_MSG(other_language->get_extension() == p_language->get_extension(), ERR_ALREADY_EXISTS, vformat("A script language with extension '%s' is already registered.", p_language->get_extension()));
241+
String shared_extensions;
242+
String shared_types;
243+
for (String ext : p_language->get_extensions()) {
244+
if (other_language->get_extensions().has(ext)) {
245+
if (!shared_extensions.is_empty()) {
246+
shared_extensions += ", ";
247+
}
248+
shared_extensions += ext;
249+
}
250+
if (other_language->get_type_from_extension(ext) == p_language->get_type_from_extension(ext)) {
251+
if (!shared_types.is_empty()) {
252+
shared_types += ", ";
253+
}
254+
shared_types += ext;
255+
}
256+
}
257+
ERR_FAIL_COND_V_MSG(!shared_extensions.is_empty(), ERR_ALREADY_EXISTS, vformat("A script language with extension '%s' is already registered.", shared_extensions));
241258
ERR_FAIL_COND_V_MSG(other_language->get_name() == p_language->get_name(), ERR_ALREADY_EXISTS, vformat("A script language with name '%s' is already registered.", p_language->get_name()));
242-
ERR_FAIL_COND_V_MSG(other_language->get_type() == p_language->get_type(), ERR_ALREADY_EXISTS, vformat("A script language with type '%s' is already registered.", p_language->get_type()));
259+
ERR_FAIL_COND_V_MSG(!shared_types.is_empty(), ERR_ALREADY_EXISTS, vformat("A script language with type '%s' is already registered.", shared_types));
243260
}
244261
_languages[_language_count++] = p_language;
245262
return OK;

core/object/script_language.h

+11
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,8 @@ class Script : public Resource {
140140
virtual Ref<Script> get_base_script() const = 0; //for script inheritance
141141
virtual StringName get_global_name() const = 0;
142142
virtual bool inherits_script(const Ref<Script> &p_script) const = 0;
143+
virtual bool has_script_subtype(const String &p_type) const { return false; } // For script with possible multiple script types, for instance interfaces or traits(in GDScript).
144+
virtual Vector<String> get_script_subtypes() const { return Vector<String>(); }
143145

144146
virtual StringName get_instance_base_type() const = 0; // this may not work in all scripts, will return empty if so
145147
virtual ScriptInstance *instance_create(Object *p_this) = 0;
@@ -169,6 +171,7 @@ class Script : public Resource {
169171
virtual bool is_tool() const = 0;
170172
virtual bool is_valid() const = 0;
171173
virtual bool is_abstract() const = 0;
174+
virtual bool is_attachable() const { return true; }
172175

173176
virtual ScriptLanguage *get_language() const = 0;
174177

@@ -219,6 +222,13 @@ class ScriptLanguage : public Object {
219222
virtual String get_extension() const = 0;
220223
virtual void finish() = 0;
221224

225+
/* MULTI SCRIPT SUPPORT */
226+
// TODO: In the next compat breakage the following methods should be merged by removing there similar method.
227+
virtual String get_type_from_extension(const String &p_extension) const { return get_type(); }
228+
virtual Vector<String> get_extensions() const { return Vector<String>({ get_extension() }); }
229+
virtual Script *create_script_from_extension(const String &p_extension) const { return create_script(); }
230+
virtual Ref<Script> make_template_using_extension(const String &p_template, const String &p_class_name, const String &p_base_class_name, const String &p_extension) const { return make_template(p_template, p_class_name, p_base_class_name); }
231+
222232
/* EDITOR FUNCTIONS */
223233
struct Warning {
224234
int start_line = -1, end_line = -1;
@@ -272,6 +282,7 @@ class ScriptLanguage : public Object {
272282
virtual bool is_using_templates() { return false; }
273283
virtual bool validate(const String &p_script, const String &p_path = "", List<String> *r_functions = nullptr, List<ScriptError> *r_errors = nullptr, List<Warning> *r_warnings = nullptr, HashSet<int> *r_safe_lines = nullptr) const = 0;
274284
virtual String validate_path(const String &p_path) const { return ""; }
285+
virtual bool is_script_attachable(const String &p_extension) const { return true; }
275286
virtual Script *create_script() const = 0;
276287
#ifndef DISABLE_DEPRECATED
277288
virtual bool has_named_classes() const = 0;

core/object/script_language_extension.cpp

+8
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ void ScriptExtension::_bind_methods() {
3838
GDVIRTUAL_BIND(_get_base_script);
3939
GDVIRTUAL_BIND(_get_global_name);
4040
GDVIRTUAL_BIND(_inherits_script, "script");
41+
GDVIRTUAL_BIND(_has_script_subtype, "type");
42+
GDVIRTUAL_BIND(_get_script_subtypes);
4143

4244
GDVIRTUAL_BIND(_get_instance_base_type);
4345
GDVIRTUAL_BIND(_instance_create, "for_object");
@@ -65,6 +67,7 @@ void ScriptExtension::_bind_methods() {
6567
GDVIRTUAL_BIND(_is_tool);
6668
GDVIRTUAL_BIND(_is_valid);
6769
GDVIRTUAL_BIND(_is_abstract);
70+
GDVIRTUAL_BIND(_is_attachable);
6871
GDVIRTUAL_BIND(_get_language);
6972

7073
GDVIRTUAL_BIND(_has_script_signal, "signal");
@@ -90,7 +93,9 @@ void ScriptLanguageExtension::_bind_methods() {
9093
GDVIRTUAL_BIND(_get_name);
9194
GDVIRTUAL_BIND(_init);
9295
GDVIRTUAL_BIND(_get_type);
96+
GDVIRTUAL_BIND(_get_type_from_extension, "extension");
9397
GDVIRTUAL_BIND(_get_extension);
98+
GDVIRTUAL_BIND(_get_extensions);
9499
GDVIRTUAL_BIND(_finish);
95100

96101
GDVIRTUAL_BIND(_get_reserved_words);
@@ -99,12 +104,15 @@ void ScriptLanguageExtension::_bind_methods() {
99104
GDVIRTUAL_BIND(_get_doc_comment_delimiters);
100105
GDVIRTUAL_BIND(_get_string_delimiters);
101106
GDVIRTUAL_BIND(_make_template, "template", "class_name", "base_class_name");
107+
GDVIRTUAL_BIND(_make_template_using_extension, "template", "class_name", "base_class_name", "extension");
102108
GDVIRTUAL_BIND(_get_built_in_templates, "object");
103109
GDVIRTUAL_BIND(_is_using_templates);
104110
GDVIRTUAL_BIND(_validate, "script", "path", "validate_functions", "validate_errors", "validate_warnings", "validate_safe_lines");
105111

106112
GDVIRTUAL_BIND(_validate_path, "path");
113+
GDVIRTUAL_BIND(_is_script_attachable, "extension");
107114
GDVIRTUAL_BIND(_create_script);
115+
GDVIRTUAL_BIND(_create_script_from_extension, "extension");
108116
#ifndef DISABLE_DEPRECATED
109117
GDVIRTUAL_BIND(_has_named_classes);
110118
#endif

core/object/script_language_extension.h

+9-1
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ class ScriptExtension : public Script {
5454
EXBIND0RC(Ref<Script>, get_base_script)
5555
EXBIND0RC(StringName, get_global_name)
5656
EXBIND1RC(bool, inherits_script, const Ref<Script> &)
57+
EXBIND1RC(bool, has_script_subtype, const String &)
58+
EXBIND0RC(Vector<String>, get_script_subtypes)
5759
EXBIND0RC(StringName, get_instance_base_type)
5860

5961
GDVIRTUAL1RC_REQUIRED(GDExtensionPtr<void>, _instance_create, Object *)
@@ -135,7 +137,7 @@ class ScriptExtension : public Script {
135137
return GDVIRTUAL_CALL(_is_abstract, abst) && abst;
136138
}
137139
GDVIRTUAL0RC(bool, _is_abstract)
138-
140+
EXBIND0RC(bool, is_attachable)
139141
EXBIND0RC(ScriptLanguage *, get_language)
140142
EXBIND1RC(bool, has_script_signal, const StringName &)
141143

@@ -234,7 +236,9 @@ class ScriptLanguageExtension : public ScriptLanguage {
234236

235237
EXBIND0(init)
236238
EXBIND0RC(String, get_type)
239+
EXBIND1RC(String, get_type_from_extension, const String &)
237240
EXBIND0RC(String, get_extension)
241+
EXBIND0RC(Vector<String>, get_extensions)
238242
EXBIND0(finish)
239243

240244
/* EDITOR FUNCTIONS */
@@ -281,6 +285,7 @@ class ScriptLanguageExtension : public ScriptLanguage {
281285
}
282286

283287
EXBIND3RC(Ref<Script>, make_template, const String &, const String &, const String &)
288+
EXBIND4RC(Ref<Script>, make_template_using_extension, const String &, const String &, const String &, const String &)
284289

285290
GDVIRTUAL1RC_REQUIRED(TypedArray<Dictionary>, _get_built_in_templates, StringName)
286291

@@ -377,12 +382,15 @@ class ScriptLanguageExtension : public ScriptLanguage {
377382
}
378383

379384
EXBIND1RC(String, validate_path, const String &)
385+
EXBIND1RC(bool, is_script_attachable, const String &)
380386
GDVIRTUAL0RC_REQUIRED(Object *, _create_script)
381387
Script *create_script() const override {
382388
Object *ret = nullptr;
383389
GDVIRTUAL_CALL(_create_script, ret);
384390
return Object::cast_to<Script>(ret);
385391
}
392+
GDVIRTUAL1RC_REQUIRED(Object *, _create_script_from_extension, const String &)
393+
Script *create_script_from_extension(const String &p_extension) const override { return create_script(); }
386394
#ifndef DISABLE_DEPRECATED
387395
EXBIND0RC(bool, has_named_classes)
388396
#endif

doc/classes/ProjectSettings.xml

+6
Original file line numberDiff line numberDiff line change
@@ -612,6 +612,9 @@
612612
<member name="debug/gdscript/warnings/unused_local_constant" type="int" setter="" getter="" default="1">
613613
When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when a local constant is never used.
614614
</member>
615+
<member name="debug/gdscript/warnings/unused_onready_overriding_trait" type="int" setter="" getter="" default="1">
616+
When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when the [annotation @GDScript.@onready] is not used overridden variable from traits and trait variable uses [annotation @GDScript.@onready].
617+
</member>
615618
<member name="debug/gdscript/warnings/unused_parameter" type="int" setter="" getter="" default="1">
616619
When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when a function parameter is never used.
617620
</member>
@@ -621,6 +624,9 @@
621624
<member name="debug/gdscript/warnings/unused_signal" type="int" setter="" getter="" default="1">
622625
When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when a signal is declared but never explicitly used in the class.
623626
</member>
627+
<member name="debug/gdscript/warnings/unused_static_overriding_trait" type="int" setter="" getter="" default="1">
628+
When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when the [code]static[/code] is not used overridden variable or function from traits and trait variable or function uses [code]static[/code].
629+
</member>
624630
<member name="debug/gdscript/warnings/unused_variable" type="int" setter="" getter="" default="1">
625631
When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when a local variable is unused.
626632
</member>

doc/classes/Script.xml

+7-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
<description>
77
A class stored as a resource. A script extends the functionality of all objects that instantiate it.
88
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.
9-
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.
9+
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].
1010
</description>
1111
<tutorials>
1212
<link title="Scripting documentation index">$DOCS_URL/tutorials/scripting/index.html</link>
@@ -115,6 +115,12 @@
115115
Returns [code]true[/code] if the script is an abstract script. An abstract script does not have a constructor and cannot be instantiated.
116116
</description>
117117
</method>
118+
<method name="is_attachable" qualifiers="const">
119+
<return type="bool" />
120+
<description>
121+
Returns [code]true[/code] if the script is able to be attached to [Object].
122+
</description>
123+
</method>
118124
<method name="is_tool" qualifiers="const">
119125
<return type="bool" />
120126
<description>

doc/classes/ScriptExtension.xml

+21
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,13 @@
107107
<description>
108108
</description>
109109
</method>
110+
<method name="_get_script_subtypes" qualifiers="virtual const">
111+
<return type="PackedStringArray" />
112+
<description>
113+
return other script types.
114+
For script with possible multiple script types, for instance interfaces or traits(in GDScript).
115+
</description>
116+
</method>
110117
<method name="_get_source_code" qualifiers="virtual const">
111118
<return type="String" />
112119
<description>
@@ -130,6 +137,14 @@
130137
<description>
131138
</description>
132139
</method>
140+
<method name="_has_script_subtype" qualifiers="virtual const">
141+
<return type="bool" />
142+
<param index="0" name="type" type="String" />
143+
<description>
144+
Determines if script is of the given script type.
145+
For script with possible multiple script types, for instance interfaces or traits(in GDScript).
146+
</description>
147+
</method>
133148
<method name="_has_source_code" qualifiers="virtual const">
134149
<return type="bool" />
135150
<description>
@@ -165,6 +180,12 @@
165180
Returns [code]true[/code] if the script is an abstract script. An abstract script does not have a constructor and cannot be instantiated.
166181
</description>
167182
</method>
183+
<method name="_is_attachable" qualifiers="virtual const">
184+
<return type="bool" />
185+
<description>
186+
Determines if the script can be attached to [Object]s including [Node]s.
187+
</description>
188+
</method>
168189
<method name="_is_placeholder_fallback_enabled" qualifiers="virtual const">
169190
<return type="bool" />
170191
<description>

doc/classes/ScriptLanguageExtension.xml

+40
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,14 @@
5252
<description>
5353
</description>
5454
</method>
55+
<method name="_create_script_from_extension" qualifiers="virtual const">
56+
<return type="Object" />
57+
<param index="0" name="extension" type="String" />
58+
<description>
59+
Creates a new script object based on extension supported by this language.
60+
Also look at [method ScriptLanguageExtension._get_extensions].
61+
</description>
62+
</method>
5563
<method name="_debug_get_current_stack_info" qualifiers="virtual">
5664
<return type="Dictionary[]" />
5765
<description>
@@ -163,6 +171,12 @@
163171
<description>
164172
</description>
165173
</method>
174+
<method name="_get_extensions" qualifiers="virtual const">
175+
<return type="PackedStringArray" />
176+
<description>
177+
Returns file extensions of scripts supported by this language.
178+
</description>
179+
</method>
166180
<method name="_get_global_class_name" qualifiers="virtual const">
167181
<return type="Dictionary" />
168182
<param index="0" name="path" type="String" />
@@ -209,6 +223,14 @@
209223
<description>
210224
</description>
211225
</method>
226+
<method name="_get_type_from_extension" qualifiers="virtual const">
227+
<return type="String" />
228+
<param index="0" name="extension" type="String" />
229+
<description>
230+
Returns the script type of the given file extension.
231+
Also look at [method ScriptLanguageExtension._get_extensions].
232+
</description>
233+
</method>
212234
<method name="_handles_global_class_type" qualifiers="virtual const">
213235
<return type="bool" />
214236
<param index="0" name="type" type="String" />
@@ -231,6 +253,15 @@
231253
<description>
232254
</description>
233255
</method>
256+
<method name="_is_script_attachable" qualifiers="virtual const">
257+
<return type="bool" />
258+
<param index="0" name="extension" type="String" />
259+
<description>
260+
Determines if a script can be attached to objects based on the given file extension.
261+
Returns true if the script with the specified extension can be attached, false otherwise.
262+
Also look at [method ScriptLanguageExtension._get_extensions].
263+
</description>
264+
</method>
234265
<method name="_is_using_templates" qualifiers="virtual">
235266
<return type="bool" />
236267
<description>
@@ -261,6 +292,15 @@
261292
<description>
262293
</description>
263294
</method>
295+
<method name="_make_template_using_extension" qualifiers="virtual const">
296+
<return type="Script" />
297+
<param index="0" name="template" type="String" />
298+
<param index="1" name="class_name" type="String" />
299+
<param index="2" name="base_class_name" type="String" />
300+
<param index="3" name="extension" type="String" />
301+
<description>
302+
</description>
303+
</method>
264304
<method name="_open_in_external_editor" qualifiers="virtual">
265305
<return type="int" enum="Error" />
266306
<param index="0" name="script" type="Script" />

editor/create_dialog.cpp

+7-2
Original file line numberDiff line numberDiff line change
@@ -189,12 +189,17 @@ bool CreateDialog::_should_hide_type(const StringName &p_type) const {
189189
int i = script_path.find_char('/', 13); // 13 is length of "res://addons/".
190190
while (i > -1) {
191191
const String plugin_path = script_path.substr(0, i).path_join("plugin.cfg");
192-
if (FileAccess::exists(plugin_path)) {
193-
return !EditorNode::get_singleton()->is_addon_plugin_enabled(plugin_path);
192+
if (FileAccess::exists(plugin_path) && !EditorNode::get_singleton()->is_addon_plugin_enabled(plugin_path)) {
193+
return true;
194194
}
195195
i = script_path.find_char('/', i + 1);
196196
}
197197
}
198+
199+
ScriptLanguage *lang = ScriptServer::get_language_for_extension(script_path.get_extension());
200+
if (lang && !lang->is_script_attachable(script_path.get_extension())) {
201+
return true; // Hide unattachable scripts.
202+
}
198203
}
199204

200205
return false;

0 commit comments

Comments
 (0)