1 /*************************************************************************/
2 /* script_language.cpp */
3 /*************************************************************************/
4 /* This file is part of: */
5 /* GODOT ENGINE */
6 /* https://godotengine.org */
7 /*************************************************************************/
8 /* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
9 /* Copyright (c) 2014-2020 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
31 #include "script_language.h"
32
33 #include "core/core_string_names.h"
34 #include "core/project_settings.h"
35
36 ScriptLanguage *ScriptServer::_languages[MAX_LANGUAGES];
37 int ScriptServer::_language_count = 0;
38
39 bool ScriptServer::scripting_enabled = true;
40 bool ScriptServer::reload_scripts_on_save = false;
41 bool ScriptServer::languages_finished = false;
42 ScriptEditRequestFunction ScriptServer::edit_request_func = NULL;
43
_notification(int p_what)44 void Script::_notification(int p_what) {
45
46 if (p_what == NOTIFICATION_POSTINITIALIZE) {
47
48 if (ScriptDebugger::get_singleton())
49 ScriptDebugger::get_singleton()->set_break_language(get_language());
50 }
51 }
52
_get_property_default_value(const StringName & p_property)53 Variant Script::_get_property_default_value(const StringName &p_property) {
54 Variant ret;
55 get_property_default_value(p_property, ret);
56 return ret;
57 }
58
_get_script_property_list()59 Array Script::_get_script_property_list() {
60 Array ret;
61 List<PropertyInfo> list;
62 get_script_property_list(&list);
63 for (List<PropertyInfo>::Element *E = list.front(); E; E = E->next()) {
64 ret.append(E->get().operator Dictionary());
65 }
66 return ret;
67 }
68
_get_script_method_list()69 Array Script::_get_script_method_list() {
70 Array ret;
71 List<MethodInfo> list;
72 get_script_method_list(&list);
73 for (List<MethodInfo>::Element *E = list.front(); E; E = E->next()) {
74 ret.append(E->get().operator Dictionary());
75 }
76 return ret;
77 }
78
_get_script_signal_list()79 Array Script::_get_script_signal_list() {
80 Array ret;
81 List<MethodInfo> list;
82 get_script_signal_list(&list);
83 for (List<MethodInfo>::Element *E = list.front(); E; E = E->next()) {
84 ret.append(E->get().operator Dictionary());
85 }
86 return ret;
87 }
88
_get_script_constant_map()89 Dictionary Script::_get_script_constant_map() {
90 Dictionary ret;
91 Map<StringName, Variant> map;
92 get_constants(&map);
93 for (Map<StringName, Variant>::Element *E = map.front(); E; E = E->next()) {
94 ret[E->key()] = E->value();
95 }
96 return ret;
97 }
98
_bind_methods()99 void Script::_bind_methods() {
100
101 ClassDB::bind_method(D_METHOD("can_instance"), &Script::can_instance);
102 //ClassDB::bind_method(D_METHOD("instance_create","base_object"),&Script::instance_create);
103 ClassDB::bind_method(D_METHOD("instance_has", "base_object"), &Script::instance_has);
104 ClassDB::bind_method(D_METHOD("has_source_code"), &Script::has_source_code);
105 ClassDB::bind_method(D_METHOD("get_source_code"), &Script::get_source_code);
106 ClassDB::bind_method(D_METHOD("set_source_code", "source"), &Script::set_source_code);
107 ClassDB::bind_method(D_METHOD("reload", "keep_state"), &Script::reload, DEFVAL(false));
108 ClassDB::bind_method(D_METHOD("get_base_script"), &Script::get_base_script);
109 ClassDB::bind_method(D_METHOD("get_instance_base_type"), &Script::get_instance_base_type);
110
111 ClassDB::bind_method(D_METHOD("has_script_signal", "signal_name"), &Script::has_script_signal);
112
113 ClassDB::bind_method(D_METHOD("get_script_property_list"), &Script::_get_script_property_list);
114 ClassDB::bind_method(D_METHOD("get_script_method_list"), &Script::_get_script_method_list);
115 ClassDB::bind_method(D_METHOD("get_script_signal_list"), &Script::_get_script_signal_list);
116 ClassDB::bind_method(D_METHOD("get_script_constant_map"), &Script::_get_script_constant_map);
117 ClassDB::bind_method(D_METHOD("get_property_default_value", "property"), &Script::_get_property_default_value);
118
119 ClassDB::bind_method(D_METHOD("is_tool"), &Script::is_tool);
120
121 ADD_PROPERTY(PropertyInfo(Variant::STRING, "source_code", PROPERTY_HINT_NONE, "", 0), "set_source_code", "get_source_code");
122 }
123
set_scripting_enabled(bool p_enabled)124 void ScriptServer::set_scripting_enabled(bool p_enabled) {
125
126 scripting_enabled = p_enabled;
127 }
128
is_scripting_enabled()129 bool ScriptServer::is_scripting_enabled() {
130
131 return scripting_enabled;
132 }
133
get_language(int p_idx)134 ScriptLanguage *ScriptServer::get_language(int p_idx) {
135
136 ERR_FAIL_INDEX_V(p_idx, _language_count, NULL);
137
138 return _languages[p_idx];
139 }
140
register_language(ScriptLanguage * p_language)141 void ScriptServer::register_language(ScriptLanguage *p_language) {
142
143 ERR_FAIL_COND(_language_count >= MAX_LANGUAGES);
144 _languages[_language_count++] = p_language;
145 }
146
unregister_language(ScriptLanguage * p_language)147 void ScriptServer::unregister_language(ScriptLanguage *p_language) {
148
149 for (int i = 0; i < _language_count; i++) {
150 if (_languages[i] == p_language) {
151 _language_count--;
152 if (i < _language_count) {
153 SWAP(_languages[i], _languages[_language_count]);
154 }
155 return;
156 }
157 }
158 }
159
init_languages()160 void ScriptServer::init_languages() {
161
162 { //load global classes
163 global_classes_clear();
164 if (ProjectSettings::get_singleton()->has_setting("_global_script_classes")) {
165 Array script_classes = ProjectSettings::get_singleton()->get("_global_script_classes");
166
167 for (int i = 0; i < script_classes.size(); i++) {
168 Dictionary c = script_classes[i];
169 if (!c.has("class") || !c.has("language") || !c.has("path") || !c.has("base"))
170 continue;
171 add_global_class(c["class"], c["base"], c["language"], c["path"]);
172 }
173 }
174 }
175
176 for (int i = 0; i < _language_count; i++) {
177 _languages[i]->init();
178 }
179 }
180
finish_languages()181 void ScriptServer::finish_languages() {
182
183 for (int i = 0; i < _language_count; i++) {
184 _languages[i]->finish();
185 }
186 global_classes_clear();
187 languages_finished = true;
188 }
189
set_reload_scripts_on_save(bool p_enable)190 void ScriptServer::set_reload_scripts_on_save(bool p_enable) {
191
192 reload_scripts_on_save = p_enable;
193 }
194
is_reload_scripts_on_save_enabled()195 bool ScriptServer::is_reload_scripts_on_save_enabled() {
196
197 return reload_scripts_on_save;
198 }
199
thread_enter()200 void ScriptServer::thread_enter() {
201
202 for (int i = 0; i < _language_count; i++) {
203 _languages[i]->thread_enter();
204 }
205 }
206
thread_exit()207 void ScriptServer::thread_exit() {
208
209 for (int i = 0; i < _language_count; i++) {
210 _languages[i]->thread_exit();
211 }
212 }
213
214 HashMap<StringName, ScriptServer::GlobalScriptClass> ScriptServer::global_classes;
215
global_classes_clear()216 void ScriptServer::global_classes_clear() {
217 global_classes.clear();
218 }
219
add_global_class(const StringName & p_class,const StringName & p_base,const StringName & p_language,const String & p_path)220 void ScriptServer::add_global_class(const StringName &p_class, const StringName &p_base, const StringName &p_language, const String &p_path) {
221 ERR_FAIL_COND_MSG(p_class == p_base || (global_classes.has(p_base) && get_global_class_native_base(p_base) == p_class), "Cyclic inheritance in script class.");
222 GlobalScriptClass g;
223 g.language = p_language;
224 g.path = p_path;
225 g.base = p_base;
226 global_classes[p_class] = g;
227 }
remove_global_class(const StringName & p_class)228 void ScriptServer::remove_global_class(const StringName &p_class) {
229 global_classes.erase(p_class);
230 }
is_global_class(const StringName & p_class)231 bool ScriptServer::is_global_class(const StringName &p_class) {
232 return global_classes.has(p_class);
233 }
get_global_class_language(const StringName & p_class)234 StringName ScriptServer::get_global_class_language(const StringName &p_class) {
235 ERR_FAIL_COND_V(!global_classes.has(p_class), StringName());
236 return global_classes[p_class].language;
237 }
get_global_class_path(const String & p_class)238 String ScriptServer::get_global_class_path(const String &p_class) {
239 ERR_FAIL_COND_V(!global_classes.has(p_class), String());
240 return global_classes[p_class].path;
241 }
242
get_global_class_base(const String & p_class)243 StringName ScriptServer::get_global_class_base(const String &p_class) {
244 ERR_FAIL_COND_V(!global_classes.has(p_class), String());
245 return global_classes[p_class].base;
246 }
get_global_class_native_base(const String & p_class)247 StringName ScriptServer::get_global_class_native_base(const String &p_class) {
248 ERR_FAIL_COND_V(!global_classes.has(p_class), String());
249 String base = global_classes[p_class].base;
250 while (global_classes.has(base)) {
251 base = global_classes[base].base;
252 }
253 return base;
254 }
get_global_class_list(List<StringName> * r_global_classes)255 void ScriptServer::get_global_class_list(List<StringName> *r_global_classes) {
256 const StringName *K = NULL;
257 List<StringName> classes;
258 while ((K = global_classes.next(K))) {
259 classes.push_back(*K);
260 }
261 classes.sort_custom<StringName::AlphCompare>();
262 for (List<StringName>::Element *E = classes.front(); E; E = E->next()) {
263 r_global_classes->push_back(E->get());
264 }
265 }
save_global_classes()266 void ScriptServer::save_global_classes() {
267 List<StringName> gc;
268 get_global_class_list(&gc);
269 Array gcarr;
270 for (List<StringName>::Element *E = gc.front(); E; E = E->next()) {
271 Dictionary d;
272 d["class"] = E->get();
273 d["language"] = global_classes[E->get()].language;
274 d["path"] = global_classes[E->get()].path;
275 d["base"] = global_classes[E->get()].base;
276 gcarr.push_back(d);
277 }
278
279 ProjectSettings::get_singleton()->set("_global_script_classes", gcarr);
280 ProjectSettings::get_singleton()->save();
281 }
282
283 ////////////////////
get_property_state(List<Pair<StringName,Variant>> & state)284 void ScriptInstance::get_property_state(List<Pair<StringName, Variant> > &state) {
285
286 List<PropertyInfo> pinfo;
287 get_property_list(&pinfo);
288 for (List<PropertyInfo>::Element *E = pinfo.front(); E; E = E->next()) {
289
290 if (E->get().usage & PROPERTY_USAGE_STORAGE) {
291 Pair<StringName, Variant> p;
292 p.first = E->get().name;
293 if (get(p.first, p.second))
294 state.push_back(p);
295 }
296 }
297 }
298
call(const StringName & p_method,VARIANT_ARG_DECLARE)299 Variant ScriptInstance::call(const StringName &p_method, VARIANT_ARG_DECLARE) {
300
301 VARIANT_ARGPTRS;
302 int argc = 0;
303 for (int i = 0; i < VARIANT_ARG_MAX; i++) {
304 if (argptr[i]->get_type() == Variant::NIL)
305 break;
306 argc++;
307 }
308
309 Variant::CallError error;
310 return call(p_method, argptr, argc, error);
311 }
312
call_multilevel(const StringName & p_method,const Variant ** p_args,int p_argcount)313 void ScriptInstance::call_multilevel(const StringName &p_method, const Variant **p_args, int p_argcount) {
314 Variant::CallError ce;
315 call(p_method, p_args, p_argcount, ce); // script may not support multilevel calls
316 }
317
call_multilevel_reversed(const StringName & p_method,const Variant ** p_args,int p_argcount)318 void ScriptInstance::call_multilevel_reversed(const StringName &p_method, const Variant **p_args, int p_argcount) {
319 Variant::CallError ce;
320 call(p_method, p_args, p_argcount, ce); // script may not support multilevel calls
321 }
322
property_set_fallback(const StringName &,const Variant &,bool * r_valid)323 void ScriptInstance::property_set_fallback(const StringName &, const Variant &, bool *r_valid) {
324 if (r_valid)
325 *r_valid = false;
326 }
327
property_get_fallback(const StringName &,bool * r_valid)328 Variant ScriptInstance::property_get_fallback(const StringName &, bool *r_valid) {
329 if (r_valid)
330 *r_valid = false;
331 return Variant();
332 }
333
call_multilevel(const StringName & p_method,VARIANT_ARG_DECLARE)334 void ScriptInstance::call_multilevel(const StringName &p_method, VARIANT_ARG_DECLARE) {
335
336 VARIANT_ARGPTRS;
337 int argc = 0;
338 for (int i = 0; i < VARIANT_ARG_MAX; i++) {
339 if (argptr[i]->get_type() == Variant::NIL)
340 break;
341 argc++;
342 }
343
344 call_multilevel(p_method, argptr, argc);
345 }
346
~ScriptInstance()347 ScriptInstance::~ScriptInstance() {
348 }
349
350 ScriptCodeCompletionCache *ScriptCodeCompletionCache::singleton = NULL;
ScriptCodeCompletionCache()351 ScriptCodeCompletionCache::ScriptCodeCompletionCache() {
352 singleton = this;
353 }
354
frame()355 void ScriptLanguage::frame() {
356 }
357
358 ScriptDebugger *ScriptDebugger::singleton = NULL;
359
set_lines_left(int p_left)360 void ScriptDebugger::set_lines_left(int p_left) {
361
362 lines_left = p_left;
363 }
364
get_lines_left() const365 int ScriptDebugger::get_lines_left() const {
366
367 return lines_left;
368 }
369
set_depth(int p_depth)370 void ScriptDebugger::set_depth(int p_depth) {
371
372 depth = p_depth;
373 }
374
get_depth() const375 int ScriptDebugger::get_depth() const {
376
377 return depth;
378 }
379
insert_breakpoint(int p_line,const StringName & p_source)380 void ScriptDebugger::insert_breakpoint(int p_line, const StringName &p_source) {
381
382 if (!breakpoints.has(p_line))
383 breakpoints[p_line] = Set<StringName>();
384 breakpoints[p_line].insert(p_source);
385 }
386
remove_breakpoint(int p_line,const StringName & p_source)387 void ScriptDebugger::remove_breakpoint(int p_line, const StringName &p_source) {
388
389 if (!breakpoints.has(p_line))
390 return;
391
392 breakpoints[p_line].erase(p_source);
393 if (breakpoints[p_line].size() == 0)
394 breakpoints.erase(p_line);
395 }
is_breakpoint(int p_line,const StringName & p_source) const396 bool ScriptDebugger::is_breakpoint(int p_line, const StringName &p_source) const {
397
398 if (!breakpoints.has(p_line))
399 return false;
400 return breakpoints[p_line].has(p_source);
401 }
is_breakpoint_line(int p_line) const402 bool ScriptDebugger::is_breakpoint_line(int p_line) const {
403
404 return breakpoints.has(p_line);
405 }
406
breakpoint_find_source(const String & p_source) const407 String ScriptDebugger::breakpoint_find_source(const String &p_source) const {
408
409 return p_source;
410 }
411
clear_breakpoints()412 void ScriptDebugger::clear_breakpoints() {
413
414 breakpoints.clear();
415 }
416
idle_poll()417 void ScriptDebugger::idle_poll() {
418 }
419
line_poll()420 void ScriptDebugger::line_poll() {
421 }
422
set_break_language(ScriptLanguage * p_lang)423 void ScriptDebugger::set_break_language(ScriptLanguage *p_lang) {
424
425 break_lang = p_lang;
426 }
427
get_break_language() const428 ScriptLanguage *ScriptDebugger::get_break_language() const {
429
430 return break_lang;
431 }
432
ScriptDebugger()433 ScriptDebugger::ScriptDebugger() {
434
435 singleton = this;
436 lines_left = -1;
437 depth = -1;
438 break_lang = NULL;
439 }
440
set(const StringName & p_name,const Variant & p_value)441 bool PlaceHolderScriptInstance::set(const StringName &p_name, const Variant &p_value) {
442
443 if (script->is_placeholder_fallback_enabled())
444 return false;
445
446 if (values.has(p_name)) {
447 Variant defval;
448 if (script->get_property_default_value(p_name, defval)) {
449 if (defval == p_value) {
450 values.erase(p_name);
451 return true;
452 }
453 }
454 values[p_name] = p_value;
455 return true;
456 } else {
457 Variant defval;
458 if (script->get_property_default_value(p_name, defval)) {
459 if (defval != p_value) {
460 values[p_name] = p_value;
461 }
462 return true;
463 }
464 }
465 return false;
466 }
get(const StringName & p_name,Variant & r_ret) const467 bool PlaceHolderScriptInstance::get(const StringName &p_name, Variant &r_ret) const {
468
469 if (values.has(p_name)) {
470 r_ret = values[p_name];
471 return true;
472 }
473
474 if (constants.has(p_name)) {
475 r_ret = constants[p_name];
476 return true;
477 }
478
479 if (!script->is_placeholder_fallback_enabled()) {
480 Variant defval;
481 if (script->get_property_default_value(p_name, defval)) {
482 r_ret = defval;
483 return true;
484 }
485 }
486
487 return false;
488 }
489
get_property_list(List<PropertyInfo> * p_properties) const490 void PlaceHolderScriptInstance::get_property_list(List<PropertyInfo> *p_properties) const {
491
492 if (script->is_placeholder_fallback_enabled()) {
493 for (const List<PropertyInfo>::Element *E = properties.front(); E; E = E->next()) {
494 p_properties->push_back(E->get());
495 }
496 } else {
497 for (const List<PropertyInfo>::Element *E = properties.front(); E; E = E->next()) {
498 PropertyInfo pinfo = E->get();
499 if (!values.has(pinfo.name)) {
500 pinfo.usage |= PROPERTY_USAGE_SCRIPT_DEFAULT_VALUE;
501 }
502 p_properties->push_back(E->get());
503 }
504 }
505 }
506
get_property_type(const StringName & p_name,bool * r_is_valid) const507 Variant::Type PlaceHolderScriptInstance::get_property_type(const StringName &p_name, bool *r_is_valid) const {
508
509 if (values.has(p_name)) {
510 if (r_is_valid)
511 *r_is_valid = true;
512 return values[p_name].get_type();
513 }
514
515 if (constants.has(p_name)) {
516 if (r_is_valid)
517 *r_is_valid = true;
518 return constants[p_name].get_type();
519 }
520
521 if (r_is_valid)
522 *r_is_valid = false;
523
524 return Variant::NIL;
525 }
526
get_method_list(List<MethodInfo> * p_list) const527 void PlaceHolderScriptInstance::get_method_list(List<MethodInfo> *p_list) const {
528
529 if (script->is_placeholder_fallback_enabled())
530 return;
531
532 if (script.is_valid()) {
533 script->get_script_method_list(p_list);
534 }
535 }
has_method(const StringName & p_method) const536 bool PlaceHolderScriptInstance::has_method(const StringName &p_method) const {
537
538 if (script->is_placeholder_fallback_enabled())
539 return false;
540
541 if (script.is_valid()) {
542 return script->has_method(p_method);
543 }
544 return false;
545 }
546
update(const List<PropertyInfo> & p_properties,const Map<StringName,Variant> & p_values)547 void PlaceHolderScriptInstance::update(const List<PropertyInfo> &p_properties, const Map<StringName, Variant> &p_values) {
548
549 Set<StringName> new_values;
550 for (const List<PropertyInfo>::Element *E = p_properties.front(); E; E = E->next()) {
551
552 StringName n = E->get().name;
553 new_values.insert(n);
554
555 if (!values.has(n) || values[n].get_type() != E->get().type) {
556
557 if (p_values.has(n))
558 values[n] = p_values[n];
559 }
560 }
561
562 properties = p_properties;
563 List<StringName> to_remove;
564
565 for (Map<StringName, Variant>::Element *E = values.front(); E; E = E->next()) {
566
567 if (!new_values.has(E->key()))
568 to_remove.push_back(E->key());
569
570 Variant defval;
571 if (script->get_property_default_value(E->key(), defval)) {
572 //remove because it's the same as the default value
573 if (defval == E->get()) {
574 to_remove.push_back(E->key());
575 }
576 }
577 }
578
579 while (to_remove.size()) {
580
581 values.erase(to_remove.front()->get());
582 to_remove.pop_front();
583 }
584
585 if (owner && owner->get_script_instance() == this) {
586
587 owner->_change_notify();
588 }
589 //change notify
590
591 constants.clear();
592 script->get_constants(&constants);
593 }
594
property_set_fallback(const StringName & p_name,const Variant & p_value,bool * r_valid)595 void PlaceHolderScriptInstance::property_set_fallback(const StringName &p_name, const Variant &p_value, bool *r_valid) {
596
597 if (script->is_placeholder_fallback_enabled()) {
598 Map<StringName, Variant>::Element *E = values.find(p_name);
599
600 if (E) {
601 E->value() = p_value;
602 } else {
603 values.insert(p_name, p_value);
604 }
605
606 bool found = false;
607 for (const List<PropertyInfo>::Element *F = properties.front(); F; F = F->next()) {
608 if (F->get().name == p_name) {
609 found = true;
610 break;
611 }
612 }
613 if (!found) {
614 properties.push_back(PropertyInfo(p_value.get_type(), p_name, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_SCRIPT_VARIABLE));
615 }
616 }
617
618 if (r_valid)
619 *r_valid = false; // Cannot change the value in either case
620 }
621
property_get_fallback(const StringName & p_name,bool * r_valid)622 Variant PlaceHolderScriptInstance::property_get_fallback(const StringName &p_name, bool *r_valid) {
623
624 if (script->is_placeholder_fallback_enabled()) {
625 const Map<StringName, Variant>::Element *E = values.find(p_name);
626
627 if (E) {
628 if (r_valid)
629 *r_valid = true;
630 return E->value();
631 }
632
633 E = constants.find(p_name);
634 if (E) {
635 if (r_valid)
636 *r_valid = true;
637 return E->value();
638 }
639 }
640
641 if (r_valid)
642 *r_valid = false;
643
644 return Variant();
645 }
646
PlaceHolderScriptInstance(ScriptLanguage * p_language,Ref<Script> p_script,Object * p_owner)647 PlaceHolderScriptInstance::PlaceHolderScriptInstance(ScriptLanguage *p_language, Ref<Script> p_script, Object *p_owner) :
648 owner(p_owner),
649 language(p_language),
650 script(p_script) {
651 }
652
~PlaceHolderScriptInstance()653 PlaceHolderScriptInstance::~PlaceHolderScriptInstance() {
654
655 if (script.is_valid()) {
656 script->_placeholder_erased(this);
657 }
658 }
659