1 /*************************************************************************/
2 /* gd_script.cpp */
3 /*************************************************************************/
4 /* This file is part of: */
5 /* GODOT ENGINE */
6 /* https://godotengine.org */
7 /*************************************************************************/
8 /* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
9 /* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
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 #include "gd_script.h"
31 #include "gd_compiler.h"
32 #include "global_constants.h"
33 #include "globals.h"
34 #include "io/file_access_encrypted.h"
35 #include "os/file_access.h"
36 #include "os/os.h"
37
38 ///////////////////////////
39
GDNativeClass(const StringName & p_name)40 GDNativeClass::GDNativeClass(const StringName &p_name) {
41
42 name = p_name;
43 }
44
45 /*void GDNativeClass::call_multilevel(const StringName& p_method,const Variant** p_args,int p_argcount){
46
47
48 }*/
49
_get(const StringName & p_name,Variant & r_ret) const50 bool GDNativeClass::_get(const StringName &p_name, Variant &r_ret) const {
51
52 bool ok;
53 int v = ObjectTypeDB::get_integer_constant(name, p_name, &ok);
54
55 if (ok) {
56 r_ret = v;
57 return true;
58 } else {
59 return false;
60 }
61 }
62
_bind_methods()63 void GDNativeClass::_bind_methods() {
64
65 ObjectTypeDB::bind_method(_MD("new"), &GDNativeClass::_new);
66 }
67
_new()68 Variant GDNativeClass::_new() {
69
70 Object *o = instance();
71 if (!o) {
72 ERR_EXPLAIN("Class type: '" + String(name) + "' is not instantiable.");
73 ERR_FAIL_COND_V(!o, Variant());
74 }
75
76 Reference *ref = o->cast_to<Reference>();
77 if (ref) {
78 return REF(ref);
79 } else {
80 return o;
81 }
82 }
83
instance()84 Object *GDNativeClass::instance() {
85
86 return ObjectTypeDB::instance(name);
87 }
88
_create_instance(const Variant ** p_args,int p_argcount,Object * p_owner,bool p_isref,Variant::CallError & r_error)89 GDInstance *GDScript::_create_instance(const Variant **p_args, int p_argcount, Object *p_owner, bool p_isref, Variant::CallError &r_error) {
90
91 /* STEP 1, CREATE */
92
93 GDInstance *instance = memnew(GDInstance);
94 instance->base_ref = p_isref;
95 instance->members.resize(member_indices.size());
96 instance->script = Ref<GDScript>(this);
97 instance->owner = p_owner;
98 #ifdef DEBUG_ENABLED
99 //needed for hot reloading
100 for (Map<StringName, MemberInfo>::Element *E = member_indices.front(); E; E = E->next()) {
101 instance->member_indices_cache[E->key()] = E->get().index;
102 }
103 #endif
104 instance->owner->set_script_instance(instance);
105
106 /* STEP 2, INITIALIZE AND CONSRTUCT */
107
108 instances.insert(instance->owner);
109
110 initializer->call(instance, p_args, p_argcount, r_error);
111
112 if (r_error.error != Variant::CallError::CALL_OK) {
113 instance->script = Ref<GDScript>();
114 instance->owner->set_script_instance(NULL);
115 instances.erase(p_owner);
116 ERR_FAIL_COND_V(r_error.error != Variant::CallError::CALL_OK, NULL); //error constructing
117 }
118
119 //@TODO make thread safe
120 return instance;
121 }
122
_new(const Variant ** p_args,int p_argcount,Variant::CallError & r_error)123 Variant GDScript::_new(const Variant **p_args, int p_argcount, Variant::CallError &r_error) {
124
125 /* STEP 1, CREATE */
126
127 if (!valid) {
128 r_error.error = Variant::CallError::CALL_ERROR_INVALID_METHOD;
129 return Variant();
130 }
131
132 r_error.error = Variant::CallError::CALL_OK;
133 REF ref;
134 Object *owner = NULL;
135
136 GDScript *_baseptr = this;
137 while (_baseptr->_base) {
138 _baseptr = _baseptr->_base;
139 }
140
141 if (_baseptr->native.ptr()) {
142 owner = _baseptr->native->instance();
143 } else {
144 owner = memnew(Reference); //by default, no base means use reference
145 }
146
147 Reference *r = owner->cast_to<Reference>();
148 if (r) {
149 ref = REF(r);
150 }
151
152 GDInstance *instance = _create_instance(p_args, p_argcount, owner, r != NULL, r_error);
153 if (!instance) {
154 if (ref.is_null()) {
155 memdelete(owner); //no owner, sorry
156 }
157 return Variant();
158 }
159
160 if (ref.is_valid()) {
161 return ref;
162 } else {
163 return owner;
164 }
165 }
166
can_instance() const167 bool GDScript::can_instance() const {
168
169 //return valid; //any script in GDscript can instance
170 return valid || (!tool && !ScriptServer::is_scripting_enabled());
171 }
172
get_instance_base_type() const173 StringName GDScript::get_instance_base_type() const {
174
175 if (native.is_valid())
176 return native->get_name();
177 if (base.is_valid())
178 return base->get_instance_base_type();
179 return StringName();
180 }
181
182 struct _GDScriptMemberSort {
183
184 int index;
185 StringName name;
operator <_GDScriptMemberSort186 _FORCE_INLINE_ bool operator<(const _GDScriptMemberSort &p_member) const { return index < p_member.index; }
187 };
188
189 #ifdef TOOLS_ENABLED
190
_placeholder_erased(PlaceHolderScriptInstance * p_placeholder)191 void GDScript::_placeholder_erased(PlaceHolderScriptInstance *p_placeholder) {
192
193 placeholders.erase(p_placeholder);
194 }
195
196 /*
197 void GDScript::_update_placeholder(PlaceHolderScriptInstance *p_placeholder) {
198
199
200 List<PropertyInfo> plist;
201 GDScript *scr=this;
202
203 Map<StringName,Variant> default_values;
204 while(scr) {
205
206 Vector<_GDScriptMemberSort> msort;
207 for(Map<StringName,PropertyInfo>::Element *E=scr->member_info.front();E;E=E->next()) {
208
209 _GDScriptMemberSort ms;
210 ERR_CONTINUE(!scr->member_indices.has(E->key()));
211 ms.index=scr->member_indices[E->key()].index;
212 ms.name=E->key();
213
214 msort.push_back(ms);
215
216 }
217
218 msort.sort();
219 msort.invert();
220 for(int i=0;i<msort.size();i++) {
221
222 plist.push_front(scr->member_info[msort[i].name]);
223 if (scr->member_default_values.has(msort[i].name))
224 default_values[msort[i].name]=scr->member_default_values[msort[i].name];
225 else {
226 Variant::CallError err;
227 default_values[msort[i].name]=Variant::construct(scr->member_info[msort[i].name].type,NULL,0,err);
228 }
229 }
230
231 scr=scr->_base;
232 }
233
234
235 p_placeholder->update(plist,default_values);
236
237 }*/
238 #endif
239
get_property_default_value(const StringName & p_property,Variant & r_value) const240 bool GDScript::get_property_default_value(const StringName &p_property, Variant &r_value) const {
241
242 #ifdef TOOLS_ENABLED
243
244 //for (const Map<StringName,Variant>::Element *I=member_default_values.front();I;I=I->next()) {
245 // print_line("\t"+String(String(I->key())+":"+String(I->get())));
246 //}
247 const Map<StringName, Variant>::Element *E = member_default_values_cache.find(p_property);
248 if (E) {
249 r_value = E->get();
250 return true;
251 }
252
253 if (base_cache.is_valid()) {
254 return base_cache->get_property_default_value(p_property, r_value);
255 }
256 #endif
257 return false;
258 }
259
instance_create(Object * p_this)260 ScriptInstance *GDScript::instance_create(Object *p_this) {
261
262 if (!tool && !ScriptServer::is_scripting_enabled()) {
263
264 #ifdef TOOLS_ENABLED
265
266 //instance a fake script for editing the values
267 //plist.invert();
268
269 /*print_line("CREATING PLACEHOLDER");
270 for(List<PropertyInfo>::Element *E=plist.front();E;E=E->next()) {
271 print_line(E->get().name);
272 }*/
273 PlaceHolderScriptInstance *si = memnew(PlaceHolderScriptInstance(GDScriptLanguage::get_singleton(), Ref<Script>(this), p_this));
274 placeholders.insert(si);
275 //_update_placeholder(si);
276 _update_exports();
277 return si;
278 #else
279 return NULL;
280 #endif
281 }
282
283 GDScript *top = this;
284 while (top->_base)
285 top = top->_base;
286
287 if (top->native.is_valid()) {
288 if (!ObjectTypeDB::is_type(p_this->get_type_name(), top->native->get_name())) {
289
290 if (ScriptDebugger::get_singleton()) {
291 GDScriptLanguage::get_singleton()->debug_break_parse(get_path(), 0, "Script inherits from native type '" + String(top->native->get_name()) + "', so it can't be instanced in object of type: '" + p_this->get_type() + "'");
292 }
293 ERR_EXPLAIN("Script inherits from native type '" + String(top->native->get_name()) + "', so it can't be instanced in object of type: '" + p_this->get_type() + "'");
294 ERR_FAIL_V(NULL);
295 }
296 }
297
298 Variant::CallError unchecked_error;
299 return _create_instance(NULL, 0, p_this, p_this->cast_to<Reference>(), unchecked_error);
300 }
instance_has(const Object * p_this) const301 bool GDScript::instance_has(const Object *p_this) const {
302
303 return instances.has((Object *)p_this);
304 }
305
has_source_code() const306 bool GDScript::has_source_code() const {
307
308 return source != "";
309 }
get_source_code() const310 String GDScript::get_source_code() const {
311
312 return source;
313 }
set_source_code(const String & p_code)314 void GDScript::set_source_code(const String &p_code) {
315
316 if (source == p_code)
317 return;
318 source = p_code;
319 #ifdef TOOLS_ENABLED
320 source_changed_cache = true;
321 //print_line("SC CHANGED "+get_path());
322 #endif
323 }
324
325 #ifdef TOOLS_ENABLED
_update_exports_values(Map<StringName,Variant> & values,List<PropertyInfo> & propnames)326 void GDScript::_update_exports_values(Map<StringName, Variant> &values, List<PropertyInfo> &propnames) {
327
328 if (base_cache.is_valid()) {
329 base_cache->_update_exports_values(values, propnames);
330 }
331
332 for (Map<StringName, Variant>::Element *E = member_default_values_cache.front(); E; E = E->next()) {
333 values[E->key()] = E->get();
334 }
335
336 for (List<PropertyInfo>::Element *E = members_cache.front(); E; E = E->next()) {
337 propnames.push_back(E->get());
338 }
339 }
340 #endif
341
_update_exports()342 bool GDScript::_update_exports() {
343
344 #ifdef TOOLS_ENABLED
345
346 bool changed = false;
347
348 if (source_changed_cache) {
349 //print_line("updating source for "+get_path());
350 source_changed_cache = false;
351 changed = true;
352
353 String basedir = path;
354
355 if (basedir == "")
356 basedir = get_path();
357
358 if (basedir != "")
359 basedir = basedir.get_base_dir();
360
361 GDParser parser;
362 Error err = parser.parse(source, basedir, true, path);
363
364 if (err == OK) {
365
366 const GDParser::Node *root = parser.get_parse_tree();
367 ERR_FAIL_COND_V(root->type != GDParser::Node::TYPE_CLASS, false);
368
369 const GDParser::ClassNode *c = static_cast<const GDParser::ClassNode *>(root);
370
371 if (base_cache.is_valid()) {
372 base_cache->inheriters_cache.erase(get_instance_ID());
373 base_cache = Ref<GDScript>();
374 }
375
376 if (c->extends_used && String(c->extends_file) != "" && String(c->extends_file) != get_path()) {
377
378 String path = c->extends_file;
379 if (path.is_rel_path()) {
380
381 String base = get_path();
382 if (base == "" || base.is_rel_path()) {
383
384 ERR_PRINT(("Could not resolve relative path for parent class: " + path).utf8().get_data());
385 } else {
386 path = base.get_base_dir().plus_file(path);
387 }
388 }
389
390 if (path != get_path()) {
391
392 Ref<GDScript> bf = ResourceLoader::load(path);
393
394 if (bf.is_valid()) {
395
396 //print_line("parent is: "+bf->get_path());
397 base_cache = bf;
398 bf->inheriters_cache.insert(get_instance_ID());
399
400 //bf->_update_exports(p_instances,true,false);
401 }
402 } else {
403 ERR_PRINT(("Path extending itself in " + path).utf8().get_data());
404 }
405 }
406
407 members_cache.clear();
408 member_default_values_cache.clear();
409
410 for (int i = 0; i < c->variables.size(); i++) {
411 if (c->variables[i]._export.type == Variant::NIL)
412 continue;
413
414 members_cache.push_back(c->variables[i]._export);
415 //print_line("found "+c->variables[i]._export.name);
416 member_default_values_cache[c->variables[i].identifier] = c->variables[i].default_value;
417 }
418
419 _signals.clear();
420
421 for (int i = 0; i < c->_signals.size(); i++) {
422 _signals[c->_signals[i].name] = c->_signals[i].arguments;
423 }
424 }
425 } else {
426 //print_line("unchaged is "+get_path());
427 }
428
429 if (base_cache.is_valid()) {
430 if (base_cache->_update_exports()) {
431 changed = true;
432 }
433 }
434
435 if (/*changed &&*/ placeholders.size()) { //hm :(
436
437 //print_line("updating placeholders for "+get_path());
438
439 //update placeholders if any
440 Map<StringName, Variant> values;
441 List<PropertyInfo> propnames;
442 _update_exports_values(values, propnames);
443
444 for (Set<PlaceHolderScriptInstance *>::Element *E = placeholders.front(); E; E = E->next()) {
445
446 E->get()->update(propnames, values);
447 }
448 }
449
450 return changed;
451
452 #endif
453 return false;
454 }
455
update_exports()456 void GDScript::update_exports() {
457
458 #ifdef TOOLS_ENABLED
459
460 _update_exports();
461
462 Set<ObjectID> copy = inheriters_cache; //might get modified
463
464 //print_line("update exports for "+get_path()+" ic: "+itos(copy.size()));
465 for (Set<ObjectID>::Element *E = copy.front(); E; E = E->next()) {
466 Object *id = ObjectDB::get_instance(E->get());
467 if (!id)
468 continue;
469 GDScript *s = id->cast_to<GDScript>();
470 if (!s)
471 continue;
472 s->update_exports();
473 }
474
475 #endif
476 }
477
_set_subclass_path(Ref<GDScript> & p_sc,const String & p_path)478 void GDScript::_set_subclass_path(Ref<GDScript> &p_sc, const String &p_path) {
479
480 p_sc->path = p_path;
481 for (Map<StringName, Ref<GDScript> >::Element *E = p_sc->subclasses.front(); E; E = E->next()) {
482
483 _set_subclass_path(E->get(), p_path);
484 }
485 }
486
reload(bool p_keep_state)487 Error GDScript::reload(bool p_keep_state) {
488
489 ERR_FAIL_COND_V(!p_keep_state && instances.size(), ERR_ALREADY_IN_USE);
490
491 String basedir = path;
492
493 if (basedir == "")
494 basedir = get_path();
495
496 if (basedir != "")
497 basedir = basedir.get_base_dir();
498
499 valid = false;
500 GDParser parser;
501 Error err = parser.parse(source, basedir, false, path);
502 if (err) {
503 if (ScriptDebugger::get_singleton()) {
504 GDScriptLanguage::get_singleton()->debug_break_parse(get_path(), parser.get_error_line(), "Parser Error: " + parser.get_error());
505 }
506 _err_print_error("GDScript::reload", path.empty() ? "built-in" : (const char *)path.utf8().get_data(), parser.get_error_line(), ("Parse Error: " + parser.get_error()).utf8().get_data(), ERR_HANDLER_SCRIPT);
507 ERR_FAIL_V(ERR_PARSE_ERROR);
508 }
509
510 bool can_run = ScriptServer::is_scripting_enabled() || parser.is_tool_script();
511
512 GDCompiler compiler;
513 err = compiler.compile(&parser, this, p_keep_state);
514
515 if (err) {
516
517 if (can_run) {
518 if (ScriptDebugger::get_singleton()) {
519 GDScriptLanguage::get_singleton()->debug_break_parse(get_path(), compiler.get_error_line(), "Parser Error: " + compiler.get_error());
520 }
521 _err_print_error("GDScript::reload", path.empty() ? "built-in" : (const char *)path.utf8().get_data(), compiler.get_error_line(), ("Compile Error: " + compiler.get_error()).utf8().get_data(), ERR_HANDLER_SCRIPT);
522 ERR_FAIL_V(ERR_COMPILATION_FAILED);
523 } else {
524 return err;
525 }
526 }
527
528 valid = true;
529
530 for (Map<StringName, Ref<GDScript> >::Element *E = subclasses.front(); E; E = E->next()) {
531
532 _set_subclass_path(E->get(), path);
533 }
534
535 #ifdef TOOLS_ENABLED
536 /*for (Set<PlaceHolderScriptInstance*>::Element *E=placeholders.front();E;E=E->next()) {
537
538 _update_placeholder(E->get());
539 }*/
540 #endif
541 return OK;
542 }
543
get_node_type() const544 String GDScript::get_node_type() const {
545
546 return ""; // ?
547 }
548
get_language() const549 ScriptLanguage *GDScript::get_language() const {
550
551 return GDScriptLanguage::get_singleton();
552 }
553
call(const StringName & p_method,const Variant ** p_args,int p_argcount,Variant::CallError & r_error)554 Variant GDScript::call(const StringName &p_method, const Variant **p_args, int p_argcount, Variant::CallError &r_error) {
555
556 GDScript *top = this;
557 while (top) {
558
559 Map<StringName, GDFunction *>::Element *E = top->member_functions.find(p_method);
560 if (E) {
561
562 if (!E->get()->is_static()) {
563 WARN_PRINT(String("Can't call non-static function: '" + String(p_method) + "' in script.").utf8().get_data());
564 }
565
566 return E->get()->call(NULL, p_args, p_argcount, r_error);
567 }
568 top = top->_base;
569 }
570
571 //none found, regular
572
573 return Script::call(p_method, p_args, p_argcount, r_error);
574 }
575
_get(const StringName & p_name,Variant & r_ret) const576 bool GDScript::_get(const StringName &p_name, Variant &r_ret) const {
577
578 {
579
580 const GDScript *top = this;
581 while (top) {
582
583 {
584 const Map<StringName, Variant>::Element *E = top->constants.find(p_name);
585 if (E) {
586
587 r_ret = E->get();
588 return true;
589 }
590 }
591
592 {
593 const Map<StringName, Ref<GDScript> >::Element *E = subclasses.find(p_name);
594 if (E) {
595
596 r_ret = E->get();
597 return true;
598 }
599 }
600 top = top->_base;
601 }
602
603 if (p_name == GDScriptLanguage::get_singleton()->strings._script_source) {
604
605 r_ret = get_source_code();
606 return true;
607 }
608 }
609
610 return false;
611 }
_set(const StringName & p_name,const Variant & p_value)612 bool GDScript::_set(const StringName &p_name, const Variant &p_value) {
613
614 if (p_name == GDScriptLanguage::get_singleton()->strings._script_source) {
615
616 set_source_code(p_value);
617 reload();
618 } else
619 return false;
620
621 return true;
622 }
623
_get_property_list(List<PropertyInfo> * p_properties) const624 void GDScript::_get_property_list(List<PropertyInfo> *p_properties) const {
625
626 p_properties->push_back(PropertyInfo(Variant::STRING, "script/source", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
627 }
628
_bind_methods()629 void GDScript::_bind_methods() {
630
631 ObjectTypeDB::bind_native_method(METHOD_FLAGS_DEFAULT, "new", &GDScript::_new, MethodInfo("new"));
632
633 ObjectTypeDB::bind_method(_MD("get_as_byte_code"), &GDScript::get_as_byte_code);
634 }
635
get_as_byte_code() const636 Vector<uint8_t> GDScript::get_as_byte_code() const {
637
638 GDTokenizerBuffer tokenizer;
639 return tokenizer.parse_code_string(source);
640 };
641
load_byte_code(const String & p_path)642 Error GDScript::load_byte_code(const String &p_path) {
643
644 Vector<uint8_t> bytecode;
645
646 if (p_path.ends_with("gde")) {
647
648 FileAccess *fa = FileAccess::open(p_path, FileAccess::READ);
649 ERR_FAIL_COND_V(!fa, ERR_CANT_OPEN);
650 FileAccessEncrypted *fae = memnew(FileAccessEncrypted);
651 ERR_FAIL_COND_V(!fae, ERR_CANT_OPEN);
652 Vector<uint8_t> key;
653 key.resize(32);
654 for (int i = 0; i < key.size(); i++) {
655 key[i] = script_encryption_key[i];
656 }
657 Error err = fae->open_and_parse(fa, key, FileAccessEncrypted::MODE_READ);
658 ERR_FAIL_COND_V(err, err);
659 bytecode.resize(fae->get_len());
660 fae->get_buffer(bytecode.ptr(), bytecode.size());
661 memdelete(fae);
662 } else {
663
664 bytecode = FileAccess::get_file_as_array(p_path);
665 }
666 ERR_FAIL_COND_V(bytecode.size() == 0, ERR_PARSE_ERROR);
667 path = p_path;
668
669 String basedir = path;
670
671 if (basedir == "")
672 basedir = get_path();
673
674 if (basedir != "")
675 basedir = basedir.get_base_dir();
676
677 valid = false;
678 GDParser parser;
679 Error err = parser.parse_bytecode(bytecode, basedir, get_path());
680 if (err) {
681 _err_print_error("GDScript::load_byte_code", path.empty() ? "built-in" : (const char *)path.utf8().get_data(), parser.get_error_line(), ("Parse Error: " + parser.get_error()).utf8().get_data(), ERR_HANDLER_SCRIPT);
682 ERR_FAIL_V(ERR_PARSE_ERROR);
683 }
684
685 GDCompiler compiler;
686 err = compiler.compile(&parser, this);
687
688 if (err) {
689 _err_print_error("GDScript::load_byte_code", path.empty() ? "built-in" : (const char *)path.utf8().get_data(), compiler.get_error_line(), ("Compile Error: " + compiler.get_error()).utf8().get_data(), ERR_HANDLER_SCRIPT);
690 ERR_FAIL_V(ERR_COMPILATION_FAILED);
691 }
692
693 valid = true;
694
695 for (Map<StringName, Ref<GDScript> >::Element *E = subclasses.front(); E; E = E->next()) {
696
697 _set_subclass_path(E->get(), path);
698 }
699
700 return OK;
701 }
702
load_source_code(const String & p_path)703 Error GDScript::load_source_code(const String &p_path) {
704
705 DVector<uint8_t> sourcef;
706 Error err;
707 FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err);
708 if (err) {
709
710 ERR_FAIL_COND_V(err, err);
711 }
712
713 int len = f->get_len();
714 sourcef.resize(len + 1);
715 DVector<uint8_t>::Write w = sourcef.write();
716 int r = f->get_buffer(w.ptr(), len);
717 f->close();
718 memdelete(f);
719 ERR_FAIL_COND_V(r != len, ERR_CANT_OPEN);
720 w[len] = 0;
721
722 String s;
723 if (s.parse_utf8((const char *)w.ptr())) {
724
725 ERR_EXPLAIN("Script '" + p_path + "' contains invalid unicode (utf-8), so it was not loaded. Please ensure that scripts are saved in valid utf-8 unicode.");
726 ERR_FAIL_V(ERR_INVALID_DATA);
727 }
728
729 source = s;
730 #ifdef TOOLS_ENABLED
731 source_changed_cache = true;
732 #endif
733 //print_line("LSC :"+get_path());
734 path = p_path;
735 return OK;
736 }
737
debug_get_member_functions() const738 const Map<StringName, GDFunction *> &GDScript::debug_get_member_functions() const {
739
740 return member_functions;
741 }
742
debug_get_member_by_index(int p_idx) const743 StringName GDScript::debug_get_member_by_index(int p_idx) const {
744
745 for (const Map<StringName, MemberInfo>::Element *E = member_indices.front(); E; E = E->next()) {
746
747 if (E->get().index == p_idx)
748 return E->key();
749 }
750
751 return "<error>";
752 }
753
get_base() const754 Ref<GDScript> GDScript::get_base() const {
755
756 return base;
757 }
758
has_script_signal(const StringName & p_signal) const759 bool GDScript::has_script_signal(const StringName &p_signal) const {
760 if (_signals.has(p_signal))
761 return true;
762 if (base.is_valid()) {
763 return base->has_script_signal(p_signal);
764 }
765 #ifdef TOOLS_ENABLED
766 else if (base_cache.is_valid()) {
767 return base_cache->has_script_signal(p_signal);
768 }
769
770 #endif
771 return false;
772 }
get_script_signal_list(List<MethodInfo> * r_signals) const773 void GDScript::get_script_signal_list(List<MethodInfo> *r_signals) const {
774
775 for (const Map<StringName, Vector<StringName> >::Element *E = _signals.front(); E; E = E->next()) {
776
777 MethodInfo mi;
778 mi.name = E->key();
779 for (int i = 0; i < E->get().size(); i++) {
780 PropertyInfo arg;
781 arg.name = E->get()[i];
782 mi.arguments.push_back(arg);
783 }
784 r_signals->push_back(mi);
785 }
786
787 if (base.is_valid()) {
788 base->get_script_signal_list(r_signals);
789 }
790 #ifdef TOOLS_ENABLED
791 else if (base_cache.is_valid()) {
792 base_cache->get_script_signal_list(r_signals);
793 }
794
795 #endif
796 }
797
GDScript()798 GDScript::GDScript() :
799 script_list(this) {
800
801 _static_ref = this;
802 valid = false;
803 subclass_count = 0;
804 initializer = NULL;
805 _base = NULL;
806 _owner = NULL;
807 tool = false;
808 #ifdef TOOLS_ENABLED
809 source_changed_cache = false;
810 #endif
811
812 #ifdef DEBUG_ENABLED
813 if (GDScriptLanguage::get_singleton()->lock) {
814 GDScriptLanguage::get_singleton()->lock->lock();
815 }
816 GDScriptLanguage::get_singleton()->script_list.add(&script_list);
817
818 if (GDScriptLanguage::get_singleton()->lock) {
819 GDScriptLanguage::get_singleton()->lock->unlock();
820 }
821 #endif
822 }
823
~GDScript()824 GDScript::~GDScript() {
825 for (Map<StringName, GDFunction *>::Element *E = member_functions.front(); E; E = E->next()) {
826 memdelete(E->get());
827 }
828
829 for (Map<StringName, Ref<GDScript> >::Element *E = subclasses.front(); E; E = E->next()) {
830 E->get()->_owner = NULL; //bye, you are no longer owned cause I died
831 }
832
833 #ifdef DEBUG_ENABLED
834 if (GDScriptLanguage::get_singleton()->lock) {
835 GDScriptLanguage::get_singleton()->lock->lock();
836 }
837 GDScriptLanguage::get_singleton()->script_list.remove(&script_list);
838
839 if (GDScriptLanguage::get_singleton()->lock) {
840 GDScriptLanguage::get_singleton()->lock->unlock();
841 }
842 #endif
843 }
844
845 //////////////////////////////
846 // INSTANCE //
847 //////////////////////////////
848
set(const StringName & p_name,const Variant & p_value)849 bool GDInstance::set(const StringName &p_name, const Variant &p_value) {
850
851 //member
852 {
853 const Map<StringName, GDScript::MemberInfo>::Element *E = script->member_indices.find(p_name);
854 if (E) {
855 if (E->get().setter) {
856 const Variant *val = &p_value;
857 Variant::CallError err;
858 call(E->get().setter, &val, 1, err);
859 if (err.error == Variant::CallError::CALL_OK) {
860 return true; //function exists, call was successful
861 }
862 } else
863 members[E->get().index] = p_value;
864 return true;
865 }
866 }
867
868 GDScript *sptr = script.ptr();
869 while (sptr) {
870
871 Map<StringName, GDFunction *>::Element *E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._set);
872 if (E) {
873
874 Variant name = p_name;
875 const Variant *args[2] = { &name, &p_value };
876
877 Variant::CallError err;
878 Variant ret = E->get()->call(this, (const Variant **)args, 2, err);
879 if (err.error == Variant::CallError::CALL_OK && ret.get_type() == Variant::BOOL && ret.operator bool())
880 return true;
881 }
882 sptr = sptr->_base;
883 }
884
885 return false;
886 }
887
get(const StringName & p_name,Variant & r_ret) const888 bool GDInstance::get(const StringName &p_name, Variant &r_ret) const {
889
890 const GDScript *sptr = script.ptr();
891 while (sptr) {
892
893 {
894 const Map<StringName, GDScript::MemberInfo>::Element *E = script->member_indices.find(p_name);
895 if (E) {
896 if (E->get().getter) {
897 Variant::CallError err;
898 r_ret = const_cast<GDInstance *>(this)->call(E->get().getter, NULL, 0, err);
899 if (err.error == Variant::CallError::CALL_OK) {
900 return true;
901 }
902 }
903 r_ret = members[E->get().index];
904 return true; //index found
905 }
906 }
907
908 {
909
910 const GDScript *sl = sptr;
911 while (sl) {
912 const Map<StringName, Variant>::Element *E = sl->constants.find(p_name);
913 if (E) {
914 r_ret = E->get();
915 return true; //index found
916 }
917 sl = sl->_base;
918 }
919 }
920
921 {
922 const Map<StringName, GDFunction *>::Element *E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._get);
923 if (E) {
924
925 Variant name = p_name;
926 const Variant *args[1] = { &name };
927
928 Variant::CallError err;
929 Variant ret = const_cast<GDFunction *>(E->get())->call(const_cast<GDInstance *>(this), (const Variant **)args, 1, err);
930 if (err.error == Variant::CallError::CALL_OK && ret.get_type() != Variant::NIL) {
931 r_ret = ret;
932 return true;
933 }
934 }
935 }
936 sptr = sptr->_base;
937 }
938
939 return false;
940 }
941
get_property_type(const StringName & p_name,bool * r_is_valid) const942 Variant::Type GDInstance::get_property_type(const StringName &p_name, bool *r_is_valid) const {
943
944 const GDScript *sptr = script.ptr();
945 while (sptr) {
946
947 if (sptr->member_info.has(p_name)) {
948 if (r_is_valid)
949 *r_is_valid = true;
950 return sptr->member_info[p_name].type;
951 }
952 sptr = sptr->_base;
953 }
954
955 if (r_is_valid)
956 *r_is_valid = false;
957 return Variant::NIL;
958 }
959
get_property_list(List<PropertyInfo> * p_properties) const960 void GDInstance::get_property_list(List<PropertyInfo> *p_properties) const {
961 // exported members, not doen yet!
962
963 const GDScript *sptr = script.ptr();
964 List<PropertyInfo> props;
965
966 while (sptr) {
967
968 const Map<StringName, GDFunction *>::Element *E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._get_property_list);
969 if (E) {
970
971 Variant::CallError err;
972 Variant ret = const_cast<GDFunction *>(E->get())->call(const_cast<GDInstance *>(this), NULL, 0, err);
973 if (err.error == Variant::CallError::CALL_OK) {
974
975 if (ret.get_type() != Variant::ARRAY) {
976
977 ERR_EXPLAIN("Wrong type for _get_property list, must be an array of dictionaries.");
978 ERR_FAIL();
979 }
980 Array arr = ret;
981 for (int i = 0; i < arr.size(); i++) {
982
983 Dictionary d = arr[i];
984 ERR_CONTINUE(!d.has("name"));
985 ERR_CONTINUE(!d.has("type"));
986 PropertyInfo pinfo;
987 pinfo.type = Variant::Type(d["type"].operator int());
988 ERR_CONTINUE(pinfo.type < 0 || pinfo.type >= Variant::VARIANT_MAX);
989 pinfo.name = d["name"];
990 ERR_CONTINUE(pinfo.name == "");
991 if (d.has("hint"))
992 pinfo.hint = PropertyHint(d["hint"].operator int());
993 if (d.has("hint_string"))
994 pinfo.hint_string = d["hint_string"];
995 if (d.has("usage"))
996 pinfo.usage = d["usage"];
997
998 props.push_back(pinfo);
999 }
1000 }
1001 }
1002
1003 //instance a fake script for editing the values
1004
1005 Vector<_GDScriptMemberSort> msort;
1006 for (Map<StringName, PropertyInfo>::Element *E = sptr->member_info.front(); E; E = E->next()) {
1007
1008 _GDScriptMemberSort ms;
1009 ERR_CONTINUE(!sptr->member_indices.has(E->key()));
1010 ms.index = sptr->member_indices[E->key()].index;
1011 ms.name = E->key();
1012 msort.push_back(ms);
1013 }
1014
1015 msort.sort();
1016 msort.invert();
1017 for (int i = 0; i < msort.size(); i++) {
1018
1019 props.push_front(sptr->member_info[msort[i].name]);
1020 }
1021 #if 0
1022 if (sptr->member_functions.has("_get_property_list")) {
1023
1024 Variant::CallError err;
1025 GDFunction *f = const_cast<GDFunction*>(sptr->member_functions["_get_property_list"]);
1026 Variant plv = f->call(const_cast<GDInstance*>(this),NULL,0,err);
1027
1028 if (plv.get_type()!=Variant::ARRAY) {
1029
1030 ERR_PRINT("_get_property_list: expected array returned");
1031 } else {
1032
1033 Array pl=plv;
1034
1035 for(int i=0;i<pl.size();i++) {
1036
1037 Dictionary p = pl[i];
1038 PropertyInfo pinfo;
1039 if (!p.has("name")) {
1040 ERR_PRINT("_get_property_list: expected 'name' key of type string.")
1041 continue;
1042 }
1043 if (!p.has("type")) {
1044 ERR_PRINT("_get_property_list: expected 'type' key of type integer.")
1045 continue;
1046 }
1047 pinfo.name=p["name"];
1048 pinfo.type=Variant::Type(int(p["type"]));
1049 if (p.has("hint"))
1050 pinfo.hint=PropertyHint(int(p["hint"]));
1051 if (p.has("hint_string"))
1052 pinfo.hint_string=p["hint_string"];
1053 if (p.has("usage"))
1054 pinfo.usage=p["usage"];
1055
1056
1057 props.push_back(pinfo);
1058 }
1059 }
1060 }
1061 #endif
1062
1063 sptr = sptr->_base;
1064 }
1065
1066 //props.invert();
1067
1068 for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) {
1069
1070 p_properties->push_back(E->get());
1071 }
1072 }
1073
get_method_list(List<MethodInfo> * p_list) const1074 void GDInstance::get_method_list(List<MethodInfo> *p_list) const {
1075
1076 const GDScript *sptr = script.ptr();
1077 while (sptr) {
1078
1079 for (Map<StringName, GDFunction *>::Element *E = sptr->member_functions.front(); E; E = E->next()) {
1080
1081 MethodInfo mi;
1082 mi.name = E->key();
1083 mi.flags |= METHOD_FLAG_FROM_SCRIPT;
1084 for (int i = 0; i < E->get()->get_argument_count(); i++)
1085 mi.arguments.push_back(PropertyInfo(Variant::NIL, "arg" + itos(i)));
1086 p_list->push_back(mi);
1087 }
1088 sptr = sptr->_base;
1089 }
1090 }
1091
has_method(const StringName & p_method) const1092 bool GDInstance::has_method(const StringName &p_method) const {
1093
1094 const GDScript *sptr = script.ptr();
1095 while (sptr) {
1096 const Map<StringName, GDFunction *>::Element *E = sptr->member_functions.find(p_method);
1097 if (E)
1098 return true;
1099 sptr = sptr->_base;
1100 }
1101
1102 return false;
1103 }
call(const StringName & p_method,const Variant ** p_args,int p_argcount,Variant::CallError & r_error)1104 Variant GDInstance::call(const StringName &p_method, const Variant **p_args, int p_argcount, Variant::CallError &r_error) {
1105
1106 //printf("calling %ls:%i method %ls\n", script->get_path().c_str(), -1, String(p_method).c_str());
1107
1108 GDScript *sptr = script.ptr();
1109 while (sptr) {
1110 Map<StringName, GDFunction *>::Element *E = sptr->member_functions.find(p_method);
1111 if (E) {
1112 return E->get()->call(this, p_args, p_argcount, r_error);
1113 }
1114 sptr = sptr->_base;
1115 }
1116 r_error.error = Variant::CallError::CALL_ERROR_INVALID_METHOD;
1117 return Variant();
1118 }
1119
call_multilevel(const StringName & p_method,const Variant ** p_args,int p_argcount)1120 void GDInstance::call_multilevel(const StringName &p_method, const Variant **p_args, int p_argcount) {
1121
1122 GDScript *sptr = script.ptr();
1123 Variant::CallError ce;
1124
1125 while (sptr) {
1126 Map<StringName, GDFunction *>::Element *E = sptr->member_functions.find(p_method);
1127 if (E) {
1128 E->get()->call(this, p_args, p_argcount, ce);
1129 }
1130 sptr = sptr->_base;
1131 }
1132 }
1133
_ml_call_reversed(GDScript * sptr,const StringName & p_method,const Variant ** p_args,int p_argcount)1134 void GDInstance::_ml_call_reversed(GDScript *sptr, const StringName &p_method, const Variant **p_args, int p_argcount) {
1135
1136 if (sptr->_base)
1137 _ml_call_reversed(sptr->_base, p_method, p_args, p_argcount);
1138
1139 Variant::CallError ce;
1140
1141 Map<StringName, GDFunction *>::Element *E = sptr->member_functions.find(p_method);
1142 if (E) {
1143 E->get()->call(this, p_args, p_argcount, ce);
1144 }
1145 }
1146
call_multilevel_reversed(const StringName & p_method,const Variant ** p_args,int p_argcount)1147 void GDInstance::call_multilevel_reversed(const StringName &p_method, const Variant **p_args, int p_argcount) {
1148
1149 if (script.ptr()) {
1150 _ml_call_reversed(script.ptr(), p_method, p_args, p_argcount);
1151 }
1152 }
1153
notification(int p_notification)1154 void GDInstance::notification(int p_notification) {
1155
1156 //notification is not virutal, it gets called at ALL levels just like in C.
1157 Variant value = p_notification;
1158 const Variant *args[1] = { &value };
1159
1160 GDScript *sptr = script.ptr();
1161 while (sptr) {
1162 Map<StringName, GDFunction *>::Element *E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._notification);
1163 if (E) {
1164 Variant::CallError err;
1165 E->get()->call(this, args, 1, err);
1166 if (err.error != Variant::CallError::CALL_OK) {
1167 //print error about notification call
1168 }
1169 }
1170 sptr = sptr->_base;
1171 }
1172 }
1173
get_script() const1174 Ref<Script> GDInstance::get_script() const {
1175
1176 return script;
1177 }
1178
get_language()1179 ScriptLanguage *GDInstance::get_language() {
1180
1181 return GDScriptLanguage::get_singleton();
1182 }
1183
reload_members()1184 void GDInstance::reload_members() {
1185
1186 #ifdef DEBUG_ENABLED
1187
1188 members.resize(script->member_indices.size()); //resize
1189
1190 Vector<Variant> new_members;
1191 new_members.resize(script->member_indices.size());
1192
1193 //pass the values to the new indices
1194 for (Map<StringName, GDScript::MemberInfo>::Element *E = script->member_indices.front(); E; E = E->next()) {
1195
1196 if (member_indices_cache.has(E->key())) {
1197 Variant value = members[member_indices_cache[E->key()]];
1198 new_members[E->get().index] = value;
1199 }
1200 }
1201
1202 //apply
1203 members = new_members;
1204
1205 //pass the values to the new indices
1206 member_indices_cache.clear();
1207 for (Map<StringName, GDScript::MemberInfo>::Element *E = script->member_indices.front(); E; E = E->next()) {
1208
1209 member_indices_cache[E->key()] = E->get().index;
1210 }
1211
1212 #endif
1213 }
1214
GDInstance()1215 GDInstance::GDInstance() {
1216 owner = NULL;
1217 base_ref = false;
1218 }
1219
~GDInstance()1220 GDInstance::~GDInstance() {
1221 if (script.is_valid() && owner) {
1222 script->instances.erase(owner);
1223 }
1224 }
1225
1226 /************* SCRIPT LANGUAGE **************/
1227 /************* SCRIPT LANGUAGE **************/
1228 /************* SCRIPT LANGUAGE **************/
1229 /************* SCRIPT LANGUAGE **************/
1230 /************* SCRIPT LANGUAGE **************/
1231
1232 GDScriptLanguage *GDScriptLanguage::singleton = NULL;
1233
get_name() const1234 String GDScriptLanguage::get_name() const {
1235
1236 return "GDScript";
1237 }
1238
1239 /* LANGUAGE FUNCTIONS */
1240
_add_global(const StringName & p_name,const Variant & p_value)1241 void GDScriptLanguage::_add_global(const StringName &p_name, const Variant &p_value) {
1242
1243 if (globals.has(p_name)) {
1244 //overwrite existing
1245 global_array[globals[p_name]] = p_value;
1246 return;
1247 }
1248 globals[p_name] = global_array.size();
1249 global_array.push_back(p_value);
1250 _global_array = global_array.ptr();
1251 }
1252
add_global_constant(const StringName & p_variable,const Variant & p_value)1253 void GDScriptLanguage::add_global_constant(const StringName &p_variable, const Variant &p_value) {
1254
1255 _add_global(p_variable, p_value);
1256 }
1257
init()1258 void GDScriptLanguage::init() {
1259
1260 //populate global constants
1261 int gcc = GlobalConstants::get_global_constant_count();
1262 for (int i = 0; i < gcc; i++) {
1263
1264 _add_global(StaticCString::create(GlobalConstants::get_global_constant_name(i)), GlobalConstants::get_global_constant_value(i));
1265 }
1266
1267 _add_global(StaticCString::create("PI"), Math_PI);
1268
1269 //populate native classes
1270
1271 List<StringName> class_list;
1272 ObjectTypeDB::get_type_list(&class_list);
1273 for (List<StringName>::Element *E = class_list.front(); E; E = E->next()) {
1274
1275 StringName n = E->get();
1276 String s = String(n);
1277 if (s.begins_with("_"))
1278 n = s.substr(1, s.length());
1279
1280 if (globals.has(n))
1281 continue;
1282 Ref<GDNativeClass> nc = memnew(GDNativeClass(E->get()));
1283 _add_global(n, nc);
1284 }
1285
1286 //populate singletons
1287
1288 List<Globals::Singleton> singletons;
1289 Globals::get_singleton()->get_singletons(&singletons);
1290 for (List<Globals::Singleton>::Element *E = singletons.front(); E; E = E->next()) {
1291
1292 _add_global(E->get().name, E->get().ptr);
1293 }
1294 }
1295
get_type() const1296 String GDScriptLanguage::get_type() const {
1297
1298 return "GDScript";
1299 }
get_extension() const1300 String GDScriptLanguage::get_extension() const {
1301
1302 return "gd";
1303 }
execute_file(const String & p_path)1304 Error GDScriptLanguage::execute_file(const String &p_path) {
1305
1306 // ??
1307 return OK;
1308 }
finish()1309 void GDScriptLanguage::finish() {
1310 }
1311
profiling_start()1312 void GDScriptLanguage::profiling_start() {
1313
1314 #ifdef DEBUG_ENABLED
1315 if (lock) {
1316 lock->lock();
1317 }
1318
1319 SelfList<GDFunction> *elem = function_list.first();
1320 while (elem) {
1321 elem->self()->profile.call_count = 0;
1322 elem->self()->profile.self_time = 0;
1323 elem->self()->profile.total_time = 0;
1324 elem->self()->profile.frame_call_count = 0;
1325 elem->self()->profile.frame_self_time = 0;
1326 elem->self()->profile.frame_total_time = 0;
1327 elem->self()->profile.last_frame_call_count = 0;
1328 elem->self()->profile.last_frame_self_time = 0;
1329 elem->self()->profile.last_frame_total_time = 0;
1330 elem = elem->next();
1331 }
1332
1333 profiling = true;
1334 if (lock) {
1335 lock->unlock();
1336 }
1337
1338 #endif
1339 }
1340
profiling_stop()1341 void GDScriptLanguage::profiling_stop() {
1342
1343 #ifdef DEBUG_ENABLED
1344 if (lock) {
1345 lock->lock();
1346 }
1347
1348 profiling = false;
1349 if (lock) {
1350 lock->unlock();
1351 }
1352
1353 #endif
1354 }
1355
profiling_get_accumulated_data(ProfilingInfo * p_info_arr,int p_info_max)1356 int GDScriptLanguage::profiling_get_accumulated_data(ProfilingInfo *p_info_arr, int p_info_max) {
1357
1358 int current = 0;
1359 #ifdef DEBUG_ENABLED
1360 if (lock) {
1361 lock->lock();
1362 }
1363
1364 SelfList<GDFunction> *elem = function_list.first();
1365 while (elem) {
1366 if (current >= p_info_max)
1367 break;
1368 p_info_arr[current].call_count = elem->self()->profile.call_count;
1369 p_info_arr[current].self_time = elem->self()->profile.self_time;
1370 p_info_arr[current].total_time = elem->self()->profile.total_time;
1371 p_info_arr[current].signature = elem->self()->profile.signature;
1372 elem = elem->next();
1373 current++;
1374 }
1375
1376 if (lock) {
1377 lock->unlock();
1378 }
1379
1380 #endif
1381
1382 return current;
1383 }
1384
profiling_get_frame_data(ProfilingInfo * p_info_arr,int p_info_max)1385 int GDScriptLanguage::profiling_get_frame_data(ProfilingInfo *p_info_arr, int p_info_max) {
1386
1387 int current = 0;
1388
1389 #ifdef DEBUG_ENABLED
1390 if (lock) {
1391 lock->lock();
1392 }
1393
1394 SelfList<GDFunction> *elem = function_list.first();
1395 while (elem) {
1396 if (current >= p_info_max)
1397 break;
1398 if (elem->self()->profile.last_frame_call_count > 0) {
1399 p_info_arr[current].call_count = elem->self()->profile.last_frame_call_count;
1400 p_info_arr[current].self_time = elem->self()->profile.last_frame_self_time;
1401 p_info_arr[current].total_time = elem->self()->profile.last_frame_total_time;
1402 p_info_arr[current].signature = elem->self()->profile.signature;
1403 //print_line(String(elem->self()->profile.signature)+": "+itos(elem->self()->profile.last_frame_call_count));
1404 current++;
1405 }
1406 elem = elem->next();
1407 }
1408
1409 if (lock) {
1410 lock->unlock();
1411 }
1412
1413 #endif
1414
1415 return current;
1416 }
1417
1418 struct GDScriptDepSort {
1419
1420 //must support sorting so inheritance works properly (parent must be reloaded first)
operator ()GDScriptDepSort1421 bool operator()(const Ref<GDScript> &A, const Ref<GDScript> &B) const {
1422
1423 if (A == B)
1424 return false; //shouldn't happen but..
1425 const GDScript *I = B->get_base().ptr();
1426 while (I) {
1427 if (I == A.ptr()) {
1428 // A is a base of B
1429 return true;
1430 }
1431
1432 I = I->get_base().ptr();
1433 }
1434
1435 return false; //not a base
1436 }
1437 };
1438
reload_all_scripts()1439 void GDScriptLanguage::reload_all_scripts() {
1440
1441 #ifdef DEBUG_ENABLED
1442 print_line("RELOAD ALL SCRIPTS");
1443 if (lock) {
1444 lock->lock();
1445 }
1446
1447 List<Ref<GDScript> > scripts;
1448
1449 SelfList<GDScript> *elem = script_list.first();
1450 while (elem) {
1451 if (elem->self()->get_path().is_resource_file()) {
1452 print_line("FOUND: " + elem->self()->get_path());
1453 scripts.push_back(Ref<GDScript>(elem->self())); //cast to gdscript to avoid being erased by accident
1454 }
1455 elem = elem->next();
1456 }
1457
1458 if (lock) {
1459 lock->unlock();
1460 }
1461
1462 //as scripts are going to be reloaded, must proceed without locking here
1463
1464 scripts.sort_custom<GDScriptDepSort>(); //update in inheritance dependency order
1465
1466 for (List<Ref<GDScript> >::Element *E = scripts.front(); E; E = E->next()) {
1467
1468 print_line("RELOADING: " + E->get()->get_path());
1469 E->get()->load_source_code(E->get()->get_path());
1470 E->get()->reload(true);
1471 }
1472 #endif
1473 }
1474
reload_tool_script(const Ref<Script> & p_script,bool p_soft_reload)1475 void GDScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_soft_reload) {
1476
1477 #ifdef DEBUG_ENABLED
1478
1479 if (lock) {
1480 lock->lock();
1481 }
1482
1483 List<Ref<GDScript> > scripts;
1484
1485 SelfList<GDScript> *elem = script_list.first();
1486 while (elem) {
1487 if (elem->self()->get_path().is_resource_file()) {
1488
1489 scripts.push_back(Ref<GDScript>(elem->self())); //cast to gdscript to avoid being erased by accident
1490 }
1491 elem = elem->next();
1492 }
1493
1494 if (lock) {
1495 lock->unlock();
1496 }
1497
1498 //when someone asks you why dynamically typed languages are easier to write....
1499
1500 Map<Ref<GDScript>, Map<ObjectID, List<Pair<StringName, Variant> > > > to_reload;
1501
1502 //as scripts are going to be reloaded, must proceed without locking here
1503
1504 scripts.sort_custom<GDScriptDepSort>(); //update in inheritance dependency order
1505
1506 for (List<Ref<GDScript> >::Element *E = scripts.front(); E; E = E->next()) {
1507
1508 bool reload = E->get() == p_script || to_reload.has(E->get()->get_base());
1509
1510 if (!reload)
1511 continue;
1512
1513 to_reload.insert(E->get(), Map<ObjectID, List<Pair<StringName, Variant> > >());
1514
1515 if (!p_soft_reload) {
1516
1517 //save state and remove script from instances
1518 Map<ObjectID, List<Pair<StringName, Variant> > > &map = to_reload[E->get()];
1519
1520 while (E->get()->instances.front()) {
1521 Object *obj = E->get()->instances.front()->get();
1522 //save instance info
1523 List<Pair<StringName, Variant> > state;
1524 if (obj->get_script_instance()) {
1525
1526 obj->get_script_instance()->get_property_state(state);
1527 map[obj->get_instance_ID()] = state;
1528 obj->set_script(RefPtr());
1529 }
1530 }
1531
1532 //same thing for placeholders
1533 #ifdef TOOLS_ENABLED
1534
1535 while (E->get()->placeholders.size()) {
1536 Object *obj = E->get()->placeholders.front()->get()->get_owner();
1537
1538 //save instance info
1539 List<Pair<StringName, Variant> > state;
1540 if (obj->get_script_instance()) {
1541
1542 obj->get_script_instance()->get_property_state(state);
1543 map[obj->get_instance_ID()] = state;
1544 obj->set_script(RefPtr());
1545 } else {
1546 // no instance found. Let's remove it so we don't loop forever
1547 E->get()->placeholders.erase(E->get()->placeholders.front()->get());
1548 }
1549 }
1550 #endif
1551
1552 for (Map<ObjectID, List<Pair<StringName, Variant> > >::Element *F = E->get()->pending_reload_state.front(); F; F = F->next()) {
1553 map[F->key()] = F->get(); //pending to reload, use this one instead
1554 }
1555 }
1556 }
1557
1558 for (Map<Ref<GDScript>, Map<ObjectID, List<Pair<StringName, Variant> > > >::Element *E = to_reload.front(); E; E = E->next()) {
1559
1560 Ref<GDScript> scr = E->key();
1561 scr->reload(p_soft_reload);
1562
1563 //restore state if saved
1564 for (Map<ObjectID, List<Pair<StringName, Variant> > >::Element *F = E->get().front(); F; F = F->next()) {
1565
1566 Object *obj = ObjectDB::get_instance(F->key());
1567 if (!obj)
1568 continue;
1569
1570 if (!p_soft_reload) {
1571 //clear it just in case (may be a pending reload state)
1572 obj->set_script(RefPtr());
1573 }
1574 obj->set_script(scr.get_ref_ptr());
1575 if (!obj->get_script_instance()) {
1576 //failed, save reload state for next time if not saved
1577 if (!scr->pending_reload_state.has(obj->get_instance_ID())) {
1578 scr->pending_reload_state[obj->get_instance_ID()] = F->get();
1579 }
1580 continue;
1581 }
1582
1583 for (List<Pair<StringName, Variant> >::Element *G = F->get().front(); G; G = G->next()) {
1584 obj->get_script_instance()->set(G->get().first, G->get().second);
1585 }
1586
1587 scr->pending_reload_state.erase(obj->get_instance_ID()); //as it reloaded, remove pending state
1588 }
1589
1590 //if instance states were saved, set them!
1591 }
1592
1593 #endif
1594 }
1595
frame()1596 void GDScriptLanguage::frame() {
1597
1598 // print_line("calls: "+itos(calls));
1599 calls = 0;
1600
1601 #ifdef DEBUG_ENABLED
1602 if (profiling) {
1603 if (lock) {
1604 lock->lock();
1605 }
1606
1607 SelfList<GDFunction> *elem = function_list.first();
1608 while (elem) {
1609 elem->self()->profile.last_frame_call_count = elem->self()->profile.frame_call_count;
1610 elem->self()->profile.last_frame_self_time = elem->self()->profile.frame_self_time;
1611 elem->self()->profile.last_frame_total_time = elem->self()->profile.frame_total_time;
1612 elem->self()->profile.frame_call_count = 0;
1613 elem->self()->profile.frame_self_time = 0;
1614 elem->self()->profile.frame_total_time = 0;
1615 elem = elem->next();
1616 }
1617
1618 if (lock) {
1619 lock->unlock();
1620 }
1621 }
1622
1623 #endif
1624 }
1625
1626 /* EDITOR FUNCTIONS */
get_reserved_words(List<String> * p_words) const1627 void GDScriptLanguage::get_reserved_words(List<String> *p_words) const {
1628
1629 static const char *_reserved_words[] = {
1630 // operators
1631 "and",
1632 "in",
1633 "not",
1634 "or",
1635 // types and values
1636 "false",
1637 "float",
1638 "int",
1639 "bool",
1640 "null",
1641 "PI",
1642 "self",
1643 "true",
1644 // functions
1645 "assert",
1646 "breakpoint",
1647 "class",
1648 "extends",
1649 "func",
1650 "preload",
1651 "setget",
1652 "signal",
1653 "tool",
1654 "yield",
1655 // var
1656 "const",
1657 "enum",
1658 "export",
1659 "onready",
1660 "static",
1661 "var",
1662 // control flow
1663 "break",
1664 "continue",
1665 "if",
1666 "elif",
1667 "else",
1668 "for",
1669 "pass",
1670 "return",
1671 "while",
1672 0
1673 };
1674
1675 const char **w = _reserved_words;
1676
1677 while (*w) {
1678
1679 p_words->push_back(*w);
1680 w++;
1681 }
1682
1683 for (int i = 0; i < GDFunctions::FUNC_MAX; i++) {
1684 p_words->push_back(GDFunctions::get_func_name(GDFunctions::Function(i)));
1685 }
1686 }
1687
GDScriptLanguage()1688 GDScriptLanguage::GDScriptLanguage() {
1689
1690 calls = 0;
1691 ERR_FAIL_COND(singleton);
1692 singleton = this;
1693 strings._init = StaticCString::create("_init");
1694 strings._notification = StaticCString::create("_notification");
1695 strings._set = StaticCString::create("_set");
1696 strings._get = StaticCString::create("_get");
1697 strings._get_property_list = StaticCString::create("_get_property_list");
1698 strings._script_source = StaticCString::create("script/source");
1699 _debug_parse_err_line = -1;
1700 _debug_parse_err_file = "";
1701
1702 #ifdef NO_THREADS
1703 lock = NULL;
1704 #else
1705 lock = Mutex::create();
1706 #endif
1707 profiling = false;
1708 script_frame_time = 0;
1709
1710 _debug_call_stack_pos = 0;
1711 int dmcs = GLOBAL_DEF("debug/script_max_call_stack", 1024);
1712 if (ScriptDebugger::get_singleton()) {
1713 //debugging enabled!
1714
1715 _debug_max_call_stack = dmcs;
1716 if (_debug_max_call_stack < 1024)
1717 _debug_max_call_stack = 1024;
1718 _call_stack = memnew_arr(CallLevel, _debug_max_call_stack + 1);
1719
1720 } else {
1721 _debug_max_call_stack = 0;
1722 _call_stack = NULL;
1723 }
1724 }
1725
~GDScriptLanguage()1726 GDScriptLanguage::~GDScriptLanguage() {
1727
1728 if (lock) {
1729 memdelete(lock);
1730 lock = NULL;
1731 }
1732 if (_call_stack) {
1733 memdelete_arr(_call_stack);
1734 }
1735 singleton = NULL;
1736 }
1737
1738 /*************** RESOURCE ***************/
1739
load(const String & p_path,const String & p_original_path,Error * r_error)1740 RES ResourceFormatLoaderGDScript::load(const String &p_path, const String &p_original_path, Error *r_error) {
1741
1742 if (r_error)
1743 *r_error = ERR_FILE_CANT_OPEN;
1744
1745 GDScript *script = memnew(GDScript);
1746
1747 Ref<GDScript> scriptres(script);
1748
1749 if (p_path.ends_with(".gde") || p_path.ends_with(".gdc")) {
1750
1751 script->set_script_path(p_original_path); // script needs this.
1752 script->set_path(p_original_path);
1753 Error err = script->load_byte_code(p_path);
1754
1755 if (err != OK) {
1756
1757 ERR_FAIL_COND_V(err != OK, RES());
1758 }
1759
1760 } else {
1761 Error err = script->load_source_code(p_path);
1762
1763 if (err != OK) {
1764
1765 ERR_FAIL_COND_V(err != OK, RES());
1766 }
1767
1768 script->set_script_path(p_original_path); // script needs this.
1769 script->set_path(p_original_path);
1770 //script->set_name(p_path.get_file());
1771
1772 script->reload();
1773 }
1774 if (r_error)
1775 *r_error = OK;
1776
1777 return scriptres;
1778 }
get_recognized_extensions(List<String> * p_extensions) const1779 void ResourceFormatLoaderGDScript::get_recognized_extensions(List<String> *p_extensions) const {
1780
1781 p_extensions->push_back("gd");
1782 p_extensions->push_back("gdc");
1783 p_extensions->push_back("gde");
1784 }
1785
handles_type(const String & p_type) const1786 bool ResourceFormatLoaderGDScript::handles_type(const String &p_type) const {
1787
1788 return (p_type == "Script" || p_type == "GDScript");
1789 }
1790
get_resource_type(const String & p_path) const1791 String ResourceFormatLoaderGDScript::get_resource_type(const String &p_path) const {
1792
1793 String el = p_path.extension().to_lower();
1794 if (el == "gd" || el == "gdc" || el == "gde")
1795 return "GDScript";
1796 return "";
1797 }
1798
save(const String & p_path,const RES & p_resource,uint32_t p_flags)1799 Error ResourceFormatSaverGDScript::save(const String &p_path, const RES &p_resource, uint32_t p_flags) {
1800
1801 Ref<GDScript> sqscr = p_resource;
1802 ERR_FAIL_COND_V(sqscr.is_null(), ERR_INVALID_PARAMETER);
1803
1804 String source = sqscr->get_source_code();
1805
1806 Error err;
1807 FileAccess *file = FileAccess::open(p_path, FileAccess::WRITE, &err);
1808
1809 if (err) {
1810
1811 ERR_FAIL_COND_V(err, err);
1812 }
1813
1814 file->store_string(source);
1815 if (file->get_error() != OK && file->get_error() != ERR_FILE_EOF) {
1816 memdelete(file);
1817 return ERR_CANT_CREATE;
1818 }
1819 file->close();
1820 memdelete(file);
1821
1822 if (ScriptServer::is_reload_scripts_on_save_enabled()) {
1823 GDScriptLanguage::get_singleton()->reload_tool_script(p_resource, false);
1824 }
1825
1826 return OK;
1827 }
1828
get_recognized_extensions(const RES & p_resource,List<String> * p_extensions) const1829 void ResourceFormatSaverGDScript::get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const {
1830
1831 if (p_resource->cast_to<GDScript>()) {
1832 p_extensions->push_back("gd");
1833 }
1834 }
recognize(const RES & p_resource) const1835 bool ResourceFormatSaverGDScript::recognize(const RES &p_resource) const {
1836
1837 return p_resource->cast_to<GDScript>() != NULL;
1838 }
1839