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