Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/modules/gdscript/gdscript.cpp
10277 views
1
/**************************************************************************/
2
/* gdscript.cpp */
3
/**************************************************************************/
4
/* This file is part of: */
5
/* GODOT ENGINE */
6
/* https://godotengine.org */
7
/**************************************************************************/
8
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10
/* */
11
/* Permission is hereby granted, free of charge, to any person obtaining */
12
/* a copy of this software and associated documentation files (the */
13
/* "Software"), to deal in the Software without restriction, including */
14
/* without limitation the rights to use, copy, modify, merge, publish, */
15
/* distribute, sublicense, and/or sell copies of the Software, and to */
16
/* permit persons to whom the Software is furnished to do so, subject to */
17
/* the following conditions: */
18
/* */
19
/* The above copyright notice and this permission notice shall be */
20
/* included in all copies or substantial portions of the Software. */
21
/* */
22
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29
/**************************************************************************/
30
31
#include "gdscript.h"
32
33
#include "gdscript_analyzer.h"
34
#include "gdscript_cache.h"
35
#include "gdscript_compiler.h"
36
#include "gdscript_parser.h"
37
#include "gdscript_rpc_callable.h"
38
#include "gdscript_tokenizer_buffer.h"
39
#include "gdscript_warning.h"
40
41
#ifdef TOOLS_ENABLED
42
#include "editor/gdscript_docgen.h"
43
#endif
44
45
#ifdef TESTS_ENABLED
46
#include "tests/gdscript_test_runner.h"
47
#endif
48
49
#include "core/config/engine.h"
50
#include "core/config/project_settings.h"
51
#include "core/core_constants.h"
52
#include "core/io/file_access.h"
53
54
#include "scene/resources/packed_scene.h"
55
#include "scene/scene_string_names.h"
56
57
#ifdef TOOLS_ENABLED
58
#include "core/extension/gdextension_manager.h"
59
#include "editor/file_system/editor_paths.h"
60
#endif
61
62
///////////////////////////
63
64
GDScriptNativeClass::GDScriptNativeClass(const StringName &p_name) {
65
name = p_name;
66
}
67
68
bool GDScriptNativeClass::_get(const StringName &p_name, Variant &r_ret) const {
69
bool ok;
70
int64_t v = ClassDB::get_integer_constant(name, p_name, &ok);
71
72
if (ok) {
73
r_ret = v;
74
return true;
75
}
76
77
MethodBind *method = ClassDB::get_method(name, p_name);
78
if (method && method->is_static()) {
79
// Native static method.
80
r_ret = Callable(this, p_name);
81
return true;
82
}
83
84
return false;
85
}
86
87
void GDScriptNativeClass::_bind_methods() {
88
ClassDB::bind_method(D_METHOD("new"), &GDScriptNativeClass::_new);
89
}
90
91
Variant GDScriptNativeClass::_new() {
92
Object *o = instantiate();
93
ERR_FAIL_NULL_V_MSG(o, Variant(), "Class type: '" + String(name) + "' is not instantiable.");
94
95
RefCounted *rc = Object::cast_to<RefCounted>(o);
96
if (rc) {
97
return Ref<RefCounted>(rc);
98
} else {
99
return o;
100
}
101
}
102
103
Object *GDScriptNativeClass::instantiate() {
104
return ClassDB::instantiate_no_placeholders(name);
105
}
106
107
Variant GDScriptNativeClass::callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
108
if (p_method == SNAME("new")) {
109
// Constructor.
110
return Object::callp(p_method, p_args, p_argcount, r_error);
111
}
112
MethodBind *method = ClassDB::get_method(name, p_method);
113
if (method && method->is_static()) {
114
// Native static method.
115
return method->call(nullptr, p_args, p_argcount, r_error);
116
}
117
118
r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
119
return Variant();
120
}
121
122
GDScriptFunction *GDScript::_super_constructor(GDScript *p_script) {
123
if (likely(p_script->valid) && p_script->initializer) {
124
return p_script->initializer;
125
} else {
126
GDScript *base_src = p_script->_base;
127
if (base_src != nullptr) {
128
return _super_constructor(base_src);
129
} else {
130
return nullptr;
131
}
132
}
133
}
134
135
void GDScript::_super_implicit_constructor(GDScript *p_script, GDScriptInstance *p_instance, Callable::CallError &r_error) {
136
GDScript *base_src = p_script->_base;
137
if (base_src != nullptr) {
138
_super_implicit_constructor(base_src, p_instance, r_error);
139
if (r_error.error != Callable::CallError::CALL_OK) {
140
return;
141
}
142
}
143
ERR_FAIL_NULL(p_script->implicit_initializer);
144
if (likely(p_script->valid)) {
145
p_script->implicit_initializer->call(p_instance, nullptr, 0, r_error);
146
} else {
147
r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
148
}
149
}
150
151
GDScriptInstance *GDScript::_create_instance(const Variant **p_args, int p_argcount, Object *p_owner, bool p_is_ref_counted, Callable::CallError &r_error) {
152
/* STEP 1, CREATE */
153
154
GDScriptInstance *instance = memnew(GDScriptInstance);
155
instance->base_ref_counted = p_is_ref_counted;
156
instance->members.resize(member_indices.size());
157
instance->script = Ref<GDScript>(this);
158
instance->owner = p_owner;
159
instance->owner_id = p_owner->get_instance_id();
160
#ifdef DEBUG_ENABLED
161
//needed for hot reloading
162
for (const KeyValue<StringName, MemberInfo> &E : member_indices) {
163
instance->member_indices_cache[E.key] = E.value.index;
164
}
165
#endif
166
instance->owner->set_script_instance(instance);
167
168
/* STEP 2, INITIALIZE AND CONSTRUCT */
169
{
170
MutexLock lock(GDScriptLanguage::singleton->mutex);
171
instances.insert(instance->owner);
172
}
173
174
_super_implicit_constructor(this, instance, r_error);
175
if (r_error.error != Callable::CallError::CALL_OK) {
176
String error_text = Variant::get_call_error_text(instance->owner, "@implicit_new", nullptr, 0, r_error);
177
instance->script = Ref<GDScript>();
178
instance->owner->set_script_instance(nullptr);
179
{
180
MutexLock lock(GDScriptLanguage::singleton->mutex);
181
instances.erase(p_owner);
182
}
183
ERR_FAIL_V_MSG(nullptr, "Error constructing a GDScriptInstance: " + error_text);
184
}
185
186
if (p_argcount < 0) {
187
return instance;
188
}
189
190
GDScriptFunction *applicable_initializer = _super_constructor(this);
191
if (applicable_initializer != nullptr) {
192
applicable_initializer->call(instance, p_args, p_argcount, r_error);
193
if (r_error.error != Callable::CallError::CALL_OK) {
194
String error_text = Variant::get_call_error_text(instance->owner, "_init", p_args, p_argcount, r_error);
195
instance->script = Ref<GDScript>();
196
instance->owner->set_script_instance(nullptr);
197
{
198
MutexLock lock(GDScriptLanguage::singleton->mutex);
199
instances.erase(p_owner);
200
}
201
ERR_FAIL_V_MSG(nullptr, "Error constructing a GDScriptInstance: " + error_text);
202
}
203
}
204
//@TODO make thread safe
205
return instance;
206
}
207
208
Variant GDScript::_new(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
209
/* STEP 1, CREATE */
210
211
if (!valid) {
212
r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
213
return Variant();
214
}
215
216
r_error.error = Callable::CallError::CALL_OK;
217
Ref<RefCounted> ref;
218
Object *owner = nullptr;
219
220
GDScript *_baseptr = this;
221
while (_baseptr->_base) {
222
_baseptr = _baseptr->_base;
223
}
224
225
ERR_FAIL_COND_V(_baseptr->native.is_null(), Variant());
226
if (_baseptr->native.ptr()) {
227
owner = _baseptr->native->instantiate();
228
} else {
229
owner = memnew(RefCounted); //by default, no base means use reference
230
}
231
ERR_FAIL_NULL_V_MSG(owner, Variant(), "Can't inherit from a virtual class.");
232
233
RefCounted *r = Object::cast_to<RefCounted>(owner);
234
if (r) {
235
ref = Ref<RefCounted>(r);
236
}
237
238
GDScriptInstance *instance = _create_instance(p_args, p_argcount, owner, r != nullptr, r_error);
239
if (!instance) {
240
if (ref.is_null()) {
241
memdelete(owner); //no owner, sorry
242
}
243
return Variant();
244
}
245
246
if (ref.is_valid()) {
247
return ref;
248
} else {
249
return owner;
250
}
251
}
252
253
bool GDScript::can_instantiate() const {
254
#ifdef TOOLS_ENABLED
255
return valid && (tool || ScriptServer::is_scripting_enabled()) && !Engine::get_singleton()->is_recovery_mode_hint();
256
#else
257
return valid;
258
#endif
259
}
260
261
Ref<Script> GDScript::get_base_script() const {
262
if (_base) {
263
return Ref<GDScript>(_base);
264
} else {
265
return Ref<Script>();
266
}
267
}
268
269
StringName GDScript::get_global_name() const {
270
return global_name;
271
}
272
273
StringName GDScript::get_instance_base_type() const {
274
if (native.is_valid()) {
275
return native->get_name();
276
}
277
if (base.is_valid() && base->is_valid()) {
278
return base->get_instance_base_type();
279
}
280
return StringName();
281
}
282
283
struct _GDScriptMemberSort {
284
int index = 0;
285
StringName name;
286
_FORCE_INLINE_ bool operator<(const _GDScriptMemberSort &p_member) const { return index < p_member.index; }
287
};
288
289
#ifdef TOOLS_ENABLED
290
291
void GDScript::_placeholder_erased(PlaceHolderScriptInstance *p_placeholder) {
292
placeholders.erase(p_placeholder);
293
}
294
295
#endif
296
297
void GDScript::_get_script_method_list(List<MethodInfo> *r_list, bool p_include_base) const {
298
const GDScript *current = this;
299
while (current) {
300
for (const KeyValue<StringName, GDScriptFunction *> &E : current->member_functions) {
301
r_list->push_back(E.value->get_method_info());
302
}
303
304
if (!p_include_base) {
305
return;
306
}
307
308
current = current->_base;
309
}
310
}
311
312
void GDScript::get_script_method_list(List<MethodInfo> *r_list) const {
313
_get_script_method_list(r_list, true);
314
}
315
316
void GDScript::_get_script_property_list(List<PropertyInfo> *r_list, bool p_include_base) const {
317
const GDScript *sptr = this;
318
List<PropertyInfo> props;
319
320
while (sptr) {
321
Vector<_GDScriptMemberSort> msort;
322
for (const KeyValue<StringName, MemberInfo> &E : sptr->member_indices) {
323
if (!sptr->members.has(E.key)) {
324
continue; // Skip base class members.
325
}
326
_GDScriptMemberSort ms;
327
ms.index = E.value.index;
328
ms.name = E.key;
329
msort.push_back(ms);
330
}
331
332
msort.sort();
333
msort.reverse();
334
for (int i = 0; i < msort.size(); i++) {
335
props.push_front(sptr->member_indices[msort[i].name].property_info);
336
}
337
338
#ifdef TOOLS_ENABLED
339
r_list->push_back(sptr->get_class_category());
340
#endif // TOOLS_ENABLED
341
342
for (const PropertyInfo &E : props) {
343
r_list->push_back(E);
344
}
345
346
if (!p_include_base) {
347
break;
348
}
349
350
props.clear();
351
sptr = sptr->_base;
352
}
353
}
354
355
void GDScript::get_script_property_list(List<PropertyInfo> *r_list) const {
356
_get_script_property_list(r_list, true);
357
}
358
359
bool GDScript::has_method(const StringName &p_method) const {
360
return member_functions.has(p_method);
361
}
362
363
bool GDScript::has_static_method(const StringName &p_method) const {
364
return member_functions.has(p_method) && member_functions[p_method]->is_static();
365
}
366
367
int GDScript::get_script_method_argument_count(const StringName &p_method, bool *r_is_valid) const {
368
HashMap<StringName, GDScriptFunction *>::ConstIterator E = member_functions.find(p_method);
369
if (!E) {
370
if (r_is_valid) {
371
*r_is_valid = false;
372
}
373
return 0;
374
}
375
376
if (r_is_valid) {
377
*r_is_valid = true;
378
}
379
return E->value->get_argument_count();
380
}
381
382
MethodInfo GDScript::get_method_info(const StringName &p_method) const {
383
HashMap<StringName, GDScriptFunction *>::ConstIterator E = member_functions.find(p_method);
384
if (!E) {
385
return MethodInfo();
386
}
387
388
return E->value->get_method_info();
389
}
390
391
bool GDScript::get_property_default_value(const StringName &p_property, Variant &r_value) const {
392
#ifdef TOOLS_ENABLED
393
394
HashMap<StringName, Variant>::ConstIterator E = member_default_values_cache.find(p_property);
395
if (E) {
396
r_value = E->value;
397
return true;
398
}
399
400
if (base_cache.is_valid()) {
401
return base_cache->get_property_default_value(p_property, r_value);
402
}
403
#endif
404
return false;
405
}
406
407
ScriptInstance *GDScript::instance_create(Object *p_this) {
408
ERR_FAIL_COND_V_MSG(!valid, nullptr, "Script is invalid!");
409
410
GDScript *top = this;
411
while (top->_base) {
412
top = top->_base;
413
}
414
415
if (top->native.is_valid()) {
416
if (!ClassDB::is_parent_class(p_this->get_class_name(), top->native->get_name())) {
417
if (EngineDebugger::is_active()) {
418
GDScriptLanguage::get_singleton()->debug_break_parse(_get_debug_path(), 1, "Script inherits from native type '" + String(top->native->get_name()) + "', so it can't be assigned to an object of type: '" + p_this->get_class() + "'");
419
}
420
ERR_FAIL_V_MSG(nullptr, "Script inherits from native type '" + String(top->native->get_name()) + "', so it can't be assigned to an object of type '" + p_this->get_class() + "'" + ".");
421
}
422
}
423
424
Callable::CallError unchecked_error;
425
return _create_instance(nullptr, 0, p_this, Object::cast_to<RefCounted>(p_this) != nullptr, unchecked_error);
426
}
427
428
PlaceHolderScriptInstance *GDScript::placeholder_instance_create(Object *p_this) {
429
#ifdef TOOLS_ENABLED
430
PlaceHolderScriptInstance *si = memnew(PlaceHolderScriptInstance(GDScriptLanguage::get_singleton(), Ref<Script>(this), p_this));
431
placeholders.insert(si);
432
_update_exports(nullptr, false, si);
433
return si;
434
#else
435
return nullptr;
436
#endif
437
}
438
439
bool GDScript::instance_has(const Object *p_this) const {
440
MutexLock lock(GDScriptLanguage::singleton->mutex);
441
442
return instances.has((Object *)p_this);
443
}
444
445
bool GDScript::has_source_code() const {
446
return !source.is_empty();
447
}
448
449
String GDScript::get_source_code() const {
450
return source;
451
}
452
453
void GDScript::set_source_code(const String &p_code) {
454
if (source == p_code) {
455
return;
456
}
457
source = p_code;
458
#ifdef TOOLS_ENABLED
459
source_changed_cache = true;
460
#endif
461
}
462
463
#ifdef TOOLS_ENABLED
464
void GDScript::_update_exports_values(HashMap<StringName, Variant> &values, List<PropertyInfo> &propnames) {
465
for (const KeyValue<StringName, Variant> &E : member_default_values_cache) {
466
values[E.key] = E.value;
467
}
468
469
for (const PropertyInfo &E : members_cache) {
470
propnames.push_back(E);
471
}
472
473
if (base_cache.is_valid()) {
474
base_cache->_update_exports_values(values, propnames);
475
}
476
}
477
478
void GDScript::_add_doc(const DocData::ClassDoc &p_doc) {
479
doc_class_name = p_doc.name;
480
if (_owner) { // Only the top-level class stores doc info.
481
_owner->_add_doc(p_doc);
482
} else { // Remove old docs, add new.
483
for (int i = 0; i < docs.size(); i++) {
484
if (docs[i].name == p_doc.name) {
485
docs.remove_at(i);
486
break;
487
}
488
}
489
docs.append(p_doc);
490
}
491
}
492
493
void GDScript::_clear_doc() {
494
doc_class_name = StringName();
495
doc = DocData::ClassDoc();
496
docs.clear();
497
}
498
499
String GDScript::get_class_icon_path() const {
500
return simplified_icon_path;
501
}
502
#endif
503
504
bool GDScript::_update_exports(bool *r_err, bool p_recursive_call, PlaceHolderScriptInstance *p_instance_to_update, bool p_base_exports_changed) {
505
#ifdef TOOLS_ENABLED
506
507
static Vector<GDScript *> base_caches;
508
if (!p_recursive_call) {
509
base_caches.clear();
510
}
511
base_caches.append(this);
512
513
bool changed = p_base_exports_changed;
514
515
if (source_changed_cache) {
516
source_changed_cache = false;
517
changed = true;
518
519
String basedir = path;
520
521
if (basedir.is_empty()) {
522
basedir = get_path();
523
}
524
525
if (!basedir.is_empty()) {
526
basedir = basedir.get_base_dir();
527
}
528
529
GDScriptParser parser;
530
GDScriptAnalyzer analyzer(&parser);
531
Error err = parser.parse(source, path, false);
532
533
if (err == OK && analyzer.analyze() == OK) {
534
const GDScriptParser::ClassNode *c = parser.get_tree();
535
536
if (base_cache.is_valid()) {
537
base_cache->inheriters_cache.erase(get_instance_id());
538
base_cache = Ref<GDScript>();
539
}
540
541
GDScriptParser::DataType base_type = parser.get_tree()->base_type;
542
if (base_type.kind == GDScriptParser::DataType::CLASS) {
543
Ref<GDScript> bf = GDScriptCache::get_full_script(base_type.script_path, err, path);
544
if (err == OK) {
545
bf = Ref<GDScript>(bf->find_class(base_type.class_type->fqcn));
546
if (bf.is_valid()) {
547
base_cache = bf;
548
bf->inheriters_cache.insert(get_instance_id());
549
}
550
}
551
}
552
553
members_cache.clear();
554
member_default_values_cache.clear();
555
_signals.clear();
556
557
members_cache.push_back(get_class_category());
558
559
for (int i = 0; i < c->members.size(); i++) {
560
const GDScriptParser::ClassNode::Member &member = c->members[i];
561
562
switch (member.type) {
563
case GDScriptParser::ClassNode::Member::VARIABLE: {
564
if (!member.variable->exported) {
565
continue;
566
}
567
568
members_cache.push_back(member.variable->export_info);
569
Variant default_value = analyzer.make_variable_default_value(member.variable);
570
member_default_values_cache[member.variable->identifier->name] = default_value;
571
} break;
572
case GDScriptParser::ClassNode::Member::SIGNAL: {
573
_signals[member.signal->identifier->name] = member.signal->method_info;
574
} break;
575
case GDScriptParser::ClassNode::Member::GROUP: {
576
members_cache.push_back(member.annotation->export_info);
577
} break;
578
default:
579
break; // Nothing.
580
}
581
}
582
} else {
583
placeholder_fallback_enabled = true;
584
return false;
585
}
586
} else if (placeholder_fallback_enabled) {
587
return false;
588
}
589
590
placeholder_fallback_enabled = false;
591
592
if (base_cache.is_valid() && base_cache->is_valid()) {
593
for (int i = 0; i < base_caches.size(); i++) {
594
if (base_caches[i] == base_cache.ptr()) {
595
if (r_err) {
596
*r_err = true;
597
}
598
valid = false; // to show error in the editor
599
base_cache->valid = false;
600
base_cache->inheriters_cache.clear(); // to prevent future stackoverflows
601
base_cache.unref();
602
base.unref();
603
_base = nullptr;
604
ERR_FAIL_V_MSG(false, "Cyclic inheritance in script class.");
605
}
606
}
607
if (base_cache->_update_exports(r_err, true)) {
608
if (r_err && *r_err) {
609
return false;
610
}
611
changed = true;
612
}
613
}
614
615
if ((changed || p_instance_to_update) && placeholders.size()) { //hm :(
616
617
// update placeholders if any
618
HashMap<StringName, Variant> values;
619
List<PropertyInfo> propnames;
620
_update_exports_values(values, propnames);
621
622
if (changed) {
623
for (PlaceHolderScriptInstance *E : placeholders) {
624
E->update(propnames, values);
625
}
626
} else {
627
p_instance_to_update->update(propnames, values);
628
}
629
}
630
631
return changed;
632
633
#else
634
return false;
635
#endif
636
}
637
638
void GDScript::update_exports() {
639
#ifdef TOOLS_ENABLED
640
_update_exports_down(false);
641
#endif
642
}
643
644
#ifdef TOOLS_ENABLED
645
void GDScript::_update_exports_down(bool p_base_exports_changed) {
646
bool cyclic_error = false;
647
bool changed = _update_exports(&cyclic_error, false, nullptr, p_base_exports_changed);
648
649
if (cyclic_error) {
650
return;
651
}
652
653
HashSet<ObjectID> copy = inheriters_cache; //might get modified
654
655
for (const ObjectID &E : copy) {
656
Object *id = ObjectDB::get_instance(E);
657
GDScript *s = Object::cast_to<GDScript>(id);
658
659
if (!s) {
660
continue;
661
}
662
s->_update_exports_down(p_base_exports_changed || changed);
663
}
664
}
665
#endif
666
667
String GDScript::_get_debug_path() const {
668
if (is_built_in() && !get_name().is_empty()) {
669
return vformat("%s(%s)", get_name(), get_script_path());
670
} else {
671
return get_script_path();
672
}
673
}
674
675
Error GDScript::_static_init() {
676
if (likely(valid) && static_initializer) {
677
Callable::CallError call_err;
678
static_initializer->call(nullptr, nullptr, 0, call_err);
679
if (call_err.error != Callable::CallError::CALL_OK) {
680
return ERR_CANT_CREATE;
681
}
682
}
683
Error err = OK;
684
for (KeyValue<StringName, Ref<GDScript>> &inner : subclasses) {
685
err = inner.value->_static_init();
686
if (err) {
687
break;
688
}
689
}
690
return err;
691
}
692
693
void GDScript::_static_default_init() {
694
for (const KeyValue<StringName, MemberInfo> &E : static_variables_indices) {
695
const GDScriptDataType &type = E.value.data_type;
696
// Only initialize builtin types, which are not expected to be `null`.
697
if (!type.has_type || type.kind != GDScriptDataType::BUILTIN) {
698
continue;
699
}
700
if (type.builtin_type == Variant::ARRAY && type.has_container_element_type(0)) {
701
const GDScriptDataType element_type = type.get_container_element_type(0);
702
Array default_value;
703
default_value.set_typed(element_type.builtin_type, element_type.native_type, element_type.script_type);
704
static_variables.write[E.value.index] = default_value;
705
} else if (type.builtin_type == Variant::DICTIONARY && type.has_container_element_types()) {
706
const GDScriptDataType key_type = type.get_container_element_type_or_variant(0);
707
const GDScriptDataType value_type = type.get_container_element_type_or_variant(1);
708
Dictionary default_value;
709
default_value.set_typed(key_type.builtin_type, key_type.native_type, key_type.script_type, value_type.builtin_type, value_type.native_type, value_type.script_type);
710
static_variables.write[E.value.index] = default_value;
711
} else {
712
Variant default_value;
713
Callable::CallError err;
714
Variant::construct(type.builtin_type, default_value, nullptr, 0, err);
715
static_variables.write[E.value.index] = default_value;
716
}
717
}
718
}
719
720
#ifdef TOOLS_ENABLED
721
722
void GDScript::_save_old_static_data() {
723
old_static_variables_indices = static_variables_indices;
724
old_static_variables = static_variables;
725
for (KeyValue<StringName, Ref<GDScript>> &inner : subclasses) {
726
inner.value->_save_old_static_data();
727
}
728
}
729
730
void GDScript::_restore_old_static_data() {
731
for (KeyValue<StringName, MemberInfo> &E : old_static_variables_indices) {
732
if (static_variables_indices.has(E.key)) {
733
static_variables.write[static_variables_indices[E.key].index] = old_static_variables[E.value.index];
734
}
735
}
736
old_static_variables_indices.clear();
737
old_static_variables.clear();
738
for (KeyValue<StringName, Ref<GDScript>> &inner : subclasses) {
739
inner.value->_restore_old_static_data();
740
}
741
}
742
743
#endif
744
745
Error GDScript::reload(bool p_keep_state) {
746
if (reloading) {
747
return OK;
748
}
749
reloading = true;
750
751
bool has_instances;
752
{
753
MutexLock lock(GDScriptLanguage::singleton->mutex);
754
755
has_instances = instances.size();
756
}
757
758
// Check condition but reset flag before early return
759
if (!p_keep_state && has_instances) {
760
reloading = false; // Reset flag before returning
761
762
ERR_FAIL_V_MSG(ERR_ALREADY_IN_USE, "Cannot reload script while instances exist.");
763
}
764
765
String basedir = path;
766
767
if (basedir.is_empty()) {
768
basedir = get_path();
769
}
770
771
if (!basedir.is_empty()) {
772
basedir = basedir.get_base_dir();
773
}
774
775
// Loading a template, don't parse.
776
#ifdef TOOLS_ENABLED
777
if (EditorPaths::get_singleton() && basedir.begins_with(EditorPaths::get_singleton()->get_project_script_templates_dir())) {
778
reloading = false;
779
return OK;
780
}
781
#endif
782
783
{
784
String source_path = path;
785
if (source_path.is_empty()) {
786
source_path = get_path();
787
}
788
if (!source_path.is_empty()) {
789
if (GDScriptCache::get_cached_script(source_path).is_null()) {
790
MutexLock lock(GDScriptCache::singleton->mutex);
791
GDScriptCache::singleton->shallow_gdscript_cache[source_path] = Ref<GDScript>(this);
792
}
793
if (GDScriptCache::has_parser(source_path)) {
794
Error err = OK;
795
Ref<GDScriptParserRef> parser_ref = GDScriptCache::get_parser(source_path, GDScriptParserRef::EMPTY, err);
796
if (parser_ref.is_valid()) {
797
uint32_t source_hash;
798
if (!binary_tokens.is_empty()) {
799
source_hash = hash_djb2_buffer(binary_tokens.ptr(), binary_tokens.size());
800
} else {
801
source_hash = source.hash();
802
}
803
if (parser_ref->get_source_hash() != source_hash) {
804
GDScriptCache::remove_parser(source_path);
805
}
806
}
807
}
808
}
809
}
810
811
bool can_run = ScriptServer::is_scripting_enabled() || is_tool();
812
813
#ifdef TOOLS_ENABLED
814
if (p_keep_state && can_run && is_valid()) {
815
_save_old_static_data();
816
}
817
#endif
818
819
valid = false;
820
GDScriptParser parser;
821
Error err;
822
if (!binary_tokens.is_empty()) {
823
err = parser.parse_binary(binary_tokens, path);
824
} else {
825
err = parser.parse(source, path, false);
826
}
827
if (err) {
828
if (EngineDebugger::is_active()) {
829
GDScriptLanguage::get_singleton()->debug_break_parse(_get_debug_path(), parser.get_errors().front()->get().line, "Parser Error: " + parser.get_errors().front()->get().message);
830
}
831
// TODO: Show all error messages.
832
_err_print_error("GDScript::reload", path.is_empty() ? "built-in" : (const char *)path.utf8().get_data(), parser.get_errors().front()->get().line, ("Parse Error: " + parser.get_errors().front()->get().message).utf8().get_data(), false, ERR_HANDLER_SCRIPT);
833
reloading = false;
834
return ERR_PARSE_ERROR;
835
}
836
837
GDScriptAnalyzer analyzer(&parser);
838
err = analyzer.analyze();
839
840
if (err) {
841
if (EngineDebugger::is_active()) {
842
GDScriptLanguage::get_singleton()->debug_break_parse(_get_debug_path(), parser.get_errors().front()->get().line, "Parser Error: " + parser.get_errors().front()->get().message);
843
}
844
845
const List<GDScriptParser::ParserError>::Element *e = parser.get_errors().front();
846
while (e != nullptr) {
847
_err_print_error("GDScript::reload", path.is_empty() ? "built-in" : (const char *)path.utf8().get_data(), e->get().line, ("Parse Error: " + e->get().message).utf8().get_data(), false, ERR_HANDLER_SCRIPT);
848
e = e->next();
849
}
850
reloading = false;
851
return ERR_PARSE_ERROR;
852
}
853
854
can_run = ScriptServer::is_scripting_enabled() || parser.is_tool();
855
856
GDScriptCompiler compiler;
857
err = compiler.compile(&parser, this, p_keep_state);
858
859
if (err) {
860
// TODO: Provide the script function as the first argument.
861
_err_print_error("GDScript::reload", path.is_empty() ? "built-in" : (const char *)path.utf8().get_data(), compiler.get_error_line(), ("Compile Error: " + compiler.get_error()).utf8().get_data(), false, ERR_HANDLER_SCRIPT);
862
if (can_run) {
863
if (EngineDebugger::is_active()) {
864
GDScriptLanguage::get_singleton()->debug_break_parse(_get_debug_path(), compiler.get_error_line(), "Parser Error: " + compiler.get_error());
865
}
866
reloading = false;
867
return ERR_COMPILATION_FAILED;
868
} else {
869
reloading = false;
870
return err;
871
}
872
}
873
874
#ifdef TOOLS_ENABLED
875
// Done after compilation because it needs the GDScript object's inner class GDScript objects,
876
// which are made by calling make_scripts() within compiler.compile() above.
877
GDScriptDocGen::generate_docs(this, parser.get_tree());
878
#endif
879
880
#ifdef DEBUG_ENABLED
881
for (const GDScriptWarning &warning : parser.get_warnings()) {
882
if (EngineDebugger::is_active()) {
883
Vector<ScriptLanguage::StackInfo> si;
884
// TODO: Provide the script function as the first argument.
885
EngineDebugger::get_script_debugger()->send_error("GDScript::reload", get_script_path(), warning.start_line, warning.get_name(), warning.get_message(), false, ERR_HANDLER_WARNING, si);
886
}
887
}
888
#endif
889
890
if (can_run) {
891
err = _static_init();
892
if (err) {
893
return err;
894
}
895
}
896
897
#ifdef TOOLS_ENABLED
898
if (can_run && p_keep_state) {
899
_restore_old_static_data();
900
}
901
902
if (p_keep_state) {
903
// Update the properties in the inspector.
904
update_exports();
905
}
906
#endif
907
908
reloading = false;
909
return OK;
910
}
911
912
ScriptLanguage *GDScript::get_language() const {
913
return GDScriptLanguage::get_singleton();
914
}
915
916
void GDScript::get_constants(HashMap<StringName, Variant> *p_constants) {
917
if (p_constants) {
918
for (const KeyValue<StringName, Variant> &E : constants) {
919
(*p_constants)[E.key] = E.value;
920
}
921
}
922
}
923
924
void GDScript::get_members(HashSet<StringName> *p_members) {
925
if (p_members) {
926
for (const StringName &E : members) {
927
p_members->insert(E);
928
}
929
}
930
}
931
932
const Variant GDScript::get_rpc_config() const {
933
return rpc_config;
934
}
935
936
void GDScript::unload_static() const {
937
GDScriptCache::remove_script(fully_qualified_name);
938
}
939
940
Variant GDScript::callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
941
GDScript *top = this;
942
while (top) {
943
if (likely(top->valid)) {
944
HashMap<StringName, GDScriptFunction *>::Iterator E = top->member_functions.find(p_method);
945
if (E) {
946
ERR_FAIL_COND_V_MSG(!E->value->is_static(), Variant(), "Can't call non-static function '" + String(p_method) + "' in script.");
947
948
return E->value->call(nullptr, p_args, p_argcount, r_error);
949
}
950
}
951
top = top->_base;
952
}
953
954
//none found, regular
955
956
return Script::callp(p_method, p_args, p_argcount, r_error);
957
}
958
959
bool GDScript::_get(const StringName &p_name, Variant &r_ret) const {
960
if (p_name == GDScriptLanguage::get_singleton()->strings._script_source) {
961
r_ret = get_source_code();
962
return true;
963
}
964
965
const GDScript *top = this;
966
while (top) {
967
{
968
HashMap<StringName, Variant>::ConstIterator E = top->constants.find(p_name);
969
if (E) {
970
r_ret = E->value;
971
return true;
972
}
973
}
974
975
{
976
HashMap<StringName, MemberInfo>::ConstIterator E = top->static_variables_indices.find(p_name);
977
if (E) {
978
if (likely(top->valid) && E->value.getter) {
979
Callable::CallError ce;
980
const Variant ret = const_cast<GDScript *>(this)->callp(E->value.getter, nullptr, 0, ce);
981
r_ret = (ce.error == Callable::CallError::CALL_OK) ? ret : Variant();
982
return true;
983
}
984
r_ret = top->static_variables[E->value.index];
985
return true;
986
}
987
}
988
989
if (likely(top->valid)) {
990
HashMap<StringName, GDScriptFunction *>::ConstIterator E = top->member_functions.find(p_name);
991
if (E && E->value->is_static()) {
992
if (top->rpc_config.has(p_name)) {
993
r_ret = Callable(memnew(GDScriptRPCCallable(const_cast<GDScript *>(top), E->key)));
994
} else {
995
r_ret = Callable(const_cast<GDScript *>(top), E->key);
996
}
997
return true;
998
}
999
}
1000
1001
{
1002
HashMap<StringName, Ref<GDScript>>::ConstIterator E = top->subclasses.find(p_name);
1003
if (E) {
1004
r_ret = E->value;
1005
return true;
1006
}
1007
}
1008
1009
top = top->_base;
1010
}
1011
1012
return false;
1013
}
1014
1015
bool GDScript::_set(const StringName &p_name, const Variant &p_value) {
1016
if (p_name == GDScriptLanguage::get_singleton()->strings._script_source) {
1017
set_source_code(p_value);
1018
reload(true);
1019
return true;
1020
}
1021
1022
GDScript *top = this;
1023
while (top) {
1024
HashMap<StringName, MemberInfo>::ConstIterator E = top->static_variables_indices.find(p_name);
1025
if (E) {
1026
const MemberInfo *member = &E->value;
1027
Variant value = p_value;
1028
if (member->data_type.has_type && !member->data_type.is_type(value)) {
1029
const Variant *args = &p_value;
1030
Callable::CallError err;
1031
Variant::construct(member->data_type.builtin_type, value, &args, 1, err);
1032
if (err.error != Callable::CallError::CALL_OK || !member->data_type.is_type(value)) {
1033
return false;
1034
}
1035
}
1036
if (likely(top->valid) && member->setter) {
1037
const Variant *args = &value;
1038
Callable::CallError err;
1039
callp(member->setter, &args, 1, err);
1040
return err.error == Callable::CallError::CALL_OK;
1041
} else {
1042
top->static_variables.write[member->index] = value;
1043
return true;
1044
}
1045
}
1046
1047
top = top->_base;
1048
}
1049
1050
return false;
1051
}
1052
1053
void GDScript::_get_property_list(List<PropertyInfo> *p_properties) const {
1054
p_properties->push_back(PropertyInfo(Variant::STRING, "script/source", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL));
1055
1056
List<const GDScript *> classes;
1057
const GDScript *top = this;
1058
while (top) {
1059
classes.push_back(top);
1060
top = top->_base;
1061
}
1062
1063
for (const List<const GDScript *>::Element *E = classes.back(); E; E = E->prev()) {
1064
Vector<_GDScriptMemberSort> msort;
1065
for (const KeyValue<StringName, MemberInfo> &F : E->get()->static_variables_indices) {
1066
_GDScriptMemberSort ms;
1067
ms.index = F.value.index;
1068
ms.name = F.key;
1069
msort.push_back(ms);
1070
}
1071
msort.sort();
1072
1073
for (int i = 0; i < msort.size(); i++) {
1074
p_properties->push_back(E->get()->static_variables_indices[msort[i].name].property_info);
1075
}
1076
}
1077
}
1078
1079
void GDScript::_bind_methods() {
1080
ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "new", &GDScript::_new, MethodInfo("new"));
1081
}
1082
1083
void GDScript::set_path(const String &p_path, bool p_take_over) {
1084
if (is_root_script()) {
1085
Script::set_path(p_path, p_take_over);
1086
}
1087
1088
String old_path = path;
1089
path = p_path;
1090
path_valid = true;
1091
GDScriptCache::move_script(old_path, p_path);
1092
1093
for (KeyValue<StringName, Ref<GDScript>> &kv : subclasses) {
1094
kv.value->set_path(p_path, p_take_over);
1095
}
1096
}
1097
1098
String GDScript::get_script_path() const {
1099
if (!path_valid && !get_path().is_empty()) {
1100
return get_path();
1101
}
1102
return path;
1103
}
1104
1105
Error GDScript::load_source_code(const String &p_path) {
1106
if (p_path.is_empty() || p_path.begins_with("gdscript://") || ResourceLoader::get_resource_type(p_path.get_slice("::", 0)) == "PackedScene") {
1107
return OK;
1108
}
1109
1110
Vector<uint8_t> sourcef;
1111
Error err;
1112
Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ, &err);
1113
if (err) {
1114
const char *err_name;
1115
if (err < 0 || err >= ERR_MAX) {
1116
err_name = "(invalid error code)";
1117
} else {
1118
err_name = error_names[err];
1119
}
1120
ERR_FAIL_COND_V_MSG(err, err, "Attempt to open script '" + p_path + "' resulted in error '" + err_name + "'.");
1121
}
1122
1123
uint64_t len = f->get_length();
1124
sourcef.resize(len + 1);
1125
uint8_t *w = sourcef.ptrw();
1126
uint64_t r = f->get_buffer(w, len);
1127
ERR_FAIL_COND_V(r != len, ERR_CANT_OPEN);
1128
w[len] = 0;
1129
1130
String s;
1131
if (s.append_utf8((const char *)w, len) != OK) {
1132
ERR_FAIL_V_MSG(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.");
1133
}
1134
1135
source = s;
1136
path = p_path;
1137
path_valid = true;
1138
#ifdef TOOLS_ENABLED
1139
source_changed_cache = true;
1140
set_edited(false);
1141
set_last_modified_time(FileAccess::get_modified_time(path));
1142
#endif // TOOLS_ENABLED
1143
return OK;
1144
}
1145
1146
void GDScript::set_binary_tokens_source(const Vector<uint8_t> &p_binary_tokens) {
1147
binary_tokens = p_binary_tokens;
1148
}
1149
1150
const Vector<uint8_t> &GDScript::get_binary_tokens_source() const {
1151
return binary_tokens;
1152
}
1153
1154
Vector<uint8_t> GDScript::get_as_binary_tokens() const {
1155
GDScriptTokenizerBuffer tokenizer;
1156
return tokenizer.parse_code_string(source, GDScriptTokenizerBuffer::COMPRESS_NONE);
1157
}
1158
1159
const HashMap<StringName, GDScriptFunction *> &GDScript::debug_get_member_functions() const {
1160
return member_functions;
1161
}
1162
1163
StringName GDScript::debug_get_member_by_index(int p_idx) const {
1164
for (const KeyValue<StringName, MemberInfo> &E : member_indices) {
1165
if (E.value.index == p_idx) {
1166
return E.key;
1167
}
1168
}
1169
1170
return "<error>";
1171
}
1172
1173
StringName GDScript::debug_get_static_var_by_index(int p_idx) const {
1174
for (const KeyValue<StringName, MemberInfo> &E : static_variables_indices) {
1175
if (E.value.index == p_idx) {
1176
return E.key;
1177
}
1178
}
1179
1180
return "<error>";
1181
}
1182
1183
Ref<GDScript> GDScript::get_base() const {
1184
return base;
1185
}
1186
1187
bool GDScript::inherits_script(const Ref<Script> &p_script) const {
1188
Ref<GDScript> gd = p_script;
1189
if (gd.is_null()) {
1190
return false;
1191
}
1192
1193
const GDScript *s = this;
1194
1195
while (s) {
1196
if (s == p_script.ptr()) {
1197
return true;
1198
}
1199
s = s->_base;
1200
}
1201
1202
return false;
1203
}
1204
1205
GDScript *GDScript::find_class(const String &p_qualified_name) {
1206
String first = p_qualified_name.get_slice("::", 0);
1207
1208
Vector<String> class_names;
1209
GDScript *result = nullptr;
1210
// Empty initial name means start here.
1211
if (first.is_empty() || first == global_name) {
1212
class_names = p_qualified_name.split("::");
1213
result = this;
1214
} else if (p_qualified_name.begins_with(get_root_script()->path)) {
1215
// Script path could have a class path separator("::") in it.
1216
class_names = p_qualified_name.trim_prefix(get_root_script()->path).split("::");
1217
result = get_root_script();
1218
} else if (HashMap<StringName, Ref<GDScript>>::Iterator E = subclasses.find(first)) {
1219
class_names = p_qualified_name.split("::");
1220
result = E->value.ptr();
1221
} else if (_owner != nullptr) {
1222
// Check parent scope.
1223
return _owner->find_class(p_qualified_name);
1224
}
1225
1226
// Starts at index 1 because index 0 was handled above.
1227
for (int i = 1; result != nullptr && i < class_names.size(); i++) {
1228
if (HashMap<StringName, Ref<GDScript>>::Iterator E = result->subclasses.find(class_names[i])) {
1229
result = E->value.ptr();
1230
} else {
1231
// Couldn't find inner class.
1232
return nullptr;
1233
}
1234
}
1235
1236
return result;
1237
}
1238
1239
bool GDScript::has_class(const GDScript *p_script) {
1240
String fqn = p_script->fully_qualified_name;
1241
if (fully_qualified_name.is_empty() && fqn.get_slice("::", 0).is_empty()) {
1242
return p_script == this;
1243
} else if (fqn.begins_with(fully_qualified_name)) {
1244
return p_script == find_class(fqn.trim_prefix(fully_qualified_name));
1245
}
1246
return false;
1247
}
1248
1249
GDScript *GDScript::get_root_script() {
1250
GDScript *result = this;
1251
while (result->_owner) {
1252
result = result->_owner;
1253
}
1254
return result;
1255
}
1256
1257
RBSet<GDScript *> GDScript::get_dependencies() {
1258
RBSet<GDScript *> dependencies;
1259
1260
_collect_dependencies(dependencies, this);
1261
dependencies.erase(this);
1262
1263
return dependencies;
1264
}
1265
1266
HashMap<GDScript *, RBSet<GDScript *>> GDScript::get_all_dependencies() {
1267
HashMap<GDScript *, RBSet<GDScript *>> all_dependencies;
1268
1269
List<GDScript *> scripts;
1270
{
1271
MutexLock lock(GDScriptLanguage::singleton->mutex);
1272
1273
SelfList<GDScript> *elem = GDScriptLanguage::singleton->script_list.first();
1274
while (elem) {
1275
scripts.push_back(elem->self());
1276
elem = elem->next();
1277
}
1278
}
1279
1280
for (GDScript *scr : scripts) {
1281
if (scr == nullptr || scr->destructing) {
1282
continue;
1283
}
1284
all_dependencies.insert(scr, scr->get_dependencies());
1285
}
1286
1287
return all_dependencies;
1288
}
1289
1290
RBSet<GDScript *> GDScript::get_must_clear_dependencies() {
1291
RBSet<GDScript *> dependencies = get_dependencies();
1292
RBSet<GDScript *> must_clear_dependencies;
1293
HashMap<GDScript *, RBSet<GDScript *>> all_dependencies = get_all_dependencies();
1294
1295
RBSet<GDScript *> cant_clear;
1296
for (KeyValue<GDScript *, RBSet<GDScript *>> &E : all_dependencies) {
1297
if (dependencies.has(E.key)) {
1298
continue;
1299
}
1300
for (GDScript *F : E.value) {
1301
if (dependencies.has(F)) {
1302
cant_clear.insert(F);
1303
}
1304
}
1305
}
1306
1307
for (GDScript *E : dependencies) {
1308
if (cant_clear.has(E) || ScriptServer::is_global_class(E->get_fully_qualified_name())) {
1309
continue;
1310
}
1311
must_clear_dependencies.insert(E);
1312
}
1313
1314
cant_clear.clear();
1315
dependencies.clear();
1316
all_dependencies.clear();
1317
return must_clear_dependencies;
1318
}
1319
1320
bool GDScript::has_script_signal(const StringName &p_signal) const {
1321
if (_signals.has(p_signal)) {
1322
return true;
1323
}
1324
if (base.is_valid()) {
1325
return base->has_script_signal(p_signal);
1326
}
1327
#ifdef TOOLS_ENABLED
1328
else if (base_cache.is_valid()) {
1329
return base_cache->has_script_signal(p_signal);
1330
}
1331
#endif
1332
return false;
1333
}
1334
1335
void GDScript::_get_script_signal_list(List<MethodInfo> *r_list, bool p_include_base) const {
1336
for (const KeyValue<StringName, MethodInfo> &E : _signals) {
1337
r_list->push_back(E.value);
1338
}
1339
1340
if (!p_include_base) {
1341
return;
1342
}
1343
1344
if (base.is_valid()) {
1345
base->get_script_signal_list(r_list);
1346
}
1347
#ifdef TOOLS_ENABLED
1348
else if (base_cache.is_valid()) {
1349
base_cache->get_script_signal_list(r_list);
1350
}
1351
#endif
1352
}
1353
1354
void GDScript::get_script_signal_list(List<MethodInfo> *r_signals) const {
1355
_get_script_signal_list(r_signals, true);
1356
}
1357
1358
GDScript *GDScript::_get_gdscript_from_variant(const Variant &p_variant) {
1359
Object *obj = p_variant;
1360
if (obj == nullptr || obj->get_instance_id().is_null()) {
1361
return nullptr;
1362
}
1363
return Object::cast_to<GDScript>(obj);
1364
}
1365
1366
void GDScript::_collect_function_dependencies(GDScriptFunction *p_func, RBSet<GDScript *> &p_dependencies, const GDScript *p_except) {
1367
if (p_func == nullptr) {
1368
return;
1369
}
1370
for (GDScriptFunction *lambda : p_func->lambdas) {
1371
_collect_function_dependencies(lambda, p_dependencies, p_except);
1372
}
1373
for (const Variant &V : p_func->constants) {
1374
GDScript *scr = _get_gdscript_from_variant(V);
1375
if (scr != nullptr && scr != p_except) {
1376
scr->_collect_dependencies(p_dependencies, p_except);
1377
}
1378
}
1379
}
1380
1381
void GDScript::_collect_dependencies(RBSet<GDScript *> &p_dependencies, const GDScript *p_except) {
1382
if (p_dependencies.has(this)) {
1383
return;
1384
}
1385
if (this != p_except) {
1386
p_dependencies.insert(this);
1387
}
1388
1389
for (const KeyValue<StringName, GDScriptFunction *> &E : member_functions) {
1390
_collect_function_dependencies(E.value, p_dependencies, p_except);
1391
}
1392
1393
if (implicit_initializer) {
1394
_collect_function_dependencies(implicit_initializer, p_dependencies, p_except);
1395
}
1396
1397
if (implicit_ready) {
1398
_collect_function_dependencies(implicit_ready, p_dependencies, p_except);
1399
}
1400
1401
if (static_initializer) {
1402
_collect_function_dependencies(static_initializer, p_dependencies, p_except);
1403
}
1404
1405
for (KeyValue<StringName, Ref<GDScript>> &E : subclasses) {
1406
if (E.value != p_except) {
1407
E.value->_collect_dependencies(p_dependencies, p_except);
1408
}
1409
}
1410
1411
for (const KeyValue<StringName, Variant> &E : constants) {
1412
GDScript *scr = _get_gdscript_from_variant(E.value);
1413
if (scr != nullptr && scr != p_except) {
1414
scr->_collect_dependencies(p_dependencies, p_except);
1415
}
1416
}
1417
}
1418
1419
GDScript::GDScript() :
1420
script_list(this) {
1421
{
1422
MutexLock lock(GDScriptLanguage::get_singleton()->mutex);
1423
1424
GDScriptLanguage::get_singleton()->script_list.add(&script_list);
1425
}
1426
1427
path = vformat("gdscript://%d.gd", get_instance_id());
1428
}
1429
1430
void GDScript::_save_orphaned_subclasses(ClearData *p_clear_data) {
1431
struct ClassRefWithName {
1432
ObjectID id;
1433
String fully_qualified_name;
1434
};
1435
Vector<ClassRefWithName> weak_subclasses;
1436
// collect subclasses ObjectID and name
1437
for (KeyValue<StringName, Ref<GDScript>> &E : subclasses) {
1438
E.value->_owner = nullptr; //bye, you are no longer owned cause I died
1439
ClassRefWithName subclass;
1440
subclass.id = E.value->get_instance_id();
1441
subclass.fully_qualified_name = E.value->fully_qualified_name;
1442
weak_subclasses.push_back(subclass);
1443
}
1444
1445
// clear subclasses to allow unused subclasses to be deleted
1446
for (KeyValue<StringName, Ref<GDScript>> &E : subclasses) {
1447
p_clear_data->scripts.insert(E.value);
1448
}
1449
subclasses.clear();
1450
// subclasses are also held by constants, clear those as well
1451
for (KeyValue<StringName, Variant> &E : constants) {
1452
GDScript *gdscr = _get_gdscript_from_variant(E.value);
1453
if (gdscr != nullptr) {
1454
p_clear_data->scripts.insert(gdscr);
1455
}
1456
}
1457
constants.clear();
1458
1459
// keep orphan subclass only for subclasses that are still in use
1460
for (int i = 0; i < weak_subclasses.size(); i++) {
1461
ClassRefWithName subclass = weak_subclasses[i];
1462
Object *obj = ObjectDB::get_instance(subclass.id);
1463
if (!obj) {
1464
continue;
1465
}
1466
// subclass is not released
1467
GDScriptLanguage::get_singleton()->add_orphan_subclass(subclass.fully_qualified_name, subclass.id);
1468
}
1469
}
1470
1471
#ifdef DEBUG_ENABLED
1472
String GDScript::debug_get_script_name(const Ref<Script> &p_script) {
1473
if (p_script.is_valid()) {
1474
Ref<GDScript> gdscript = p_script;
1475
if (gdscript.is_valid()) {
1476
if (gdscript->get_local_name() != StringName()) {
1477
return gdscript->get_local_name();
1478
}
1479
return gdscript->get_fully_qualified_name().get_file();
1480
}
1481
1482
if (p_script->get_global_name() != StringName()) {
1483
return p_script->get_global_name();
1484
} else if (!p_script->get_path().is_empty()) {
1485
return p_script->get_path().get_file();
1486
} else if (!p_script->get_name().is_empty()) {
1487
return p_script->get_name(); // Resource name.
1488
}
1489
}
1490
1491
return "<unknown script>";
1492
}
1493
#endif
1494
1495
String GDScript::canonicalize_path(const String &p_path) {
1496
if (p_path.get_extension() == "gdc") {
1497
return p_path.get_basename() + ".gd";
1498
}
1499
return p_path;
1500
}
1501
1502
GDScript::UpdatableFuncPtr::UpdatableFuncPtr(GDScriptFunction *p_function) {
1503
if (p_function == nullptr) {
1504
return;
1505
}
1506
1507
ptr = p_function;
1508
script = ptr->get_script();
1509
ERR_FAIL_NULL(script);
1510
1511
MutexLock script_lock(script->func_ptrs_to_update_mutex);
1512
list_element = script->func_ptrs_to_update.push_back(this);
1513
}
1514
1515
GDScript::UpdatableFuncPtr::~UpdatableFuncPtr() {
1516
ERR_FAIL_NULL(script);
1517
1518
if (list_element) {
1519
MutexLock script_lock(script->func_ptrs_to_update_mutex);
1520
list_element->erase();
1521
list_element = nullptr;
1522
}
1523
}
1524
1525
void GDScript::_recurse_replace_function_ptrs(const HashMap<GDScriptFunction *, GDScriptFunction *> &p_replacements) const {
1526
MutexLock lock(func_ptrs_to_update_mutex);
1527
for (UpdatableFuncPtr *updatable : func_ptrs_to_update) {
1528
HashMap<GDScriptFunction *, GDScriptFunction *>::ConstIterator replacement = p_replacements.find(updatable->ptr);
1529
if (replacement) {
1530
updatable->ptr = replacement->value;
1531
} else {
1532
// Probably a lambda from another reload, ignore.
1533
updatable->ptr = nullptr;
1534
}
1535
}
1536
1537
for (HashMap<StringName, Ref<GDScript>>::ConstIterator subscript = subclasses.begin(); subscript; ++subscript) {
1538
subscript->value->_recurse_replace_function_ptrs(p_replacements);
1539
}
1540
}
1541
1542
void GDScript::clear(ClearData *p_clear_data) {
1543
if (clearing) {
1544
return;
1545
}
1546
clearing = true;
1547
1548
ClearData data;
1549
ClearData *clear_data = p_clear_data;
1550
bool is_root = false;
1551
1552
// If `clear_data` is `nullptr`, it means that it's the root.
1553
// The root is in charge to clear functions and scripts of itself and its dependencies
1554
if (clear_data == nullptr) {
1555
clear_data = &data;
1556
is_root = true;
1557
}
1558
1559
{
1560
MutexLock lock(func_ptrs_to_update_mutex);
1561
for (UpdatableFuncPtr *updatable : func_ptrs_to_update) {
1562
updatable->ptr = nullptr;
1563
}
1564
}
1565
1566
// If we're in the process of shutting things down then every single script will be cleared
1567
// anyway, so we can safely skip this very costly operation.
1568
if (!GDScriptLanguage::singleton->finishing) {
1569
RBSet<GDScript *> must_clear_dependencies = get_must_clear_dependencies();
1570
for (GDScript *E : must_clear_dependencies) {
1571
clear_data->scripts.insert(E);
1572
E->clear(clear_data);
1573
}
1574
}
1575
1576
for (const KeyValue<StringName, GDScriptFunction *> &E : member_functions) {
1577
clear_data->functions.insert(E.value);
1578
}
1579
member_functions.clear();
1580
1581
for (KeyValue<StringName, MemberInfo> &E : member_indices) {
1582
clear_data->scripts.insert(E.value.data_type.script_type_ref);
1583
E.value.data_type.script_type_ref = Ref<Script>();
1584
}
1585
1586
for (KeyValue<StringName, MemberInfo> &E : static_variables_indices) {
1587
clear_data->scripts.insert(E.value.data_type.script_type_ref);
1588
E.value.data_type.script_type_ref = Ref<Script>();
1589
}
1590
static_variables.clear();
1591
static_variables_indices.clear();
1592
1593
if (implicit_initializer) {
1594
clear_data->functions.insert(implicit_initializer);
1595
implicit_initializer = nullptr;
1596
}
1597
1598
if (implicit_ready) {
1599
clear_data->functions.insert(implicit_ready);
1600
implicit_ready = nullptr;
1601
}
1602
1603
if (static_initializer) {
1604
clear_data->functions.insert(static_initializer);
1605
static_initializer = nullptr;
1606
}
1607
1608
_save_orphaned_subclasses(clear_data);
1609
1610
#ifdef TOOLS_ENABLED
1611
// Clearing inner class doc, script doc only cleared when the script source deleted.
1612
if (_owner) {
1613
_clear_doc();
1614
}
1615
#endif
1616
1617
// If it's not the root, skip clearing the data
1618
if (is_root) {
1619
// All dependencies have been accounted for
1620
for (GDScriptFunction *E : clear_data->functions) {
1621
memdelete(E);
1622
}
1623
for (Ref<Script> &E : clear_data->scripts) {
1624
Ref<GDScript> gdscr = E;
1625
if (gdscr.is_valid()) {
1626
GDScriptCache::remove_script(gdscr->get_path());
1627
}
1628
}
1629
clear_data->clear();
1630
}
1631
}
1632
1633
void GDScript::cancel_pending_functions(bool warn) {
1634
MutexLock lock(GDScriptLanguage::get_singleton()->mutex);
1635
1636
while (SelfList<GDScriptFunctionState> *E = pending_func_states.first()) {
1637
// Order matters since clearing the stack may already cause
1638
// the GDScriptFunctionState to be destroyed and thus removed from the list.
1639
pending_func_states.remove(E);
1640
GDScriptFunctionState *state = E->self();
1641
#ifdef DEBUG_ENABLED
1642
if (warn) {
1643
WARN_PRINT("Canceling suspended execution of \"" + state->get_readable_function() + "\" due to a script reload.");
1644
}
1645
#endif
1646
ObjectID state_id = state->get_instance_id();
1647
state->_clear_connections();
1648
if (ObjectDB::get_instance(state_id)) {
1649
state->_clear_stack();
1650
}
1651
}
1652
}
1653
1654
GDScript::~GDScript() {
1655
if (destructing) {
1656
return;
1657
}
1658
destructing = true;
1659
1660
if (is_print_verbose_enabled()) {
1661
MutexLock lock(func_ptrs_to_update_mutex);
1662
if (!func_ptrs_to_update.is_empty()) {
1663
print_line(vformat("GDScript: %d orphaned lambdas becoming invalid at destruction of script '%s'.", func_ptrs_to_update.size(), fully_qualified_name));
1664
}
1665
}
1666
1667
clear();
1668
1669
cancel_pending_functions(false);
1670
1671
{
1672
MutexLock lock(GDScriptLanguage::get_singleton()->mutex);
1673
1674
script_list.remove_from_list();
1675
}
1676
}
1677
1678
//////////////////////////////
1679
// INSTANCE //
1680
//////////////////////////////
1681
1682
bool GDScriptInstance::set(const StringName &p_name, const Variant &p_value) {
1683
{
1684
HashMap<StringName, GDScript::MemberInfo>::Iterator E = script->member_indices.find(p_name);
1685
if (E) {
1686
const GDScript::MemberInfo *member = &E->value;
1687
Variant value = p_value;
1688
if (member->data_type.has_type && !member->data_type.is_type(value)) {
1689
const Variant *args = &p_value;
1690
Callable::CallError err;
1691
Variant::construct(member->data_type.builtin_type, value, &args, 1, err);
1692
if (err.error != Callable::CallError::CALL_OK || !member->data_type.is_type(value)) {
1693
return false;
1694
}
1695
}
1696
if (likely(script->valid) && member->setter) {
1697
const Variant *args = &value;
1698
Callable::CallError err;
1699
callp(member->setter, &args, 1, err);
1700
return err.error == Callable::CallError::CALL_OK;
1701
} else {
1702
members.write[member->index] = value;
1703
return true;
1704
}
1705
}
1706
}
1707
1708
GDScript *sptr = script.ptr();
1709
while (sptr) {
1710
{
1711
HashMap<StringName, GDScript::MemberInfo>::ConstIterator E = sptr->static_variables_indices.find(p_name);
1712
if (E) {
1713
const GDScript::MemberInfo *member = &E->value;
1714
Variant value = p_value;
1715
if (member->data_type.has_type && !member->data_type.is_type(value)) {
1716
const Variant *args = &p_value;
1717
Callable::CallError err;
1718
Variant::construct(member->data_type.builtin_type, value, &args, 1, err);
1719
if (err.error != Callable::CallError::CALL_OK || !member->data_type.is_type(value)) {
1720
return false;
1721
}
1722
}
1723
if (likely(sptr->valid) && member->setter) {
1724
const Variant *args = &value;
1725
Callable::CallError err;
1726
callp(member->setter, &args, 1, err);
1727
return err.error == Callable::CallError::CALL_OK;
1728
} else {
1729
sptr->static_variables.write[member->index] = value;
1730
return true;
1731
}
1732
}
1733
}
1734
1735
if (likely(sptr->valid)) {
1736
HashMap<StringName, GDScriptFunction *>::Iterator E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._set);
1737
if (E) {
1738
Variant name = p_name;
1739
const Variant *args[2] = { &name, &p_value };
1740
1741
Callable::CallError err;
1742
Variant ret = E->value->call(this, (const Variant **)args, 2, err);
1743
if (err.error == Callable::CallError::CALL_OK && ret.get_type() == Variant::BOOL && ret.operator bool()) {
1744
return true;
1745
}
1746
}
1747
}
1748
1749
sptr = sptr->_base;
1750
}
1751
1752
return false;
1753
}
1754
1755
bool GDScriptInstance::get(const StringName &p_name, Variant &r_ret) const {
1756
{
1757
HashMap<StringName, GDScript::MemberInfo>::ConstIterator E = script->member_indices.find(p_name);
1758
if (E) {
1759
if (likely(script->valid) && E->value.getter) {
1760
Callable::CallError err;
1761
const Variant ret = const_cast<GDScriptInstance *>(this)->callp(E->value.getter, nullptr, 0, err);
1762
r_ret = (err.error == Callable::CallError::CALL_OK) ? ret : Variant();
1763
return true;
1764
}
1765
r_ret = members[E->value.index];
1766
return true;
1767
}
1768
}
1769
1770
const GDScript *sptr = script.ptr();
1771
while (sptr) {
1772
{
1773
HashMap<StringName, Variant>::ConstIterator E = sptr->constants.find(p_name);
1774
if (E) {
1775
r_ret = E->value;
1776
return true;
1777
}
1778
}
1779
1780
{
1781
HashMap<StringName, GDScript::MemberInfo>::ConstIterator E = sptr->static_variables_indices.find(p_name);
1782
if (E) {
1783
if (likely(sptr->valid) && E->value.getter) {
1784
Callable::CallError ce;
1785
const Variant ret = const_cast<GDScript *>(sptr)->callp(E->value.getter, nullptr, 0, ce);
1786
r_ret = (ce.error == Callable::CallError::CALL_OK) ? ret : Variant();
1787
return true;
1788
}
1789
r_ret = sptr->static_variables[E->value.index];
1790
return true;
1791
}
1792
}
1793
1794
{
1795
HashMap<StringName, MethodInfo>::ConstIterator E = sptr->_signals.find(p_name);
1796
if (E) {
1797
r_ret = Signal(owner, E->key);
1798
return true;
1799
}
1800
}
1801
1802
if (likely(sptr->valid)) {
1803
HashMap<StringName, GDScriptFunction *>::ConstIterator E = sptr->member_functions.find(p_name);
1804
if (E) {
1805
if (sptr->rpc_config.has(p_name)) {
1806
r_ret = Callable(memnew(GDScriptRPCCallable(owner, E->key)));
1807
} else {
1808
r_ret = Callable(owner, E->key);
1809
}
1810
return true;
1811
}
1812
}
1813
1814
{
1815
HashMap<StringName, Ref<GDScript>>::ConstIterator E = sptr->subclasses.find(p_name);
1816
if (E) {
1817
r_ret = E->value;
1818
return true;
1819
}
1820
}
1821
1822
if (likely(sptr->valid)) {
1823
HashMap<StringName, GDScriptFunction *>::ConstIterator E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._get);
1824
if (E) {
1825
Variant name = p_name;
1826
const Variant *args[1] = { &name };
1827
1828
Callable::CallError err;
1829
Variant ret = E->value->call(const_cast<GDScriptInstance *>(this), (const Variant **)args, 1, err);
1830
if (err.error == Callable::CallError::CALL_OK && ret.get_type() != Variant::NIL) {
1831
r_ret = ret;
1832
return true;
1833
}
1834
}
1835
}
1836
sptr = sptr->_base;
1837
}
1838
1839
return false;
1840
}
1841
1842
Variant::Type GDScriptInstance::get_property_type(const StringName &p_name, bool *r_is_valid) const {
1843
if (script->member_indices.has(p_name)) {
1844
if (r_is_valid) {
1845
*r_is_valid = true;
1846
}
1847
return script->member_indices[p_name].property_info.type;
1848
}
1849
1850
if (r_is_valid) {
1851
*r_is_valid = false;
1852
}
1853
return Variant::NIL;
1854
}
1855
1856
void GDScriptInstance::validate_property(PropertyInfo &p_property) const {
1857
const GDScript *sptr = script.ptr();
1858
while (sptr) {
1859
if (likely(sptr->valid)) {
1860
HashMap<StringName, GDScriptFunction *>::ConstIterator E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._validate_property);
1861
if (E) {
1862
Variant property = (Dictionary)p_property;
1863
const Variant *args[1] = { &property };
1864
1865
Callable::CallError err;
1866
Variant ret = E->value->call(const_cast<GDScriptInstance *>(this), args, 1, err);
1867
if (err.error == Callable::CallError::CALL_OK) {
1868
p_property = PropertyInfo::from_dict(property);
1869
return;
1870
}
1871
}
1872
}
1873
sptr = sptr->_base;
1874
}
1875
}
1876
1877
void GDScriptInstance::get_property_list(List<PropertyInfo> *p_properties) const {
1878
// exported members, not done yet!
1879
1880
const GDScript *sptr = script.ptr();
1881
List<PropertyInfo> props;
1882
1883
while (sptr) {
1884
if (likely(sptr->valid)) {
1885
HashMap<StringName, GDScriptFunction *>::ConstIterator E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._get_property_list);
1886
if (E) {
1887
Callable::CallError err;
1888
Variant ret = E->value->call(const_cast<GDScriptInstance *>(this), nullptr, 0, err);
1889
if (err.error == Callable::CallError::CALL_OK) {
1890
ERR_FAIL_COND_MSG(ret.get_type() != Variant::ARRAY, "Wrong type for _get_property_list, must be an array of dictionaries.");
1891
1892
Array arr = ret;
1893
for (int i = 0; i < arr.size(); i++) {
1894
Dictionary d = arr[i];
1895
ERR_CONTINUE(!d.has("name"));
1896
ERR_CONTINUE(!d.has("type"));
1897
1898
PropertyInfo pinfo;
1899
pinfo.name = d["name"];
1900
pinfo.type = Variant::Type(d["type"].operator int());
1901
if (d.has("hint")) {
1902
pinfo.hint = PropertyHint(d["hint"].operator int());
1903
}
1904
if (d.has("hint_string")) {
1905
pinfo.hint_string = d["hint_string"];
1906
}
1907
if (d.has("usage")) {
1908
pinfo.usage = d["usage"];
1909
}
1910
if (d.has("class_name")) {
1911
pinfo.class_name = d["class_name"];
1912
}
1913
1914
ERR_CONTINUE(pinfo.name.is_empty() && (pinfo.usage & PROPERTY_USAGE_STORAGE));
1915
ERR_CONTINUE(pinfo.type < 0 || pinfo.type >= Variant::VARIANT_MAX);
1916
1917
props.push_back(pinfo);
1918
}
1919
}
1920
}
1921
}
1922
1923
//instance a fake script for editing the values
1924
1925
Vector<_GDScriptMemberSort> msort;
1926
for (const KeyValue<StringName, GDScript::MemberInfo> &F : sptr->member_indices) {
1927
if (!sptr->members.has(F.key)) {
1928
continue; // Skip base class members.
1929
}
1930
_GDScriptMemberSort ms;
1931
ms.index = F.value.index;
1932
ms.name = F.key;
1933
msort.push_back(ms);
1934
}
1935
1936
msort.sort();
1937
msort.reverse();
1938
for (int i = 0; i < msort.size(); i++) {
1939
props.push_front(sptr->member_indices[msort[i].name].property_info);
1940
}
1941
1942
#ifdef TOOLS_ENABLED
1943
p_properties->push_back(sptr->get_class_category());
1944
#endif // TOOLS_ENABLED
1945
1946
for (PropertyInfo &prop : props) {
1947
validate_property(prop);
1948
p_properties->push_back(prop);
1949
}
1950
1951
props.clear();
1952
1953
sptr = sptr->_base;
1954
}
1955
}
1956
1957
bool GDScriptInstance::property_can_revert(const StringName &p_name) const {
1958
Variant name = p_name;
1959
const Variant *args[1] = { &name };
1960
1961
const GDScript *sptr = script.ptr();
1962
while (sptr) {
1963
if (likely(sptr->valid)) {
1964
HashMap<StringName, GDScriptFunction *>::ConstIterator E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._property_can_revert);
1965
if (E) {
1966
Callable::CallError err;
1967
Variant ret = E->value->call(const_cast<GDScriptInstance *>(this), args, 1, err);
1968
if (err.error == Callable::CallError::CALL_OK && ret.get_type() == Variant::BOOL && ret.operator bool()) {
1969
return true;
1970
}
1971
}
1972
}
1973
sptr = sptr->_base;
1974
}
1975
1976
return false;
1977
}
1978
1979
bool GDScriptInstance::property_get_revert(const StringName &p_name, Variant &r_ret) const {
1980
Variant name = p_name;
1981
const Variant *args[1] = { &name };
1982
1983
const GDScript *sptr = script.ptr();
1984
while (sptr) {
1985
if (likely(sptr->valid)) {
1986
HashMap<StringName, GDScriptFunction *>::ConstIterator E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._property_get_revert);
1987
if (E) {
1988
Callable::CallError err;
1989
Variant ret = E->value->call(const_cast<GDScriptInstance *>(this), args, 1, err);
1990
if (err.error == Callable::CallError::CALL_OK && ret.get_type() != Variant::NIL) {
1991
r_ret = ret;
1992
return true;
1993
}
1994
}
1995
}
1996
sptr = sptr->_base;
1997
}
1998
1999
return false;
2000
}
2001
2002
void GDScriptInstance::get_method_list(List<MethodInfo> *p_list) const {
2003
const GDScript *sptr = script.ptr();
2004
while (sptr) {
2005
for (const KeyValue<StringName, GDScriptFunction *> &E : sptr->member_functions) {
2006
p_list->push_back(E.value->get_method_info());
2007
}
2008
sptr = sptr->_base;
2009
}
2010
}
2011
2012
bool GDScriptInstance::has_method(const StringName &p_method) const {
2013
const GDScript *sptr = script.ptr();
2014
while (sptr) {
2015
HashMap<StringName, GDScriptFunction *>::ConstIterator E = sptr->member_functions.find(p_method);
2016
if (E) {
2017
return true;
2018
}
2019
sptr = sptr->_base;
2020
}
2021
2022
return false;
2023
}
2024
2025
int GDScriptInstance::get_method_argument_count(const StringName &p_method, bool *r_is_valid) const {
2026
const GDScript *sptr = script.ptr();
2027
while (sptr) {
2028
HashMap<StringName, GDScriptFunction *>::ConstIterator E = sptr->member_functions.find(p_method);
2029
if (E) {
2030
if (r_is_valid) {
2031
*r_is_valid = true;
2032
}
2033
return E->value->get_argument_count();
2034
}
2035
sptr = sptr->_base;
2036
}
2037
2038
if (r_is_valid) {
2039
*r_is_valid = false;
2040
}
2041
return 0;
2042
}
2043
2044
void GDScriptInstance::_call_implicit_ready_recursively(GDScript *p_script) {
2045
// Call base class first.
2046
if (p_script->_base) {
2047
_call_implicit_ready_recursively(p_script->_base);
2048
}
2049
if (likely(p_script->valid) && p_script->implicit_ready) {
2050
Callable::CallError err;
2051
p_script->implicit_ready->call(this, nullptr, 0, err);
2052
}
2053
}
2054
2055
Variant GDScriptInstance::callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
2056
GDScript *sptr = script.ptr();
2057
if (unlikely(p_method == SceneStringName(_ready))) {
2058
// Call implicit ready first, including for the super classes recursively.
2059
_call_implicit_ready_recursively(sptr);
2060
}
2061
while (sptr) {
2062
if (likely(sptr->valid)) {
2063
HashMap<StringName, GDScriptFunction *>::Iterator E = sptr->member_functions.find(p_method);
2064
if (E) {
2065
return E->value->call(this, p_args, p_argcount, r_error);
2066
}
2067
}
2068
sptr = sptr->_base;
2069
}
2070
2071
r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
2072
return Variant();
2073
}
2074
2075
void GDScriptInstance::notification(int p_notification, bool p_reversed) {
2076
if (unlikely(!script->valid)) {
2077
return;
2078
}
2079
2080
//notification is not virtual, it gets called at ALL levels just like in C.
2081
Variant value = p_notification;
2082
const Variant *args[1] = { &value };
2083
2084
List<GDScript *> pl;
2085
GDScript *sptr = script.ptr();
2086
while (sptr) {
2087
if (p_reversed) {
2088
pl.push_back(sptr);
2089
} else {
2090
pl.push_front(sptr);
2091
}
2092
sptr = sptr->_base;
2093
}
2094
for (GDScript *sc : pl) {
2095
if (likely(sc->valid)) {
2096
HashMap<StringName, GDScriptFunction *>::Iterator E = sc->member_functions.find(GDScriptLanguage::get_singleton()->strings._notification);
2097
if (E) {
2098
Callable::CallError err;
2099
E->value->call(this, args, 1, err);
2100
if (err.error != Callable::CallError::CALL_OK) {
2101
//print error about notification call
2102
}
2103
}
2104
}
2105
}
2106
}
2107
2108
String GDScriptInstance::to_string(bool *r_valid) {
2109
if (has_method(CoreStringName(_to_string))) {
2110
Callable::CallError ce;
2111
Variant ret = callp(CoreStringName(_to_string), nullptr, 0, ce);
2112
if (ce.error == Callable::CallError::CALL_OK) {
2113
if (ret.get_type() != Variant::STRING) {
2114
if (r_valid) {
2115
*r_valid = false;
2116
}
2117
ERR_FAIL_V_MSG(String(), "Wrong type for " + CoreStringName(_to_string) + ", must be a String.");
2118
}
2119
if (r_valid) {
2120
*r_valid = true;
2121
}
2122
return ret.operator String();
2123
}
2124
}
2125
if (r_valid) {
2126
*r_valid = false;
2127
}
2128
return String();
2129
}
2130
2131
Ref<Script> GDScriptInstance::get_script() const {
2132
return script;
2133
}
2134
2135
ScriptLanguage *GDScriptInstance::get_language() {
2136
return GDScriptLanguage::get_singleton();
2137
}
2138
2139
const Variant GDScriptInstance::get_rpc_config() const {
2140
return script->get_rpc_config();
2141
}
2142
2143
void GDScriptInstance::reload_members() {
2144
#ifdef DEBUG_ENABLED
2145
2146
Vector<Variant> new_members;
2147
new_members.resize(script->member_indices.size());
2148
2149
//pass the values to the new indices
2150
for (KeyValue<StringName, GDScript::MemberInfo> &E : script->member_indices) {
2151
if (member_indices_cache.has(E.key)) {
2152
Variant value = members[member_indices_cache[E.key]];
2153
new_members.write[E.value.index] = value;
2154
}
2155
}
2156
2157
members.resize(new_members.size()); //resize
2158
2159
//apply
2160
members = new_members;
2161
2162
//pass the values to the new indices
2163
member_indices_cache.clear();
2164
for (const KeyValue<StringName, GDScript::MemberInfo> &E : script->member_indices) {
2165
member_indices_cache[E.key] = E.value.index;
2166
}
2167
2168
#endif
2169
}
2170
2171
GDScriptInstance::GDScriptInstance() {
2172
owner = nullptr;
2173
base_ref_counted = false;
2174
}
2175
2176
GDScriptInstance::~GDScriptInstance() {
2177
MutexLock lock(GDScriptLanguage::get_singleton()->mutex);
2178
2179
while (SelfList<GDScriptFunctionState> *E = pending_func_states.first()) {
2180
// Order matters since clearing the stack may already cause
2181
// the GDSCriptFunctionState to be destroyed and thus removed from the list.
2182
pending_func_states.remove(E);
2183
GDScriptFunctionState *state = E->self();
2184
ObjectID state_id = state->get_instance_id();
2185
state->_clear_connections();
2186
if (ObjectDB::get_instance(state_id)) {
2187
state->_clear_stack();
2188
}
2189
}
2190
2191
if (script.is_valid() && owner) {
2192
script->instances.erase(owner);
2193
}
2194
}
2195
2196
/************* SCRIPT LANGUAGE **************/
2197
2198
GDScriptLanguage *GDScriptLanguage::singleton = nullptr;
2199
2200
String GDScriptLanguage::get_name() const {
2201
return "GDScript";
2202
}
2203
2204
/* LANGUAGE FUNCTIONS */
2205
2206
void GDScriptLanguage::_add_global(const StringName &p_name, const Variant &p_value) {
2207
if (globals.has(p_name)) {
2208
//overwrite existing
2209
global_array.write[globals[p_name]] = p_value;
2210
return;
2211
}
2212
2213
if (global_array_empty_indexes.size()) {
2214
int index = global_array_empty_indexes[global_array_empty_indexes.size() - 1];
2215
globals[p_name] = index;
2216
global_array.write[index] = p_value;
2217
global_array_empty_indexes.resize(global_array_empty_indexes.size() - 1);
2218
} else {
2219
globals[p_name] = global_array.size();
2220
global_array.push_back(p_value);
2221
_global_array = global_array.ptrw();
2222
}
2223
}
2224
2225
void GDScriptLanguage::_remove_global(const StringName &p_name) {
2226
if (!globals.has(p_name)) {
2227
return;
2228
}
2229
global_array_empty_indexes.push_back(globals[p_name]);
2230
global_array.write[globals[p_name]] = Variant::NIL;
2231
globals.erase(p_name);
2232
}
2233
2234
void GDScriptLanguage::add_global_constant(const StringName &p_variable, const Variant &p_value) {
2235
_add_global(p_variable, p_value);
2236
}
2237
2238
void GDScriptLanguage::add_named_global_constant(const StringName &p_name, const Variant &p_value) {
2239
named_globals[p_name] = p_value;
2240
}
2241
2242
Variant GDScriptLanguage::get_any_global_constant(const StringName &p_name) {
2243
if (named_globals.has(p_name)) {
2244
return named_globals[p_name];
2245
}
2246
if (globals.has(p_name)) {
2247
return _global_array[globals[p_name]];
2248
}
2249
ERR_FAIL_V_MSG(Variant(), vformat("Could not find any global constant with name: %s.", p_name));
2250
}
2251
2252
void GDScriptLanguage::remove_named_global_constant(const StringName &p_name) {
2253
ERR_FAIL_COND(!named_globals.has(p_name));
2254
named_globals.erase(p_name);
2255
}
2256
2257
void GDScriptLanguage::init() {
2258
//populate global constants
2259
int gcc = CoreConstants::get_global_constant_count();
2260
for (int i = 0; i < gcc; i++) {
2261
_add_global(StringName(CoreConstants::get_global_constant_name(i)), CoreConstants::get_global_constant_value(i));
2262
}
2263
2264
_add_global(StringName("PI"), Math::PI);
2265
_add_global(StringName("TAU"), Math::TAU);
2266
_add_global(StringName("INF"), Math::INF);
2267
_add_global(StringName("NAN"), Math::NaN);
2268
2269
//populate native classes
2270
2271
List<StringName> class_list;
2272
ClassDB::get_class_list(&class_list);
2273
for (const StringName &n : class_list) {
2274
if (globals.has(n)) {
2275
continue;
2276
}
2277
Ref<GDScriptNativeClass> nc = memnew(GDScriptNativeClass(n));
2278
_add_global(n, nc);
2279
}
2280
2281
//populate singletons
2282
2283
List<Engine::Singleton> singletons;
2284
Engine::get_singleton()->get_singletons(&singletons);
2285
for (const Engine::Singleton &E : singletons) {
2286
_add_global(E.name, E.ptr);
2287
}
2288
2289
#ifdef TOOLS_ENABLED
2290
if (Engine::get_singleton()->is_editor_hint()) {
2291
GDExtensionManager::get_singleton()->connect("extension_loaded", callable_mp(this, &GDScriptLanguage::_extension_loaded));
2292
GDExtensionManager::get_singleton()->connect("extension_unloading", callable_mp(this, &GDScriptLanguage::_extension_unloading));
2293
}
2294
#endif
2295
2296
#ifdef TESTS_ENABLED
2297
GDScriptTests::GDScriptTestRunner::handle_cmdline();
2298
#endif
2299
}
2300
2301
#ifdef TOOLS_ENABLED
2302
void GDScriptLanguage::_extension_loaded(const Ref<GDExtension> &p_extension) {
2303
List<StringName> class_list;
2304
ClassDB::get_extension_class_list(p_extension, &class_list);
2305
for (const StringName &n : class_list) {
2306
if (globals.has(n)) {
2307
continue;
2308
}
2309
Ref<GDScriptNativeClass> nc = memnew(GDScriptNativeClass(n));
2310
_add_global(n, nc);
2311
}
2312
}
2313
2314
void GDScriptLanguage::_extension_unloading(const Ref<GDExtension> &p_extension) {
2315
List<StringName> class_list;
2316
ClassDB::get_extension_class_list(p_extension, &class_list);
2317
for (const StringName &n : class_list) {
2318
_remove_global(n);
2319
}
2320
}
2321
#endif
2322
2323
String GDScriptLanguage::get_type() const {
2324
return "GDScript";
2325
}
2326
2327
String GDScriptLanguage::get_extension() const {
2328
return "gd";
2329
}
2330
2331
void GDScriptLanguage::finish() {
2332
if (finishing) {
2333
return;
2334
}
2335
finishing = true;
2336
2337
// Clear the cache before parsing the script_list
2338
GDScriptCache::clear();
2339
2340
// Clear dependencies between scripts, to ensure cyclic references are broken
2341
// (to avoid leaks at exit).
2342
SelfList<GDScript> *s = script_list.first();
2343
while (s) {
2344
// This ensures the current script is not released before we can check
2345
// what's the next one in the list (we can't get the next upfront because we
2346
// don't know if the reference breaking will cause it -or any other after
2347
// it, for that matter- to be released so the next one is not the same as
2348
// before).
2349
Ref<GDScript> scr = s->self();
2350
if (scr.is_valid()) {
2351
for (KeyValue<StringName, GDScriptFunction *> &E : scr->member_functions) {
2352
GDScriptFunction *func = E.value;
2353
for (int i = 0; i < func->argument_types.size(); i++) {
2354
func->argument_types.write[i].script_type_ref = Ref<Script>();
2355
}
2356
func->return_type.script_type_ref = Ref<Script>();
2357
}
2358
for (KeyValue<StringName, GDScript::MemberInfo> &E : scr->member_indices) {
2359
E.value.data_type.script_type_ref = Ref<Script>();
2360
}
2361
2362
// Clear backup for scripts that could slip out of the cyclic reference
2363
// check
2364
scr->clear();
2365
}
2366
s = s->next();
2367
}
2368
script_list.clear();
2369
function_list.clear();
2370
2371
finishing = false;
2372
}
2373
2374
void GDScriptLanguage::profiling_start() {
2375
#ifdef DEBUG_ENABLED
2376
MutexLock lock(mutex);
2377
2378
SelfList<GDScriptFunction> *elem = function_list.first();
2379
while (elem) {
2380
elem->self()->profile.call_count.set(0);
2381
elem->self()->profile.self_time.set(0);
2382
elem->self()->profile.total_time.set(0);
2383
elem->self()->profile.frame_call_count.set(0);
2384
elem->self()->profile.frame_self_time.set(0);
2385
elem->self()->profile.frame_total_time.set(0);
2386
elem->self()->profile.last_frame_call_count = 0;
2387
elem->self()->profile.last_frame_self_time = 0;
2388
elem->self()->profile.last_frame_total_time = 0;
2389
elem->self()->profile.native_calls.clear();
2390
elem->self()->profile.last_native_calls.clear();
2391
elem = elem->next();
2392
}
2393
2394
profiling = true;
2395
#endif
2396
}
2397
2398
void GDScriptLanguage::profiling_set_save_native_calls(bool p_enable) {
2399
#ifdef DEBUG_ENABLED
2400
MutexLock lock(mutex);
2401
profile_native_calls = p_enable;
2402
#endif
2403
}
2404
2405
void GDScriptLanguage::profiling_stop() {
2406
#ifdef DEBUG_ENABLED
2407
MutexLock lock(mutex);
2408
2409
profiling = false;
2410
#endif
2411
}
2412
2413
int GDScriptLanguage::profiling_get_accumulated_data(ProfilingInfo *p_info_arr, int p_info_max) {
2414
int current = 0;
2415
#ifdef DEBUG_ENABLED
2416
2417
MutexLock lock(mutex);
2418
2419
profiling_collate_native_call_data(true);
2420
SelfList<GDScriptFunction> *elem = function_list.first();
2421
while (elem) {
2422
if (current >= p_info_max) {
2423
break;
2424
}
2425
int last_non_internal = current;
2426
p_info_arr[current].call_count = elem->self()->profile.call_count.get();
2427
p_info_arr[current].self_time = elem->self()->profile.self_time.get();
2428
p_info_arr[current].total_time = elem->self()->profile.total_time.get();
2429
p_info_arr[current].signature = elem->self()->profile.signature;
2430
current++;
2431
2432
int nat_time = 0;
2433
HashMap<String, GDScriptFunction::Profile::NativeProfile>::ConstIterator nat_calls = elem->self()->profile.native_calls.begin();
2434
while (nat_calls) {
2435
p_info_arr[current].call_count = nat_calls->value.call_count;
2436
p_info_arr[current].total_time = nat_calls->value.total_time;
2437
p_info_arr[current].self_time = nat_calls->value.total_time;
2438
p_info_arr[current].signature = nat_calls->value.signature;
2439
nat_time += nat_calls->value.total_time;
2440
current++;
2441
++nat_calls;
2442
}
2443
p_info_arr[last_non_internal].internal_time = nat_time;
2444
elem = elem->next();
2445
}
2446
#endif
2447
2448
return current;
2449
}
2450
2451
int GDScriptLanguage::profiling_get_frame_data(ProfilingInfo *p_info_arr, int p_info_max) {
2452
int current = 0;
2453
2454
#ifdef DEBUG_ENABLED
2455
MutexLock lock(mutex);
2456
2457
profiling_collate_native_call_data(false);
2458
SelfList<GDScriptFunction> *elem = function_list.first();
2459
while (elem) {
2460
if (current >= p_info_max) {
2461
break;
2462
}
2463
if (elem->self()->profile.last_frame_call_count > 0) {
2464
int last_non_internal = current;
2465
p_info_arr[current].call_count = elem->self()->profile.last_frame_call_count;
2466
p_info_arr[current].self_time = elem->self()->profile.last_frame_self_time;
2467
p_info_arr[current].total_time = elem->self()->profile.last_frame_total_time;
2468
p_info_arr[current].signature = elem->self()->profile.signature;
2469
current++;
2470
2471
int nat_time = 0;
2472
HashMap<String, GDScriptFunction::Profile::NativeProfile>::ConstIterator nat_calls = elem->self()->profile.last_native_calls.begin();
2473
while (nat_calls) {
2474
p_info_arr[current].call_count = nat_calls->value.call_count;
2475
p_info_arr[current].total_time = nat_calls->value.total_time;
2476
p_info_arr[current].self_time = nat_calls->value.total_time;
2477
p_info_arr[current].internal_time = nat_calls->value.total_time;
2478
p_info_arr[current].signature = nat_calls->value.signature;
2479
nat_time += nat_calls->value.total_time;
2480
current++;
2481
++nat_calls;
2482
}
2483
p_info_arr[last_non_internal].internal_time = nat_time;
2484
}
2485
elem = elem->next();
2486
}
2487
#endif
2488
2489
return current;
2490
}
2491
2492
void GDScriptLanguage::profiling_collate_native_call_data(bool p_accumulated) {
2493
#ifdef DEBUG_ENABLED
2494
// The same native call can be called from multiple functions, so join them together here.
2495
// Only use the name of the function (ie signature.split[2]).
2496
HashMap<String, GDScriptFunction::Profile::NativeProfile *> seen_nat_calls;
2497
SelfList<GDScriptFunction> *elem = function_list.first();
2498
while (elem) {
2499
HashMap<String, GDScriptFunction::Profile::NativeProfile> *nat_calls = p_accumulated ? &elem->self()->profile.native_calls : &elem->self()->profile.last_native_calls;
2500
HashMap<String, GDScriptFunction::Profile::NativeProfile>::Iterator it = nat_calls->begin();
2501
2502
while (it != nat_calls->end()) {
2503
Vector<String> sig = it->value.signature.split("::");
2504
HashMap<String, GDScriptFunction::Profile::NativeProfile *>::ConstIterator already_found = seen_nat_calls.find(sig[2]);
2505
if (already_found) {
2506
already_found->value->total_time += it->value.total_time;
2507
already_found->value->call_count += it->value.call_count;
2508
elem->self()->profile.last_native_calls.remove(it);
2509
} else {
2510
seen_nat_calls.insert(sig[2], &it->value);
2511
}
2512
++it;
2513
}
2514
elem = elem->next();
2515
}
2516
#endif
2517
}
2518
2519
struct GDScriptDepSort {
2520
//must support sorting so inheritance works properly (parent must be reloaded first)
2521
bool operator()(const Ref<GDScript> &A, const Ref<GDScript> &B) const {
2522
if (A == B) {
2523
return false; //shouldn't happen but..
2524
}
2525
const GDScript *I = B->get_base().ptr();
2526
while (I) {
2527
if (I == A.ptr()) {
2528
// A is a base of B
2529
return true;
2530
}
2531
2532
I = I->get_base().ptr();
2533
}
2534
2535
return false; //not a base
2536
}
2537
};
2538
2539
void GDScriptLanguage::reload_all_scripts() {
2540
#ifdef DEBUG_ENABLED
2541
print_verbose("GDScript: Reloading all scripts");
2542
Array scripts;
2543
{
2544
MutexLock lock(mutex);
2545
2546
SelfList<GDScript> *elem = script_list.first();
2547
while (elem) {
2548
if (elem->self()->get_path().is_resource_file()) {
2549
print_verbose("GDScript: Found: " + elem->self()->get_path());
2550
scripts.push_back(Ref<GDScript>(elem->self())); //cast to gdscript to avoid being erased by accident
2551
}
2552
elem = elem->next();
2553
}
2554
2555
#ifdef TOOLS_ENABLED
2556
if (Engine::get_singleton()->is_editor_hint()) {
2557
// Reload all pointers to existing singletons so that tool scripts can work with the reloaded extensions.
2558
List<Engine::Singleton> singletons;
2559
Engine::get_singleton()->get_singletons(&singletons);
2560
for (const Engine::Singleton &E : singletons) {
2561
if (globals.has(E.name)) {
2562
_add_global(E.name, E.ptr);
2563
}
2564
}
2565
}
2566
#endif // TOOLS_ENABLED
2567
}
2568
2569
reload_scripts(scripts, true);
2570
#endif // DEBUG_ENABLED
2571
}
2572
2573
void GDScriptLanguage::reload_scripts(const Array &p_scripts, bool p_soft_reload) {
2574
#ifdef DEBUG_ENABLED
2575
2576
List<Ref<GDScript>> scripts;
2577
{
2578
MutexLock lock(mutex);
2579
2580
SelfList<GDScript> *elem = script_list.first();
2581
while (elem) {
2582
// Scripts will reload all subclasses, so only reload root scripts.
2583
if (elem->self()->is_root_script() && !elem->self()->get_path().is_empty()) {
2584
scripts.push_back(Ref<GDScript>(elem->self())); //cast to gdscript to avoid being erased by accident
2585
}
2586
elem = elem->next();
2587
}
2588
}
2589
2590
//when someone asks you why dynamically typed languages are easier to write....
2591
2592
HashMap<Ref<GDScript>, HashMap<ObjectID, List<Pair<StringName, Variant>>>> to_reload;
2593
2594
//as scripts are going to be reloaded, must proceed without locking here
2595
2596
scripts.sort_custom<GDScriptDepSort>(); //update in inheritance dependency order
2597
2598
for (Ref<GDScript> &scr : scripts) {
2599
bool reload = p_scripts.has(scr) || to_reload.has(scr->get_base());
2600
2601
if (!reload) {
2602
continue;
2603
}
2604
2605
to_reload.insert(scr, HashMap<ObjectID, List<Pair<StringName, Variant>>>());
2606
2607
if (!p_soft_reload) {
2608
//save state and remove script from instances
2609
HashMap<ObjectID, List<Pair<StringName, Variant>>> &map = to_reload[scr];
2610
2611
while (scr->instances.front()) {
2612
Object *obj = scr->instances.front()->get();
2613
//save instance info
2614
List<Pair<StringName, Variant>> state;
2615
if (obj->get_script_instance()) {
2616
obj->get_script_instance()->get_property_state(state);
2617
map[obj->get_instance_id()] = state;
2618
obj->set_script(Variant());
2619
}
2620
}
2621
2622
//same thing for placeholders
2623
#ifdef TOOLS_ENABLED
2624
2625
while (scr->placeholders.size()) {
2626
Object *obj = (*scr->placeholders.begin())->get_owner();
2627
2628
//save instance info
2629
if (obj->get_script_instance()) {
2630
map.insert(obj->get_instance_id(), List<Pair<StringName, Variant>>());
2631
List<Pair<StringName, Variant>> &state = map[obj->get_instance_id()];
2632
obj->get_script_instance()->get_property_state(state);
2633
obj->set_script(Variant());
2634
} else {
2635
// no instance found. Let's remove it so we don't loop forever
2636
scr->placeholders.erase(*scr->placeholders.begin());
2637
}
2638
}
2639
2640
#endif // TOOLS_ENABLED
2641
2642
for (const KeyValue<ObjectID, List<Pair<StringName, Variant>>> &F : scr->pending_reload_state) {
2643
map[F.key] = F.value; //pending to reload, use this one instead
2644
}
2645
}
2646
}
2647
2648
for (KeyValue<Ref<GDScript>, HashMap<ObjectID, List<Pair<StringName, Variant>>>> &E : to_reload) {
2649
Ref<GDScript> scr = E.key;
2650
print_verbose("GDScript: Reloading: " + scr->get_path());
2651
if (scr->is_built_in()) {
2652
// TODO: It would be nice to do it more efficiently than loading the whole scene again.
2653
Ref<PackedScene> scene = ResourceLoader::load(scr->get_path().get_slice("::", 0), "", ResourceFormatLoader::CACHE_MODE_IGNORE_DEEP);
2654
ERR_CONTINUE(scene.is_null());
2655
2656
Ref<SceneState> state = scene->get_state();
2657
Ref<GDScript> fresh = state->get_sub_resource(scr->get_path());
2658
ERR_CONTINUE(fresh.is_null());
2659
2660
scr->set_source_code(fresh->get_source_code());
2661
} else {
2662
scr->load_source_code(scr->get_path());
2663
}
2664
scr->reload(p_soft_reload);
2665
2666
//restore state if saved
2667
for (KeyValue<ObjectID, List<Pair<StringName, Variant>>> &F : E.value) {
2668
List<Pair<StringName, Variant>> &saved_state = F.value;
2669
2670
Object *obj = ObjectDB::get_instance(F.key);
2671
if (!obj) {
2672
continue;
2673
}
2674
2675
if (!p_soft_reload) {
2676
//clear it just in case (may be a pending reload state)
2677
obj->set_script(Variant());
2678
}
2679
obj->set_script(scr);
2680
2681
ScriptInstance *script_inst = obj->get_script_instance();
2682
2683
if (!script_inst) {
2684
//failed, save reload state for next time if not saved
2685
if (!scr->pending_reload_state.has(obj->get_instance_id())) {
2686
scr->pending_reload_state[obj->get_instance_id()] = saved_state;
2687
}
2688
continue;
2689
}
2690
2691
if (script_inst->is_placeholder() && scr->is_placeholder_fallback_enabled()) {
2692
PlaceHolderScriptInstance *placeholder = static_cast<PlaceHolderScriptInstance *>(script_inst);
2693
for (List<Pair<StringName, Variant>>::Element *G = saved_state.front(); G; G = G->next()) {
2694
placeholder->property_set_fallback(G->get().first, G->get().second);
2695
}
2696
} else {
2697
for (List<Pair<StringName, Variant>>::Element *G = saved_state.front(); G; G = G->next()) {
2698
script_inst->set(G->get().first, G->get().second);
2699
}
2700
}
2701
2702
scr->pending_reload_state.erase(obj->get_instance_id()); //as it reloaded, remove pending state
2703
}
2704
2705
//if instance states were saved, set them!
2706
}
2707
2708
#endif // DEBUG_ENABLED
2709
}
2710
2711
void GDScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_soft_reload) {
2712
Array scripts = { p_script };
2713
reload_scripts(scripts, p_soft_reload);
2714
}
2715
2716
void GDScriptLanguage::frame() {
2717
#ifdef DEBUG_ENABLED
2718
if (profiling) {
2719
MutexLock lock(mutex);
2720
2721
SelfList<GDScriptFunction> *elem = function_list.first();
2722
while (elem) {
2723
elem->self()->profile.last_frame_call_count = elem->self()->profile.frame_call_count.get();
2724
elem->self()->profile.last_frame_self_time = elem->self()->profile.frame_self_time.get();
2725
elem->self()->profile.last_frame_total_time = elem->self()->profile.frame_total_time.get();
2726
elem->self()->profile.last_native_calls = elem->self()->profile.native_calls;
2727
elem->self()->profile.frame_call_count.set(0);
2728
elem->self()->profile.frame_self_time.set(0);
2729
elem->self()->profile.frame_total_time.set(0);
2730
elem->self()->profile.native_calls.clear();
2731
elem = elem->next();
2732
}
2733
}
2734
2735
#endif
2736
}
2737
2738
/* EDITOR FUNCTIONS */
2739
Vector<String> GDScriptLanguage::get_reserved_words() const {
2740
// Please keep alphabetical order within categories.
2741
static const Vector<String> ret = {
2742
// Control flow.
2743
"break",
2744
"continue",
2745
"elif",
2746
"else",
2747
"for",
2748
"if",
2749
"match",
2750
"pass",
2751
"return",
2752
"when",
2753
"while",
2754
// Declarations.
2755
"class",
2756
"class_name",
2757
"const",
2758
"enum",
2759
"extends",
2760
"func",
2761
"namespace", // Reserved for potential future use.
2762
"signal",
2763
"static",
2764
"trait", // Reserved for potential future use.
2765
"var",
2766
// Other keywords.
2767
"await",
2768
"breakpoint",
2769
"self",
2770
"super",
2771
"yield", // Reserved for potential future use.
2772
// Operators.
2773
"and",
2774
"as",
2775
"in",
2776
"is",
2777
"not",
2778
"or",
2779
// Special values (tokenizer treats them as literals, not as tokens).
2780
"false",
2781
"null",
2782
"true",
2783
// Constants.
2784
"INF",
2785
"NAN",
2786
"PI",
2787
"TAU",
2788
// Functions (highlighter uses global function color instead).
2789
"assert",
2790
"preload",
2791
// Types (highlighter uses type color instead).
2792
"void",
2793
};
2794
2795
return ret;
2796
}
2797
2798
bool GDScriptLanguage::is_control_flow_keyword(const String &p_keyword) const {
2799
// Please keep alphabetical order.
2800
return p_keyword == "break" ||
2801
p_keyword == "continue" ||
2802
p_keyword == "elif" ||
2803
p_keyword == "else" ||
2804
p_keyword == "for" ||
2805
p_keyword == "if" ||
2806
p_keyword == "match" ||
2807
p_keyword == "pass" ||
2808
p_keyword == "return" ||
2809
p_keyword == "when" ||
2810
p_keyword == "while";
2811
}
2812
2813
bool GDScriptLanguage::handles_global_class_type(const String &p_type) const {
2814
return p_type == "GDScript";
2815
}
2816
2817
String GDScriptLanguage::get_global_class_name(const String &p_path, String *r_base_type, String *r_icon_path, bool *r_is_abstract, bool *r_is_tool) const {
2818
Error err;
2819
Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ, &err);
2820
if (err) {
2821
return String();
2822
}
2823
2824
String source = f->get_as_utf8_string();
2825
2826
GDScriptParser parser;
2827
err = parser.parse(source, p_path, false, false);
2828
2829
const GDScriptParser::ClassNode *c = parser.get_tree();
2830
if (!c) {
2831
return String(); // No class parsed.
2832
}
2833
2834
/* **WARNING**
2835
*
2836
* This function is written with the goal to be *extremely* error tolerant, as such
2837
* it should meet the following requirements:
2838
*
2839
* - It must not rely on the analyzer (in fact, the analyzer must not be used here),
2840
* because at the time global classes are parsed, the dependencies may not be present
2841
* yet, hence the function will fail (which is unintended).
2842
* - It must not fail even if the parsing fails, because even if the file is broken,
2843
* it should attempt its best to retrieve the inheritance metadata.
2844
*
2845
* Before changing this function, please ask the current maintainer of EditorFileSystem.
2846
*/
2847
2848
if (r_base_type) {
2849
const GDScriptParser::ClassNode *subclass = c;
2850
String path = p_path;
2851
GDScriptParser subparser;
2852
while (subclass) {
2853
if (subclass->extends_used) {
2854
if (!subclass->extends_path.is_empty()) {
2855
if (subclass->extends.is_empty()) {
2856
// We only care about the referenced class_name.
2857
_ALLOW_DISCARD_ get_global_class_name(subclass->extends_path, r_base_type);
2858
subclass = nullptr;
2859
break;
2860
} else {
2861
Vector<GDScriptParser::IdentifierNode *> extend_classes = subclass->extends;
2862
2863
Ref<FileAccess> subfile = FileAccess::open(subclass->extends_path, FileAccess::READ);
2864
if (subfile.is_null()) {
2865
break;
2866
}
2867
String subsource = subfile->get_as_utf8_string();
2868
2869
if (subsource.is_empty()) {
2870
break;
2871
}
2872
String subpath = subclass->extends_path;
2873
if (subpath.is_relative_path()) {
2874
subpath = path.get_base_dir().path_join(subpath).simplify_path();
2875
}
2876
2877
if (OK != subparser.parse(subsource, subpath, false)) {
2878
break;
2879
}
2880
path = subpath;
2881
subclass = subparser.get_tree();
2882
2883
while (extend_classes.size() > 0) {
2884
bool found = false;
2885
for (int i = 0; i < subclass->members.size(); i++) {
2886
if (subclass->members[i].type != GDScriptParser::ClassNode::Member::CLASS) {
2887
continue;
2888
}
2889
2890
const GDScriptParser::ClassNode *inner_class = subclass->members[i].m_class;
2891
if (inner_class->identifier->name == extend_classes[0]->name) {
2892
extend_classes.remove_at(0);
2893
found = true;
2894
subclass = inner_class;
2895
break;
2896
}
2897
}
2898
if (!found) {
2899
subclass = nullptr;
2900
break;
2901
}
2902
}
2903
}
2904
} else if (subclass->extends.size() == 1) {
2905
*r_base_type = subclass->extends[0]->name;
2906
subclass = nullptr;
2907
} else {
2908
break;
2909
}
2910
} else {
2911
*r_base_type = "RefCounted";
2912
subclass = nullptr;
2913
}
2914
}
2915
}
2916
if (r_icon_path) {
2917
*r_icon_path = c->simplified_icon_path;
2918
}
2919
if (r_is_abstract) {
2920
*r_is_abstract = c->is_abstract;
2921
}
2922
if (r_is_tool) {
2923
*r_is_tool = parser.is_tool();
2924
}
2925
return c->identifier != nullptr ? String(c->identifier->name) : String();
2926
}
2927
2928
thread_local GDScriptLanguage::CallLevel *GDScriptLanguage::_call_stack = nullptr;
2929
thread_local uint32_t GDScriptLanguage::_call_stack_size = 0;
2930
2931
GDScriptLanguage::CallLevel *GDScriptLanguage::_get_stack_level(uint32_t p_level) {
2932
ERR_FAIL_UNSIGNED_INDEX_V(p_level, _call_stack_size, nullptr);
2933
CallLevel *level = _call_stack; // Start from top
2934
uint32_t level_index = 0;
2935
while (p_level > level_index) {
2936
level_index++;
2937
level = level->prev;
2938
}
2939
return level;
2940
}
2941
2942
GDScriptLanguage::GDScriptLanguage() {
2943
ERR_FAIL_COND(singleton);
2944
singleton = this;
2945
strings._init = StringName("_init");
2946
strings._static_init = StringName("_static_init");
2947
strings._notification = StringName("_notification");
2948
strings._set = StringName("_set");
2949
strings._get = StringName("_get");
2950
strings._get_property_list = StringName("_get_property_list");
2951
strings._validate_property = StringName("_validate_property");
2952
strings._property_can_revert = StringName("_property_can_revert");
2953
strings._property_get_revert = StringName("_property_get_revert");
2954
strings._script_source = StringName("script/source");
2955
_debug_parse_err_line = -1;
2956
_debug_parse_err_file = "";
2957
2958
#ifdef DEBUG_ENABLED
2959
profiling = false;
2960
profile_native_calls = false;
2961
script_frame_time = 0;
2962
#endif
2963
2964
_debug_max_call_stack = GLOBAL_DEF_RST(PropertyInfo(Variant::INT, "debug/settings/gdscript/max_call_stack", PROPERTY_HINT_RANGE, "512," + itos(GDScriptFunction::MAX_CALL_DEPTH - 1) + ",1"), 1024);
2965
track_call_stack = GLOBAL_DEF_RST("debug/settings/gdscript/always_track_call_stacks", false);
2966
track_locals = GLOBAL_DEF_RST("debug/settings/gdscript/always_track_local_variables", false);
2967
2968
#ifdef DEBUG_ENABLED
2969
track_call_stack = true;
2970
track_locals = track_locals || EngineDebugger::is_active();
2971
2972
GLOBAL_DEF("debug/gdscript/warnings/enable", true);
2973
GLOBAL_DEF("debug/gdscript/warnings/exclude_addons", true);
2974
GLOBAL_DEF("debug/gdscript/warnings/renamed_in_godot_4_hint", true);
2975
for (int i = 0; i < (int)GDScriptWarning::WARNING_MAX; i++) {
2976
GDScriptWarning::Code code = (GDScriptWarning::Code)i;
2977
Variant default_enabled = GDScriptWarning::get_default_value(code);
2978
String path = GDScriptWarning::get_settings_path_from_code(code);
2979
GLOBAL_DEF(GDScriptWarning::get_property_info(code), default_enabled);
2980
}
2981
2982
#ifndef DISABLE_DEPRECATED
2983
ProjectSettings::get_singleton()->set_as_internal("debug/gdscript/warnings/property_used_as_function", true);
2984
ProjectSettings::get_singleton()->set_as_internal("debug/gdscript/warnings/constant_used_as_function", true);
2985
ProjectSettings::get_singleton()->set_as_internal("debug/gdscript/warnings/function_used_as_property", true);
2986
#endif
2987
#endif // DEBUG_ENABLED
2988
}
2989
2990
GDScriptLanguage::~GDScriptLanguage() {
2991
singleton = nullptr;
2992
}
2993
2994
void GDScriptLanguage::add_orphan_subclass(const String &p_qualified_name, const ObjectID &p_subclass) {
2995
orphan_subclasses[p_qualified_name] = p_subclass;
2996
}
2997
2998
Ref<GDScript> GDScriptLanguage::get_orphan_subclass(const String &p_qualified_name) {
2999
HashMap<String, ObjectID>::Iterator orphan_subclass_element = orphan_subclasses.find(p_qualified_name);
3000
if (!orphan_subclass_element) {
3001
return Ref<GDScript>();
3002
}
3003
ObjectID orphan_subclass = orphan_subclass_element->value;
3004
Object *obj = ObjectDB::get_instance(orphan_subclass);
3005
orphan_subclasses.remove(orphan_subclass_element);
3006
if (!obj) {
3007
return Ref<GDScript>();
3008
}
3009
return Ref<GDScript>(Object::cast_to<GDScript>(obj));
3010
}
3011
3012
Ref<GDScript> GDScriptLanguage::get_script_by_fully_qualified_name(const String &p_name) {
3013
{
3014
MutexLock lock(mutex);
3015
3016
SelfList<GDScript> *elem = script_list.first();
3017
while (elem) {
3018
GDScript *scr = elem->self();
3019
if (scr->fully_qualified_name == p_name) {
3020
return scr;
3021
}
3022
elem = elem->next();
3023
}
3024
}
3025
3026
Ref<GDScript> scr;
3027
scr.instantiate();
3028
scr->fully_qualified_name = p_name;
3029
return scr;
3030
}
3031
3032
/*************** RESOURCE ***************/
3033
3034
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) {
3035
Error err;
3036
bool ignoring = p_cache_mode == CACHE_MODE_IGNORE || p_cache_mode == CACHE_MODE_IGNORE_DEEP;
3037
Ref<GDScript> scr = GDScriptCache::get_full_script(p_original_path, err, "", ignoring);
3038
3039
if (err && scr.is_valid()) {
3040
// If !scr.is_valid(), the error was likely from scr->load_source_code(), which already generates an error.
3041
ERR_PRINT_ED(vformat(R"(Failed to load script "%s" with error "%s".)", p_original_path, error_names[err]));
3042
}
3043
3044
if (r_error) {
3045
// Don't fail loading because of parsing error.
3046
*r_error = scr.is_valid() ? OK : err;
3047
}
3048
3049
return scr;
3050
}
3051
3052
void ResourceFormatLoaderGDScript::get_recognized_extensions(List<String> *p_extensions) const {
3053
p_extensions->push_back("gd");
3054
p_extensions->push_back("gdc");
3055
}
3056
3057
bool ResourceFormatLoaderGDScript::handles_type(const String &p_type) const {
3058
return (p_type == "Script" || p_type == "GDScript");
3059
}
3060
3061
String ResourceFormatLoaderGDScript::get_resource_type(const String &p_path) const {
3062
String el = p_path.get_extension().to_lower();
3063
if (el == "gd" || el == "gdc") {
3064
return "GDScript";
3065
}
3066
return "";
3067
}
3068
3069
void ResourceFormatLoaderGDScript::get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types) {
3070
Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::READ);
3071
ERR_FAIL_COND_MSG(file.is_null(), "Cannot open file '" + p_path + "'.");
3072
3073
String source = file->get_as_utf8_string();
3074
if (source.is_empty()) {
3075
return;
3076
}
3077
3078
GDScriptParser parser;
3079
if (OK != parser.parse(source, p_path, false)) {
3080
return;
3081
}
3082
3083
for (const String &E : parser.get_dependencies()) {
3084
p_dependencies->push_back(E);
3085
}
3086
}
3087
3088
void ResourceFormatLoaderGDScript::get_classes_used(const String &p_path, HashSet<StringName> *r_classes) {
3089
Ref<GDScript> scr = ResourceLoader::load(p_path);
3090
if (scr.is_null()) {
3091
return;
3092
}
3093
3094
const String source = scr->get_source_code();
3095
GDScriptTokenizerText tokenizer;
3096
tokenizer.set_source_code(source);
3097
GDScriptTokenizer::Token current = tokenizer.scan();
3098
while (current.type != GDScriptTokenizer::Token::TK_EOF) {
3099
if (!current.is_identifier()) {
3100
current = tokenizer.scan();
3101
continue;
3102
}
3103
3104
int insert_idx = 0;
3105
for (int i = 0; i < current.start_line - 1; i++) {
3106
insert_idx = source.find("\n", insert_idx) + 1;
3107
}
3108
// Insert the "cursor" character, needed for the lookup to work.
3109
const String source_with_cursor = source.insert(insert_idx + current.start_column, String::chr(0xFFFF));
3110
3111
ScriptLanguage::LookupResult result;
3112
if (scr->get_language()->lookup_code(source_with_cursor, current.get_identifier(), p_path, nullptr, result) == OK) {
3113
if (!result.class_name.is_empty() && ClassDB::class_exists(result.class_name)) {
3114
r_classes->insert(result.class_name);
3115
}
3116
3117
if (result.type == ScriptLanguage::LOOKUP_RESULT_CLASS_PROPERTY) {
3118
PropertyInfo prop;
3119
if (ClassDB::get_property_info(result.class_name, result.class_member, &prop)) {
3120
if (!prop.class_name.is_empty() && ClassDB::class_exists(prop.class_name)) {
3121
r_classes->insert(prop.class_name);
3122
}
3123
if (!prop.hint_string.is_empty() && ClassDB::class_exists(prop.hint_string)) {
3124
r_classes->insert(prop.hint_string);
3125
}
3126
}
3127
} else if (result.type == ScriptLanguage::LOOKUP_RESULT_CLASS_METHOD) {
3128
MethodInfo met;
3129
if (ClassDB::get_method_info(result.class_name, result.class_member, &met)) {
3130
if (!met.return_val.class_name.is_empty() && ClassDB::class_exists(met.return_val.class_name)) {
3131
r_classes->insert(met.return_val.class_name);
3132
}
3133
if (!met.return_val.hint_string.is_empty() && ClassDB::class_exists(met.return_val.hint_string)) {
3134
r_classes->insert(met.return_val.hint_string);
3135
}
3136
}
3137
}
3138
}
3139
3140
current = tokenizer.scan();
3141
}
3142
}
3143
3144
Error ResourceFormatSaverGDScript::save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags) {
3145
Ref<GDScript> sqscr = p_resource;
3146
ERR_FAIL_COND_V(sqscr.is_null(), ERR_INVALID_PARAMETER);
3147
3148
String source = sqscr->get_source_code();
3149
3150
{
3151
Error err;
3152
Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::WRITE, &err);
3153
3154
ERR_FAIL_COND_V_MSG(err, err, "Cannot save GDScript file '" + p_path + "'.");
3155
3156
file->store_string(source);
3157
if (file->get_error() != OK && file->get_error() != ERR_FILE_EOF) {
3158
return ERR_CANT_CREATE;
3159
}
3160
}
3161
3162
if (ScriptServer::is_reload_scripts_on_save_enabled()) {
3163
GDScriptLanguage::get_singleton()->reload_tool_script(p_resource, true);
3164
}
3165
3166
return OK;
3167
}
3168
3169
void ResourceFormatSaverGDScript::get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const {
3170
if (Object::cast_to<GDScript>(*p_resource)) {
3171
p_extensions->push_back("gd");
3172
}
3173
}
3174
3175
bool ResourceFormatSaverGDScript::recognize(const Ref<Resource> &p_resource) const {
3176
return Object::cast_to<GDScript>(*p_resource) != nullptr;
3177
}
3178
3179