/*************************************************************************/ /* script_language.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ /* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ /* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ /* "Software"), to deal in the Software without restriction, including */ /* without limitation the rights to use, copy, modify, merge, publish, */ /* distribute, sublicense, and/or sell copies of the Software, and to */ /* permit persons to whom the Software is furnished to do so, subject to */ /* the following conditions: */ /* */ /* The above copyright notice and this permission notice shall be */ /* included in all copies or substantial portions of the Software. */ /* */ /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "script_language.h" #include "core/config/project_settings.h" #include "core/core_string_names.h" #include "core/io/resource_loader.h" ScriptLanguage *ScriptServer::_languages[MAX_LANGUAGES]; int ScriptServer::_language_count = 0; bool ScriptServer::scripting_enabled = true; bool ScriptServer::reload_scripts_on_save = false; bool ScriptServer::languages_finished = false; ScriptEditRequestFunction ScriptServer::edit_request_func = nullptr; void Script::_notification(int p_what) { if (p_what == NOTIFICATION_POSTINITIALIZE) { if (ScriptDebugger::get_singleton()) { ScriptDebugger::get_singleton()->set_break_language(get_language()); } } } Variant Script::_get_property_default_value(const StringName &p_property) { Variant ret; get_property_default_value(p_property, ret); return ret; } Array Script::_get_script_property_list() { Array ret; List list; get_script_property_list(&list); for (List::Element *E = list.front(); E; E = E->next()) { ret.append(E->get().operator Dictionary()); } return ret; } Array Script::_get_script_method_list() { Array ret; List list; get_script_method_list(&list); for (List::Element *E = list.front(); E; E = E->next()) { ret.append(E->get().operator Dictionary()); } return ret; } Array Script::_get_script_signal_list() { Array ret; List list; get_script_signal_list(&list); for (List::Element *E = list.front(); E; E = E->next()) { ret.append(E->get().operator Dictionary()); } return ret; } Dictionary Script::_get_script_constant_map() { Dictionary ret; RBMap map; get_constants(&map); for (RBMap::Element *E = map.front(); E; E = E->next()) { ret[E->key()] = E->value(); } return ret; } void Script::_bind_methods() { ClassDB::bind_method(D_METHOD("can_instance"), &Script::can_instance); //ClassDB::bind_method(D_METHOD("instance_create","base_object"),&Script::instance_create); ClassDB::bind_method(D_METHOD("instance_has", "base_object"), &Script::instance_has); ClassDB::bind_method(D_METHOD("has_source_code"), &Script::has_source_code); ClassDB::bind_method(D_METHOD("get_source_code"), &Script::get_source_code); ClassDB::bind_method(D_METHOD("set_source_code", "source"), &Script::set_source_code); ClassDB::bind_method(D_METHOD("reload", "keep_state"), &Script::reload, DEFVAL(false)); ClassDB::bind_method(D_METHOD("get_base_script"), &Script::get_base_script); ClassDB::bind_method(D_METHOD("get_instance_base_type"), &Script::get_instance_base_type); ClassDB::bind_method(D_METHOD("has_script_signal", "signal_name"), &Script::has_script_signal); ClassDB::bind_method(D_METHOD("get_script_property_list"), &Script::_get_script_property_list); ClassDB::bind_method(D_METHOD("get_script_method_list"), &Script::_get_script_method_list); ClassDB::bind_method(D_METHOD("get_script_signal_list"), &Script::_get_script_signal_list); ClassDB::bind_method(D_METHOD("get_script_constant_map"), &Script::_get_script_constant_map); ClassDB::bind_method(D_METHOD("get_property_default_value", "property"), &Script::_get_property_default_value); ClassDB::bind_method(D_METHOD("is_tool"), &Script::is_tool); ADD_PROPERTY(PropertyInfo(Variant::STRING, "source_code", PROPERTY_HINT_NONE, "", 0), "set_source_code", "get_source_code"); } void ScriptServer::set_scripting_enabled(bool p_enabled) { scripting_enabled = p_enabled; } bool ScriptServer::is_scripting_enabled() { return scripting_enabled; } ScriptLanguage *ScriptServer::get_language(int p_idx) { ERR_FAIL_INDEX_V(p_idx, _language_count, nullptr); return _languages[p_idx]; } void ScriptServer::register_language(ScriptLanguage *p_language) { ERR_FAIL_COND(_language_count >= MAX_LANGUAGES); _languages[_language_count++] = p_language; } void ScriptServer::unregister_language(ScriptLanguage *p_language) { for (int i = 0; i < _language_count; i++) { if (_languages[i] == p_language) { _language_count--; if (i < _language_count) { SWAP(_languages[i], _languages[_language_count]); } return; } } } void ScriptServer::init_languages() { { //load global classes global_classes_clear(); if (ProjectSettings::get_singleton()->has_setting("_global_script_classes")) { Array script_classes = ProjectSettings::get_singleton()->get("_global_script_classes"); for (int i = 0; i < script_classes.size(); i++) { Dictionary c = script_classes[i]; if (!c.has("class") || !c.has("language") || !c.has("path") || !c.has("base")) { continue; } add_global_class(c["class"], c["base"], c["language"], c["path"]); } } } for (int i = 0; i < _language_count; i++) { _languages[i]->init(); } } void ScriptServer::finish_languages() { for (int i = 0; i < _language_count; i++) { _languages[i]->finish(); } global_classes_clear(); languages_finished = true; } void ScriptServer::set_reload_scripts_on_save(bool p_enable) { reload_scripts_on_save = p_enable; } bool ScriptServer::is_reload_scripts_on_save_enabled() { return reload_scripts_on_save; } void ScriptServer::thread_enter() { for (int i = 0; i < _language_count; i++) { _languages[i]->thread_enter(); } } void ScriptServer::thread_exit() { for (int i = 0; i < _language_count; i++) { _languages[i]->thread_exit(); } } HashMap ScriptServer::global_classes; HashMap ScriptServer::global_class_paths; void ScriptServer::global_classes_clear() { global_classes.clear(); global_class_paths.clear(); } void ScriptServer::add_global_class(const StringName &p_class, const StringName &p_base, const StringName &p_language, const String &p_path) { 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."); ERR_FAIL_COND_MSG(p_class == StringName(), vformat("Attempted to register global script class at path '%s' without a class name.", p_path)); ERR_FAIL_COND_MSG(p_base == StringName(), vformat("Attempted to register global script class at path '%s' without a base name.", p_path)); ERR_FAIL_COND_MSG(p_language == StringName(), vformat("Attempted to register global script class at path '%s' without a language name.", p_path)); ERR_FAIL_COND_MSG(p_path.empty(), vformat("Attempted to register global script class named '%s' with an empty path.", p_class)); GlobalScriptClass g; g.language = p_language; g.path = p_path; g.base = p_base; global_classes[p_class] = g; global_class_paths[p_path] = p_class; } void ScriptServer::remove_global_class(const StringName &p_class) { global_class_paths.erase(global_classes[p_class].path); global_classes.erase(p_class); } bool ScriptServer::is_global_class(const StringName &p_class) { return global_classes.has(p_class); } StringName ScriptServer::get_global_class_language(const StringName &p_class) { ERR_FAIL_COND_V(!global_classes.has(p_class), StringName()); return global_classes[p_class].language; } String ScriptServer::get_global_class_path(const StringName &p_class) { ERR_FAIL_COND_V(!global_classes.has(p_class), String()); return global_classes[p_class].path; } StringName ScriptServer::get_global_class_name(const String &p_path) { if (global_class_paths.has(p_path)) { return global_class_paths[p_path]; } return StringName(); } StringName ScriptServer::get_global_class_base(const StringName &p_class) { ERR_FAIL_COND_V(!global_classes.has(p_class), StringName()); return global_classes[p_class].base; } StringName ScriptServer::get_global_class_native_base(const StringName &p_class) { ERR_FAIL_COND_V(!global_classes.has(p_class), StringName()); String base = global_classes[p_class].base; while (global_classes.has(base)) { base = global_classes[base].base; } return base; } Ref