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