diff options
author | Rémi Verschelde <rverschelde@gmail.com> | 2017-11-16 18:38:18 +0100 |
---|---|---|
committer | Rémi Verschelde <rverschelde@gmail.com> | 2017-11-16 18:54:56 +0100 |
commit | 4cfc29611e21811065d024a6de1685418e60111e (patch) | |
tree | 3d2b10ebd4d18b88709a49391cf6265185149d56 /modules/gdscript/gd_script.cpp | |
parent | 2070b80fc05d581fc8f44ba231fc728136877828 (diff) | |
download | redot-engine-4cfc29611e21811065d024a6de1685418e60111e.tar.gz |
GDScript: Refactor "GD" class prefix to "GDScript"
Diffstat (limited to 'modules/gdscript/gd_script.cpp')
-rw-r--r-- | modules/gdscript/gd_script.cpp | 1911 |
1 files changed, 0 insertions, 1911 deletions
diff --git a/modules/gdscript/gd_script.cpp b/modules/gdscript/gd_script.cpp deleted file mode 100644 index e5d834c9e7..0000000000 --- a/modules/gdscript/gd_script.cpp +++ /dev/null @@ -1,1911 +0,0 @@ -/*************************************************************************/ -/* gd_script.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2017 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 "gd_script.h" - -#include "engine.h" -#include "gd_compiler.h" -#include "global_constants.h" -#include "io/file_access_encrypted.h" -#include "os/file_access.h" -#include "os/os.h" -#include "project_settings.h" - -/////////////////////////// - -GDNativeClass::GDNativeClass(const StringName &p_name) { - - name = p_name; -} - -bool GDNativeClass::_get(const StringName &p_name, Variant &r_ret) const { - - bool ok; - int v = ClassDB::get_integer_constant(name, p_name, &ok); - - if (ok) { - r_ret = v; - return true; - } else { - return false; - } -} - -void GDNativeClass::_bind_methods() { - - ClassDB::bind_method(D_METHOD("new"), &GDNativeClass::_new); -} - -Variant GDNativeClass::_new() { - - Object *o = instance(); - if (!o) { - ERR_EXPLAIN("Class type: '" + String(name) + "' is not instantiable."); - ERR_FAIL_COND_V(!o, Variant()); - } - - Reference *ref = Object::cast_to<Reference>(o); - if (ref) { - return REF(ref); - } else { - return o; - } -} - -Object *GDNativeClass::instance() { - - return ClassDB::instance(name); -} - -GDInstance *GDScript::_create_instance(const Variant **p_args, int p_argcount, Object *p_owner, bool p_isref, Variant::CallError &r_error) { - - /* STEP 1, CREATE */ - - GDInstance *instance = memnew(GDInstance); - instance->base_ref = p_isref; - instance->members.resize(member_indices.size()); - instance->script = Ref<GDScript>(this); - instance->owner = p_owner; -#ifdef DEBUG_ENABLED - //needed for hot reloading - for (Map<StringName, MemberInfo>::Element *E = member_indices.front(); E; E = E->next()) { - instance->member_indices_cache[E->key()] = E->get().index; - } -#endif - instance->owner->set_script_instance(instance); - -/* STEP 2, INITIALIZE AND CONSRTUCT */ - -#ifndef NO_THREADS - GDScriptLanguage::singleton->lock->lock(); -#endif - - instances.insert(instance->owner); - -#ifndef NO_THREADS - GDScriptLanguage::singleton->lock->unlock(); -#endif - - initializer->call(instance, p_args, p_argcount, r_error); - - if (r_error.error != Variant::CallError::CALL_OK) { - instance->script = Ref<GDScript>(); - instance->owner->set_script_instance(NULL); -#ifndef NO_THREADS - GDScriptLanguage::singleton->lock->lock(); -#endif - instances.erase(p_owner); -#ifndef NO_THREADS - GDScriptLanguage::singleton->lock->unlock(); -#endif - - ERR_FAIL_COND_V(r_error.error != Variant::CallError::CALL_OK, NULL); //error constructing - } - - //@TODO make thread safe - return instance; -} - -Variant GDScript::_new(const Variant **p_args, int p_argcount, Variant::CallError &r_error) { - - /* STEP 1, CREATE */ - - if (!valid) { - r_error.error = Variant::CallError::CALL_ERROR_INVALID_METHOD; - return Variant(); - } - - r_error.error = Variant::CallError::CALL_OK; - REF ref; - Object *owner = NULL; - - GDScript *_baseptr = this; - while (_baseptr->_base) { - _baseptr = _baseptr->_base; - } - - ERR_FAIL_COND_V(_baseptr->native.is_null(), Variant()); - - if (_baseptr->native.ptr()) { - owner = _baseptr->native->instance(); - } else { - owner = memnew(Reference); //by default, no base means use reference - } - - Reference *r = Object::cast_to<Reference>(owner); - if (r) { - ref = REF(r); - } - - GDInstance *instance = _create_instance(p_args, p_argcount, owner, r != NULL, r_error); - if (!instance) { - if (ref.is_null()) { - memdelete(owner); //no owner, sorry - } - return Variant(); - } - - if (ref.is_valid()) { - return ref; - } else { - return owner; - } -} - -bool GDScript::can_instance() const { - - return valid || (!tool && !ScriptServer::is_scripting_enabled()); -} - -Ref<Script> GDScript::get_base_script() const { - - if (_base) { - return Ref<GDScript>(_base); - } else { - return Ref<Script>(); - } -} - -StringName GDScript::get_instance_base_type() const { - - if (native.is_valid()) - return native->get_name(); - if (base.is_valid()) - return base->get_instance_base_type(); - return StringName(); -} - -struct _GDScriptMemberSort { - - int index; - StringName name; - _FORCE_INLINE_ bool operator<(const _GDScriptMemberSort &p_member) const { return index < p_member.index; } -}; - -#ifdef TOOLS_ENABLED - -void GDScript::_placeholder_erased(PlaceHolderScriptInstance *p_placeholder) { - - placeholders.erase(p_placeholder); -} -#endif - -void GDScript::get_script_method_list(List<MethodInfo> *p_list) const { - - for (const Map<StringName, GDFunction *>::Element *E = member_functions.front(); E; E = E->next()) { - MethodInfo mi; - mi.name = E->key(); - for (int i = 0; i < E->get()->get_argument_count(); i++) { - PropertyInfo arg; - arg.type = Variant::NIL; //variant - arg.name = E->get()->get_argument_name(i); - mi.arguments.push_back(arg); - } - - mi.return_val.name = "Variant"; - p_list->push_back(mi); - } -} - -void GDScript::get_script_property_list(List<PropertyInfo> *p_list) const { - - const GDScript *sptr = this; - List<PropertyInfo> props; - - while (sptr) { - - Vector<_GDScriptMemberSort> msort; - for (Map<StringName, PropertyInfo>::Element *E = sptr->member_info.front(); E; E = E->next()) { - - _GDScriptMemberSort ms; - ERR_CONTINUE(!sptr->member_indices.has(E->key())); - ms.index = sptr->member_indices[E->key()].index; - ms.name = E->key(); - msort.push_back(ms); - } - - msort.sort(); - msort.invert(); - for (int i = 0; i < msort.size(); i++) { - - props.push_front(sptr->member_info[msort[i].name]); - } - - sptr = sptr->_base; - } - - for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) { - p_list->push_back(E->get()); - } -} - -bool GDScript::has_method(const StringName &p_method) const { - - return member_functions.has(p_method); -} - -MethodInfo GDScript::get_method_info(const StringName &p_method) const { - - const Map<StringName, GDFunction *>::Element *E = member_functions.find(p_method); - if (!E) - return MethodInfo(); - - MethodInfo mi; - mi.name = E->key(); - for (int i = 0; i < E->get()->get_argument_count(); i++) { - PropertyInfo arg; - arg.type = Variant::NIL; //variant - arg.name = E->get()->get_argument_name(i); - mi.arguments.push_back(arg); - } - - mi.return_val.name = "Variant"; - return mi; -} - -bool GDScript::get_property_default_value(const StringName &p_property, Variant &r_value) const { - -#ifdef TOOLS_ENABLED - - /* - for (const Map<StringName,Variant>::Element *I=member_default_values.front();I;I=I->next()) { - print_line("\t"+String(String(I->key())+":"+String(I->get()))); - } - */ - const Map<StringName, Variant>::Element *E = member_default_values_cache.find(p_property); - if (E) { - r_value = E->get(); - return true; - } - - if (base_cache.is_valid()) { - return base_cache->get_property_default_value(p_property, r_value); - } -#endif - return false; -} - -ScriptInstance *GDScript::instance_create(Object *p_this) { - - if (!tool && !ScriptServer::is_scripting_enabled()) { - -#ifdef TOOLS_ENABLED - - //instance a fake script for editing the values - //plist.invert(); - - /*print_line("CREATING PLACEHOLDER"); - for(List<PropertyInfo>::Element *E=plist.front();E;E=E->next()) { - print_line(E->get().name); - }*/ - PlaceHolderScriptInstance *si = memnew(PlaceHolderScriptInstance(GDScriptLanguage::get_singleton(), Ref<Script>(this), p_this)); - placeholders.insert(si); - //_update_placeholder(si); - _update_exports(); - return si; -#else - return NULL; -#endif - } - - GDScript *top = this; - while (top->_base) - top = top->_base; - - if (top->native.is_valid()) { - if (!ClassDB::is_parent_class(p_this->get_class_name(), top->native->get_name())) { - - if (ScriptDebugger::get_singleton()) { - 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_class() + "'"); - } - 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_class() + "'"); - ERR_FAIL_V(NULL); - } - } - - Variant::CallError unchecked_error; - return _create_instance(NULL, 0, p_this, Object::cast_to<Reference>(p_this), unchecked_error); -} -bool GDScript::instance_has(const Object *p_this) const { - -#ifndef NO_THREADS - GDScriptLanguage::singleton->lock->lock(); -#endif - bool hasit = instances.has((Object *)p_this); - -#ifndef NO_THREADS - GDScriptLanguage::singleton->lock->unlock(); -#endif - - return hasit; -} - -bool GDScript::has_source_code() const { - - return source != ""; -} -String GDScript::get_source_code() const { - - return source; -} -void GDScript::set_source_code(const String &p_code) { - - if (source == p_code) - return; - source = p_code; -#ifdef TOOLS_ENABLED - source_changed_cache = true; -#endif -} - -#ifdef TOOLS_ENABLED -void GDScript::_update_exports_values(Map<StringName, Variant> &values, List<PropertyInfo> &propnames) { - - if (base_cache.is_valid()) { - base_cache->_update_exports_values(values, propnames); - } - - for (Map<StringName, Variant>::Element *E = member_default_values_cache.front(); E; E = E->next()) { - values[E->key()] = E->get(); - } - - for (List<PropertyInfo>::Element *E = members_cache.front(); E; E = E->next()) { - propnames.push_back(E->get()); - } -} -#endif - -bool GDScript::_update_exports() { - -#ifdef TOOLS_ENABLED - - bool changed = false; - - if (source_changed_cache) { - //print_line("updating source for "+get_path()); - source_changed_cache = false; - changed = true; - - String basedir = path; - - if (basedir == "") - basedir = get_path(); - - if (basedir != "") - basedir = basedir.get_base_dir(); - - GDParser parser; - Error err = parser.parse(source, basedir, true, path); - - if (err == OK) { - - const GDParser::Node *root = parser.get_parse_tree(); - ERR_FAIL_COND_V(root->type != GDParser::Node::TYPE_CLASS, false); - - const GDParser::ClassNode *c = static_cast<const GDParser::ClassNode *>(root); - - if (base_cache.is_valid()) { - base_cache->inheriters_cache.erase(get_instance_id()); - base_cache = Ref<GDScript>(); - } - - if (c->extends_used && String(c->extends_file) != "" && String(c->extends_file) != get_path()) { - - String path = c->extends_file; - if (path.is_rel_path()) { - - String base = get_path(); - if (base == "" || base.is_rel_path()) { - - ERR_PRINT(("Could not resolve relative path for parent class: " + path).utf8().get_data()); - } else { - path = base.get_base_dir().plus_file(path); - } - } - - if (path != get_path()) { - - Ref<GDScript> bf = ResourceLoader::load(path); - - if (bf.is_valid()) { - - //print_line("parent is: "+bf->get_path()); - base_cache = bf; - bf->inheriters_cache.insert(get_instance_id()); - - //bf->_update_exports(p_instances,true,false); - } - } else { - ERR_PRINT(("Path extending itself in " + path).utf8().get_data()); - } - } - - members_cache.clear(); - member_default_values_cache.clear(); - - for (int i = 0; i < c->variables.size(); i++) { - if (c->variables[i]._export.type == Variant::NIL) - continue; - - members_cache.push_back(c->variables[i]._export); - //print_line("found "+c->variables[i]._export.name); - member_default_values_cache[c->variables[i].identifier] = c->variables[i].default_value; - } - - _signals.clear(); - - for (int i = 0; i < c->_signals.size(); i++) { - _signals[c->_signals[i].name] = c->_signals[i].arguments; - } - } - } else { - //print_line("unchanged is "+get_path()); - } - - if (base_cache.is_valid()) { - if (base_cache->_update_exports()) { - changed = true; - } - } - - if (/*changed &&*/ placeholders.size()) { //hm :( - - //print_line("updating placeholders for "+get_path()); - - //update placeholders if any - Map<StringName, Variant> values; - List<PropertyInfo> propnames; - _update_exports_values(values, propnames); - - for (Set<PlaceHolderScriptInstance *>::Element *E = placeholders.front(); E; E = E->next()) { - - E->get()->update(propnames, values); - } - } - - return changed; - -#else - return false; -#endif -} - -void GDScript::update_exports() { - -#ifdef TOOLS_ENABLED - - _update_exports(); - - Set<ObjectID> copy = inheriters_cache; //might get modified - - //print_line("update exports for "+get_path()+" ic: "+itos(copy.size())); - for (Set<ObjectID>::Element *E = copy.front(); E; E = E->next()) { - Object *id = ObjectDB::get_instance(E->get()); - GDScript *s = Object::cast_to<GDScript>(id); - if (!s) - continue; - s->update_exports(); - } - -#endif -} - -void GDScript::_set_subclass_path(Ref<GDScript> &p_sc, const String &p_path) { - - p_sc->path = p_path; - for (Map<StringName, Ref<GDScript> >::Element *E = p_sc->subclasses.front(); E; E = E->next()) { - - _set_subclass_path(E->get(), p_path); - } -} - -Error GDScript::reload(bool p_keep_state) { - -#ifndef NO_THREADS - GDScriptLanguage::singleton->lock->lock(); -#endif - bool has_instances = instances.size(); - -#ifndef NO_THREADS - GDScriptLanguage::singleton->lock->unlock(); -#endif - - ERR_FAIL_COND_V(!p_keep_state && has_instances, ERR_ALREADY_IN_USE); - - String basedir = path; - - if (basedir == "") - basedir = get_path(); - - if (basedir != "") - basedir = basedir.get_base_dir(); - - if (source.find("%BASE%") != -1) { - //loading a template, don't parse - return OK; - } - - valid = false; - GDParser parser; - Error err = parser.parse(source, basedir, false, path); - if (err) { - if (ScriptDebugger::get_singleton()) { - GDScriptLanguage::get_singleton()->debug_break_parse(get_path(), parser.get_error_line(), "Parser Error: " + parser.get_error()); - } - _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); - ERR_FAIL_V(ERR_PARSE_ERROR); - } - - bool can_run = ScriptServer::is_scripting_enabled() || parser.is_tool_script(); - - GDCompiler compiler; - err = compiler.compile(&parser, this, p_keep_state); - - if (err) { - - if (can_run) { - if (ScriptDebugger::get_singleton()) { - GDScriptLanguage::get_singleton()->debug_break_parse(get_path(), compiler.get_error_line(), "Parser Error: " + compiler.get_error()); - } - _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); - ERR_FAIL_V(ERR_COMPILATION_FAILED); - } else { - return err; - } - } - - valid = true; - - for (Map<StringName, Ref<GDScript> >::Element *E = subclasses.front(); E; E = E->next()) { - - _set_subclass_path(E->get(), path); - } - - return OK; -} - -ScriptLanguage *GDScript::get_language() const { - - return GDScriptLanguage::get_singleton(); -} - -Variant GDScript::call(const StringName &p_method, const Variant **p_args, int p_argcount, Variant::CallError &r_error) { - - GDScript *top = this; - while (top) { - - Map<StringName, GDFunction *>::Element *E = top->member_functions.find(p_method); - if (E) { - - if (!E->get()->is_static()) { - WARN_PRINT(String("Can't call non-static function: '" + String(p_method) + "' in script.").utf8().get_data()); - } - - return E->get()->call(NULL, p_args, p_argcount, r_error); - } - top = top->_base; - } - - //none found, regular - - return Script::call(p_method, p_args, p_argcount, r_error); -} - -bool GDScript::_get(const StringName &p_name, Variant &r_ret) const { - - { - - const GDScript *top = this; - while (top) { - - { - const Map<StringName, Variant>::Element *E = top->constants.find(p_name); - if (E) { - - r_ret = E->get(); - return true; - } - } - - { - const Map<StringName, Ref<GDScript> >::Element *E = subclasses.find(p_name); - if (E) { - - r_ret = E->get(); - return true; - } - } - top = top->_base; - } - - if (p_name == GDScriptLanguage::get_singleton()->strings._script_source) { - - r_ret = get_source_code(); - return true; - } - } - - return false; -} -bool GDScript::_set(const StringName &p_name, const Variant &p_value) { - - if (p_name == GDScriptLanguage::get_singleton()->strings._script_source) { - - set_source_code(p_value); - reload(); - } else - return false; - - return true; -} - -void GDScript::_get_property_list(List<PropertyInfo> *p_properties) const { - - p_properties->push_back(PropertyInfo(Variant::STRING, "script/source", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR)); -} - -void GDScript::_bind_methods() { - - ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "new", &GDScript::_new, MethodInfo(Variant::OBJECT, "new")); - - ClassDB::bind_method(D_METHOD("get_as_byte_code"), &GDScript::get_as_byte_code); -} - -Vector<uint8_t> GDScript::get_as_byte_code() const { - - GDTokenizerBuffer tokenizer; - return tokenizer.parse_code_string(source); -}; - -Error GDScript::load_byte_code(const String &p_path) { - - Vector<uint8_t> bytecode; - - if (p_path.ends_with("gde")) { - - FileAccess *fa = FileAccess::open(p_path, FileAccess::READ); - ERR_FAIL_COND_V(!fa, ERR_CANT_OPEN); - FileAccessEncrypted *fae = memnew(FileAccessEncrypted); - ERR_FAIL_COND_V(!fae, ERR_CANT_OPEN); - Vector<uint8_t> key; - key.resize(32); - for (int i = 0; i < key.size(); i++) { - key[i] = script_encryption_key[i]; - } - Error err = fae->open_and_parse(fa, key, FileAccessEncrypted::MODE_READ); - ERR_FAIL_COND_V(err, err); - bytecode.resize(fae->get_len()); - fae->get_buffer(bytecode.ptr(), bytecode.size()); - memdelete(fae); - } else { - - bytecode = FileAccess::get_file_as_array(p_path); - } - ERR_FAIL_COND_V(bytecode.size() == 0, ERR_PARSE_ERROR); - path = p_path; - - String basedir = path; - - if (basedir == "") - basedir = get_path(); - - if (basedir != "") - basedir = basedir.get_base_dir(); - - valid = false; - GDParser parser; - Error err = parser.parse_bytecode(bytecode, basedir, get_path()); - if (err) { - _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); - ERR_FAIL_V(ERR_PARSE_ERROR); - } - - GDCompiler compiler; - err = compiler.compile(&parser, this); - - if (err) { - _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); - ERR_FAIL_V(ERR_COMPILATION_FAILED); - } - - valid = true; - - for (Map<StringName, Ref<GDScript> >::Element *E = subclasses.front(); E; E = E->next()) { - - _set_subclass_path(E->get(), path); - } - - return OK; -} - -Error GDScript::load_source_code(const String &p_path) { - - PoolVector<uint8_t> sourcef; - Error err; - FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err); - if (err) { - - ERR_FAIL_COND_V(err, err); - } - - int len = f->get_len(); - sourcef.resize(len + 1); - PoolVector<uint8_t>::Write w = sourcef.write(); - int r = f->get_buffer(w.ptr(), len); - f->close(); - memdelete(f); - ERR_FAIL_COND_V(r != len, ERR_CANT_OPEN); - w[len] = 0; - - String s; - if (s.parse_utf8((const char *)w.ptr())) { - - 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."); - ERR_FAIL_V(ERR_INVALID_DATA); - } - - source = s; -#ifdef TOOLS_ENABLED - source_changed_cache = true; -#endif - //print_line("LSC :"+get_path()); - path = p_path; - return OK; -} - -const Map<StringName, GDFunction *> &GDScript::debug_get_member_functions() const { - - return member_functions; -} - -StringName GDScript::debug_get_member_by_index(int p_idx) const { - - for (const Map<StringName, MemberInfo>::Element *E = member_indices.front(); E; E = E->next()) { - - if (E->get().index == p_idx) - return E->key(); - } - - return "<error>"; -} - -Ref<GDScript> GDScript::get_base() const { - - return base; -} - -bool GDScript::has_script_signal(const StringName &p_signal) const { - if (_signals.has(p_signal)) - return true; - if (base.is_valid()) { - return base->has_script_signal(p_signal); - } -#ifdef TOOLS_ENABLED - else if (base_cache.is_valid()) { - return base_cache->has_script_signal(p_signal); - } - -#endif - return false; -} -void GDScript::get_script_signal_list(List<MethodInfo> *r_signals) const { - - for (const Map<StringName, Vector<StringName> >::Element *E = _signals.front(); E; E = E->next()) { - - MethodInfo mi; - mi.name = E->key(); - for (int i = 0; i < E->get().size(); i++) { - PropertyInfo arg; - arg.name = E->get()[i]; - mi.arguments.push_back(arg); - } - r_signals->push_back(mi); - } - - if (base.is_valid()) { - base->get_script_signal_list(r_signals); - } -#ifdef TOOLS_ENABLED - else if (base_cache.is_valid()) { - base_cache->get_script_signal_list(r_signals); - } - -#endif -} - -GDScript::GDScript() - : script_list(this) { - - _static_ref = this; - valid = false; - subclass_count = 0; - initializer = NULL; - _base = NULL; - _owner = NULL; - tool = false; -#ifdef TOOLS_ENABLED - source_changed_cache = false; -#endif - -#ifdef DEBUG_ENABLED - if (GDScriptLanguage::get_singleton()->lock) { - GDScriptLanguage::get_singleton()->lock->lock(); - } - GDScriptLanguage::get_singleton()->script_list.add(&script_list); - - if (GDScriptLanguage::get_singleton()->lock) { - GDScriptLanguage::get_singleton()->lock->unlock(); - } -#endif -} - -GDScript::~GDScript() { - for (Map<StringName, GDFunction *>::Element *E = member_functions.front(); E; E = E->next()) { - memdelete(E->get()); - } - - for (Map<StringName, Ref<GDScript> >::Element *E = subclasses.front(); E; E = E->next()) { - E->get()->_owner = NULL; //bye, you are no longer owned cause I died - } - -#ifdef DEBUG_ENABLED - if (GDScriptLanguage::get_singleton()->lock) { - GDScriptLanguage::get_singleton()->lock->lock(); - } - GDScriptLanguage::get_singleton()->script_list.remove(&script_list); - - if (GDScriptLanguage::get_singleton()->lock) { - GDScriptLanguage::get_singleton()->lock->unlock(); - } -#endif -} - -////////////////////////////// -// INSTANCE // -////////////////////////////// - -bool GDInstance::set(const StringName &p_name, const Variant &p_value) { - - //member - { - const Map<StringName, GDScript::MemberInfo>::Element *E = script->member_indices.find(p_name); - if (E) { - if (E->get().setter) { - const Variant *val = &p_value; - Variant::CallError err; - call(E->get().setter, &val, 1, err); - if (err.error == Variant::CallError::CALL_OK) { - return true; //function exists, call was successful - } - } else - members[E->get().index] = p_value; - return true; - } - } - - GDScript *sptr = script.ptr(); - while (sptr) { - - Map<StringName, GDFunction *>::Element *E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._set); - if (E) { - - Variant name = p_name; - const Variant *args[2] = { &name, &p_value }; - - Variant::CallError err; - Variant ret = E->get()->call(this, (const Variant **)args, 2, err); - if (err.error == Variant::CallError::CALL_OK && ret.get_type() == Variant::BOOL && ret.operator bool()) - return true; - } - sptr = sptr->_base; - } - - return false; -} - -bool GDInstance::get(const StringName &p_name, Variant &r_ret) const { - - const GDScript *sptr = script.ptr(); - while (sptr) { - - { - const Map<StringName, GDScript::MemberInfo>::Element *E = script->member_indices.find(p_name); - if (E) { - if (E->get().getter) { - Variant::CallError err; - r_ret = const_cast<GDInstance *>(this)->call(E->get().getter, NULL, 0, err); - if (err.error == Variant::CallError::CALL_OK) { - return true; - } - } - r_ret = members[E->get().index]; - return true; //index found - } - } - - { - - const GDScript *sl = sptr; - while (sl) { - const Map<StringName, Variant>::Element *E = sl->constants.find(p_name); - if (E) { - r_ret = E->get(); - return true; //index found - } - sl = sl->_base; - } - } - - { - const Map<StringName, GDFunction *>::Element *E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._get); - if (E) { - - Variant name = p_name; - const Variant *args[1] = { &name }; - - Variant::CallError err; - Variant ret = const_cast<GDFunction *>(E->get())->call(const_cast<GDInstance *>(this), (const Variant **)args, 1, err); - if (err.error == Variant::CallError::CALL_OK && ret.get_type() != Variant::NIL) { - r_ret = ret; - return true; - } - } - } - sptr = sptr->_base; - } - - return false; -} - -Variant::Type GDInstance::get_property_type(const StringName &p_name, bool *r_is_valid) const { - - const GDScript *sptr = script.ptr(); - while (sptr) { - - if (sptr->member_info.has(p_name)) { - if (r_is_valid) - *r_is_valid = true; - return sptr->member_info[p_name].type; - } - sptr = sptr->_base; - } - - if (r_is_valid) - *r_is_valid = false; - return Variant::NIL; -} - -void GDInstance::get_property_list(List<PropertyInfo> *p_properties) const { - // exported members, not doen yet! - - const GDScript *sptr = script.ptr(); - List<PropertyInfo> props; - - while (sptr) { - - const Map<StringName, GDFunction *>::Element *E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._get_property_list); - if (E) { - - Variant::CallError err; - Variant ret = const_cast<GDFunction *>(E->get())->call(const_cast<GDInstance *>(this), NULL, 0, err); - if (err.error == Variant::CallError::CALL_OK) { - - if (ret.get_type() != Variant::ARRAY) { - - ERR_EXPLAIN("Wrong type for _get_property list, must be an array of dictionaries."); - ERR_FAIL(); - } - Array arr = ret; - for (int i = 0; i < arr.size(); i++) { - - Dictionary d = arr[i]; - ERR_CONTINUE(!d.has("name")); - ERR_CONTINUE(!d.has("type")); - PropertyInfo pinfo; - pinfo.type = Variant::Type(d["type"].operator int()); - ERR_CONTINUE(pinfo.type < 0 || pinfo.type >= Variant::VARIANT_MAX); - pinfo.name = d["name"]; - ERR_CONTINUE(pinfo.name == ""); - if (d.has("hint")) - pinfo.hint = PropertyHint(d["hint"].operator int()); - if (d.has("hint_string")) - pinfo.hint_string = d["hint_string"]; - if (d.has("usage")) - pinfo.usage = d["usage"]; - - props.push_back(pinfo); - } - } - } - - //instance a fake script for editing the values - - Vector<_GDScriptMemberSort> msort; - for (Map<StringName, PropertyInfo>::Element *E = sptr->member_info.front(); E; E = E->next()) { - - _GDScriptMemberSort ms; - ERR_CONTINUE(!sptr->member_indices.has(E->key())); - ms.index = sptr->member_indices[E->key()].index; - ms.name = E->key(); - msort.push_back(ms); - } - - msort.sort(); - msort.invert(); - for (int i = 0; i < msort.size(); i++) { - - props.push_front(sptr->member_info[msort[i].name]); - } - - sptr = sptr->_base; - } - - for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) { - - p_properties->push_back(E->get()); - } -} - -void GDInstance::get_method_list(List<MethodInfo> *p_list) const { - - const GDScript *sptr = script.ptr(); - while (sptr) { - - for (Map<StringName, GDFunction *>::Element *E = sptr->member_functions.front(); E; E = E->next()) { - - MethodInfo mi; - mi.name = E->key(); - mi.flags |= METHOD_FLAG_FROM_SCRIPT; - for (int i = 0; i < E->get()->get_argument_count(); i++) - mi.arguments.push_back(PropertyInfo(Variant::NIL, "arg" + itos(i))); - p_list->push_back(mi); - } - sptr = sptr->_base; - } -} - -bool GDInstance::has_method(const StringName &p_method) const { - - const GDScript *sptr = script.ptr(); - while (sptr) { - const Map<StringName, GDFunction *>::Element *E = sptr->member_functions.find(p_method); - if (E) - return true; - sptr = sptr->_base; - } - - return false; -} -Variant GDInstance::call(const StringName &p_method, const Variant **p_args, int p_argcount, Variant::CallError &r_error) { - - //printf("calling %ls:%i method %ls\n", script->get_path().c_str(), -1, String(p_method).c_str()); - - GDScript *sptr = script.ptr(); - while (sptr) { - Map<StringName, GDFunction *>::Element *E = sptr->member_functions.find(p_method); - if (E) { - return E->get()->call(this, p_args, p_argcount, r_error); - } - sptr = sptr->_base; - } - r_error.error = Variant::CallError::CALL_ERROR_INVALID_METHOD; - return Variant(); -} - -void GDInstance::call_multilevel(const StringName &p_method, const Variant **p_args, int p_argcount) { - - GDScript *sptr = script.ptr(); - Variant::CallError ce; - - while (sptr) { - Map<StringName, GDFunction *>::Element *E = sptr->member_functions.find(p_method); - if (E) { - E->get()->call(this, p_args, p_argcount, ce); - } - sptr = sptr->_base; - } -} - -void GDInstance::_ml_call_reversed(GDScript *sptr, const StringName &p_method, const Variant **p_args, int p_argcount) { - - if (sptr->_base) - _ml_call_reversed(sptr->_base, p_method, p_args, p_argcount); - - Variant::CallError ce; - - Map<StringName, GDFunction *>::Element *E = sptr->member_functions.find(p_method); - if (E) { - E->get()->call(this, p_args, p_argcount, ce); - } -} - -void GDInstance::call_multilevel_reversed(const StringName &p_method, const Variant **p_args, int p_argcount) { - - if (script.ptr()) { - _ml_call_reversed(script.ptr(), p_method, p_args, p_argcount); - } -} - -void GDInstance::notification(int p_notification) { - - //notification is not virtual, it gets called at ALL levels just like in C. - Variant value = p_notification; - const Variant *args[1] = { &value }; - - GDScript *sptr = script.ptr(); - while (sptr) { - Map<StringName, GDFunction *>::Element *E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._notification); - if (E) { - Variant::CallError err; - E->get()->call(this, args, 1, err); - if (err.error != Variant::CallError::CALL_OK) { - //print error about notification call - } - } - sptr = sptr->_base; - } -} - -Ref<Script> GDInstance::get_script() const { - - return script; -} - -ScriptLanguage *GDInstance::get_language() { - - return GDScriptLanguage::get_singleton(); -} - -GDInstance::RPCMode GDInstance::get_rpc_mode(const StringName &p_method) const { - - const GDScript *cscript = script.ptr(); - - while (cscript) { - const Map<StringName, GDFunction *>::Element *E = cscript->member_functions.find(p_method); - if (E) { - - if (E->get()->get_rpc_mode() != RPC_MODE_DISABLED) { - return E->get()->get_rpc_mode(); - } - } - cscript = cscript->_base; - } - - return RPC_MODE_DISABLED; -} - -GDInstance::RPCMode GDInstance::get_rset_mode(const StringName &p_variable) const { - - const GDScript *cscript = script.ptr(); - - while (cscript) { - const Map<StringName, GDScript::MemberInfo>::Element *E = cscript->member_indices.find(p_variable); - if (E) { - - if (E->get().rpc_mode) { - return E->get().rpc_mode; - } - } - cscript = cscript->_base; - } - - return RPC_MODE_DISABLED; -} - -void GDInstance::reload_members() { - -#ifdef DEBUG_ENABLED - - members.resize(script->member_indices.size()); //resize - - Vector<Variant> new_members; - new_members.resize(script->member_indices.size()); - - //pass the values to the new indices - for (Map<StringName, GDScript::MemberInfo>::Element *E = script->member_indices.front(); E; E = E->next()) { - - if (member_indices_cache.has(E->key())) { - Variant value = members[member_indices_cache[E->key()]]; - new_members[E->get().index] = value; - } - } - - //apply - members = new_members; - - //pass the values to the new indices - member_indices_cache.clear(); - for (Map<StringName, GDScript::MemberInfo>::Element *E = script->member_indices.front(); E; E = E->next()) { - - member_indices_cache[E->key()] = E->get().index; - } - -#endif -} - -GDInstance::GDInstance() { - owner = NULL; - base_ref = false; -} - -GDInstance::~GDInstance() { - if (script.is_valid() && owner) { -#ifndef NO_THREADS - GDScriptLanguage::singleton->lock->lock(); -#endif - - script->instances.erase(owner); -#ifndef NO_THREADS - GDScriptLanguage::singleton->lock->unlock(); -#endif - } -} - -/************* SCRIPT LANGUAGE **************/ - -GDScriptLanguage *GDScriptLanguage::singleton = NULL; - -String GDScriptLanguage::get_name() const { - - return "GDScript"; -} - -/* LANGUAGE FUNCTIONS */ - -void GDScriptLanguage::_add_global(const StringName &p_name, const Variant &p_value) { - - if (globals.has(p_name)) { - //overwrite existing - global_array[globals[p_name]] = p_value; - return; - } - globals[p_name] = global_array.size(); - global_array.push_back(p_value); - _global_array = global_array.ptr(); -} - -void GDScriptLanguage::add_global_constant(const StringName &p_variable, const Variant &p_value) { - - _add_global(p_variable, p_value); -} - -void GDScriptLanguage::init() { - - //populate global constants - int gcc = GlobalConstants::get_global_constant_count(); - for (int i = 0; i < gcc; i++) { - - _add_global(StaticCString::create(GlobalConstants::get_global_constant_name(i)), GlobalConstants::get_global_constant_value(i)); - } - - _add_global(StaticCString::create("PI"), Math_PI); - _add_global(StaticCString::create("TAU"), Math_TAU); - _add_global(StaticCString::create("INF"), Math_INF); - _add_global(StaticCString::create("NAN"), Math_NAN); - - //populate native classes - - List<StringName> class_list; - ClassDB::get_class_list(&class_list); - for (List<StringName>::Element *E = class_list.front(); E; E = E->next()) { - - StringName n = E->get(); - String s = String(n); - if (s.begins_with("_")) - n = s.substr(1, s.length()); - - if (globals.has(n)) - continue; - Ref<GDNativeClass> nc = memnew(GDNativeClass(E->get())); - _add_global(n, nc); - } - - //populate singletons - - List<Engine::Singleton> singletons; - Engine::get_singleton()->get_singletons(&singletons); - for (List<Engine::Singleton>::Element *E = singletons.front(); E; E = E->next()) { - - _add_global(E->get().name, E->get().ptr); - } -} - -String GDScriptLanguage::get_type() const { - - return "GDScript"; -} -String GDScriptLanguage::get_extension() const { - - return "gd"; -} -Error GDScriptLanguage::execute_file(const String &p_path) { - - // ?? - return OK; -} -void GDScriptLanguage::finish() { -} - -void GDScriptLanguage::profiling_start() { - -#ifdef DEBUG_ENABLED - if (lock) { - lock->lock(); - } - - SelfList<GDFunction> *elem = function_list.first(); - while (elem) { - elem->self()->profile.call_count = 0; - elem->self()->profile.self_time = 0; - elem->self()->profile.total_time = 0; - elem->self()->profile.frame_call_count = 0; - elem->self()->profile.frame_self_time = 0; - elem->self()->profile.frame_total_time = 0; - elem->self()->profile.last_frame_call_count = 0; - elem->self()->profile.last_frame_self_time = 0; - elem->self()->profile.last_frame_total_time = 0; - elem = elem->next(); - } - - profiling = true; - if (lock) { - lock->unlock(); - } - -#endif -} - -void GDScriptLanguage::profiling_stop() { - -#ifdef DEBUG_ENABLED - if (lock) { - lock->lock(); - } - - profiling = false; - if (lock) { - lock->unlock(); - } - -#endif -} - -int GDScriptLanguage::profiling_get_accumulated_data(ProfilingInfo *p_info_arr, int p_info_max) { - - int current = 0; -#ifdef DEBUG_ENABLED - if (lock) { - lock->lock(); - } - - SelfList<GDFunction> *elem = function_list.first(); - while (elem) { - if (current >= p_info_max) - break; - p_info_arr[current].call_count = elem->self()->profile.call_count; - p_info_arr[current].self_time = elem->self()->profile.self_time; - p_info_arr[current].total_time = elem->self()->profile.total_time; - p_info_arr[current].signature = elem->self()->profile.signature; - elem = elem->next(); - current++; - } - - if (lock) { - lock->unlock(); - } - -#endif - - return current; -} - -int GDScriptLanguage::profiling_get_frame_data(ProfilingInfo *p_info_arr, int p_info_max) { - - int current = 0; - -#ifdef DEBUG_ENABLED - if (lock) { - lock->lock(); - } - - SelfList<GDFunction> *elem = function_list.first(); - while (elem) { - if (current >= p_info_max) - break; - if (elem->self()->profile.last_frame_call_count > 0) { - p_info_arr[current].call_count = elem->self()->profile.last_frame_call_count; - p_info_arr[current].self_time = elem->self()->profile.last_frame_self_time; - p_info_arr[current].total_time = elem->self()->profile.last_frame_total_time; - p_info_arr[current].signature = elem->self()->profile.signature; - //print_line(String(elem->self()->profile.signature)+": "+itos(elem->self()->profile.last_frame_call_count)); - current++; - } - elem = elem->next(); - } - - if (lock) { - lock->unlock(); - } - -#endif - - return current; -} - -struct GDScriptDepSort { - - //must support sorting so inheritance works properly (parent must be reloaded first) - bool operator()(const Ref<GDScript> &A, const Ref<GDScript> &B) const { - - if (A == B) - return false; //shouldn't happen but.. - const GDScript *I = B->get_base().ptr(); - while (I) { - if (I == A.ptr()) { - // A is a base of B - return true; - } - - I = I->get_base().ptr(); - } - - return false; //not a base - } -}; - -void GDScriptLanguage::reload_all_scripts() { - -#ifdef DEBUG_ENABLED - print_line("RELOAD ALL SCRIPTS"); - if (lock) { - lock->lock(); - } - - List<Ref<GDScript> > scripts; - - SelfList<GDScript> *elem = script_list.first(); - while (elem) { - if (elem->self()->get_path().is_resource_file()) { - print_line("FOUND: " + elem->self()->get_path()); - scripts.push_back(Ref<GDScript>(elem->self())); //cast to gdscript to avoid being erased by accident - } - elem = elem->next(); - } - - if (lock) { - lock->unlock(); - } - - //as scripts are going to be reloaded, must proceed without locking here - - scripts.sort_custom<GDScriptDepSort>(); //update in inheritance dependency order - - for (List<Ref<GDScript> >::Element *E = scripts.front(); E; E = E->next()) { - - print_line("RELOADING: " + E->get()->get_path()); - E->get()->load_source_code(E->get()->get_path()); - E->get()->reload(true); - } -#endif -} - -void GDScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_soft_reload) { - -#ifdef DEBUG_ENABLED - - if (lock) { - lock->lock(); - } - - List<Ref<GDScript> > scripts; - - SelfList<GDScript> *elem = script_list.first(); - while (elem) { - if (elem->self()->get_path().is_resource_file()) { - - scripts.push_back(Ref<GDScript>(elem->self())); //cast to gdscript to avoid being erased by accident - } - elem = elem->next(); - } - - if (lock) { - lock->unlock(); - } - - //when someone asks you why dynamically typed languages are easier to write.... - - Map<Ref<GDScript>, Map<ObjectID, List<Pair<StringName, Variant> > > > to_reload; - - //as scripts are going to be reloaded, must proceed without locking here - - scripts.sort_custom<GDScriptDepSort>(); //update in inheritance dependency order - - for (List<Ref<GDScript> >::Element *E = scripts.front(); E; E = E->next()) { - - bool reload = E->get() == p_script || to_reload.has(E->get()->get_base()); - - if (!reload) - continue; - - to_reload.insert(E->get(), Map<ObjectID, List<Pair<StringName, Variant> > >()); - - if (!p_soft_reload) { - - //save state and remove script from instances - Map<ObjectID, List<Pair<StringName, Variant> > > &map = to_reload[E->get()]; - - while (E->get()->instances.front()) { - Object *obj = E->get()->instances.front()->get(); - //save instance info - List<Pair<StringName, Variant> > state; - if (obj->get_script_instance()) { - - obj->get_script_instance()->get_property_state(state); - map[obj->get_instance_id()] = state; - obj->set_script(RefPtr()); - } - } - -//same thing for placeholders -#ifdef TOOLS_ENABLED - - while (E->get()->placeholders.size()) { - Object *obj = E->get()->placeholders.front()->get()->get_owner(); - - //save instance info - if (obj->get_script_instance()) { - - map.insert(obj->get_instance_id(), List<Pair<StringName, Variant> >()); - List<Pair<StringName, Variant> > &state = map[obj->get_instance_id()]; - obj->get_script_instance()->get_property_state(state); - obj->set_script(RefPtr()); - } else { - // no instance found. Let's remove it so we don't loop forever - E->get()->placeholders.erase(E->get()->placeholders.front()->get()); - } - } - -#endif - - for (Map<ObjectID, List<Pair<StringName, Variant> > >::Element *F = E->get()->pending_reload_state.front(); F; F = F->next()) { - map[F->key()] = F->get(); //pending to reload, use this one instead - } - } - } - - for (Map<Ref<GDScript>, Map<ObjectID, List<Pair<StringName, Variant> > > >::Element *E = to_reload.front(); E; E = E->next()) { - - Ref<GDScript> scr = E->key(); - scr->reload(p_soft_reload); - - //restore state if saved - for (Map<ObjectID, List<Pair<StringName, Variant> > >::Element *F = E->get().front(); F; F = F->next()) { - - Object *obj = ObjectDB::get_instance(F->key()); - if (!obj) - continue; - - if (!p_soft_reload) { - //clear it just in case (may be a pending reload state) - obj->set_script(RefPtr()); - } - obj->set_script(scr.get_ref_ptr()); - if (!obj->get_script_instance()) { - //failed, save reload state for next time if not saved - if (!scr->pending_reload_state.has(obj->get_instance_id())) { - scr->pending_reload_state[obj->get_instance_id()] = F->get(); - } - continue; - } - - for (List<Pair<StringName, Variant> >::Element *G = F->get().front(); G; G = G->next()) { - obj->get_script_instance()->set(G->get().first, G->get().second); - } - - scr->pending_reload_state.erase(obj->get_instance_id()); //as it reloaded, remove pending state - } - - //if instance states were saved, set them! - } - -#endif -} - -void GDScriptLanguage::frame() { - - //print_line("calls: "+itos(calls)); - calls = 0; - -#ifdef DEBUG_ENABLED - if (profiling) { - if (lock) { - lock->lock(); - } - - SelfList<GDFunction> *elem = function_list.first(); - while (elem) { - elem->self()->profile.last_frame_call_count = elem->self()->profile.frame_call_count; - elem->self()->profile.last_frame_self_time = elem->self()->profile.frame_self_time; - elem->self()->profile.last_frame_total_time = elem->self()->profile.frame_total_time; - elem->self()->profile.frame_call_count = 0; - elem->self()->profile.frame_self_time = 0; - elem->self()->profile.frame_total_time = 0; - elem = elem->next(); - } - - if (lock) { - lock->unlock(); - } - } - -#endif -} - -/* EDITOR FUNCTIONS */ -void GDScriptLanguage::get_reserved_words(List<String> *p_words) const { - - static const char *_reserved_words[] = { - // operators - "and", - "in", - "not", - "or", - // types and values - "false", - "float", - "int", - "bool", - "null", - "PI", - "TAU", - "INF", - "NAN", - "self", - "true", - // functions - "assert", - "breakpoint", - "class", - "extends", - "is", - "func", - "preload", - "setget", - "signal", - "tool", - "yield", - // var - "const", - "enum", - "export", - "onready", - "static", - "var", - // control flow - "break", - "continue", - "if", - "elif", - "else", - "for", - "pass", - "return", - "match", - "while", - "remote", - "sync", - "master", - "slave", - 0 - }; - - const char **w = _reserved_words; - - while (*w) { - - p_words->push_back(*w); - w++; - } - - for (int i = 0; i < GDFunctions::FUNC_MAX; i++) { - p_words->push_back(GDFunctions::get_func_name(GDFunctions::Function(i))); - } -} - -GDScriptLanguage::GDScriptLanguage() { - - calls = 0; - ERR_FAIL_COND(singleton); - singleton = this; - strings._init = StaticCString::create("_init"); - strings._notification = StaticCString::create("_notification"); - strings._set = StaticCString::create("_set"); - strings._get = StaticCString::create("_get"); - strings._get_property_list = StaticCString::create("_get_property_list"); - strings._script_source = StaticCString::create("script/source"); - _debug_parse_err_line = -1; - _debug_parse_err_file = ""; - -#ifdef NO_THREADS - lock = NULL; -#else - lock = Mutex::create(); -#endif - profiling = false; - script_frame_time = 0; - - _debug_call_stack_pos = 0; - int dmcs = GLOBAL_DEF("debug/settings/gdscript/max_call_stack", 1024); - if (ScriptDebugger::get_singleton()) { - //debugging enabled! - - _debug_max_call_stack = dmcs; - if (_debug_max_call_stack < 1024) - _debug_max_call_stack = 1024; - _call_stack = memnew_arr(CallLevel, _debug_max_call_stack + 1); - - } else { - _debug_max_call_stack = 0; - _call_stack = NULL; - } -} - -GDScriptLanguage::~GDScriptLanguage() { - - if (lock) { - memdelete(lock); - lock = NULL; - } - if (_call_stack) { - memdelete_arr(_call_stack); - } - singleton = NULL; -} - -/*************** RESOURCE ***************/ - -RES ResourceFormatLoaderGDScript::load(const String &p_path, const String &p_original_path, Error *r_error) { - - if (r_error) - *r_error = ERR_FILE_CANT_OPEN; - - GDScript *script = memnew(GDScript); - - Ref<GDScript> scriptres(script); - - if (p_path.ends_with(".gde") || p_path.ends_with(".gdc")) { - - script->set_script_path(p_original_path); // script needs this. - script->set_path(p_original_path); - Error err = script->load_byte_code(p_path); - - if (err != OK) { - - ERR_FAIL_COND_V(err != OK, RES()); - } - - } else { - Error err = script->load_source_code(p_path); - - if (err != OK) { - - ERR_FAIL_COND_V(err != OK, RES()); - } - - script->set_script_path(p_original_path); // script needs this. - script->set_path(p_original_path); - //script->set_name(p_path.get_file()); - - script->reload(); - } - if (r_error) - *r_error = OK; - - return scriptres; -} -void ResourceFormatLoaderGDScript::get_recognized_extensions(List<String> *p_extensions) const { - - p_extensions->push_back("gd"); - p_extensions->push_back("gdc"); - p_extensions->push_back("gde"); -} - -bool ResourceFormatLoaderGDScript::handles_type(const String &p_type) const { - - return (p_type == "Script" || p_type == "GDScript"); -} - -String ResourceFormatLoaderGDScript::get_resource_type(const String &p_path) const { - - String el = p_path.get_extension().to_lower(); - if (el == "gd" || el == "gdc" || el == "gde") - return "GDScript"; - return ""; -} - -Error ResourceFormatSaverGDScript::save(const String &p_path, const RES &p_resource, uint32_t p_flags) { - - Ref<GDScript> sqscr = p_resource; - ERR_FAIL_COND_V(sqscr.is_null(), ERR_INVALID_PARAMETER); - - String source = sqscr->get_source_code(); - - Error err; - FileAccess *file = FileAccess::open(p_path, FileAccess::WRITE, &err); - - if (err) { - - ERR_FAIL_COND_V(err, err); - } - - file->store_string(source); - if (file->get_error() != OK && file->get_error() != ERR_FILE_EOF) { - memdelete(file); - return ERR_CANT_CREATE; - } - file->close(); - memdelete(file); - - if (ScriptServer::is_reload_scripts_on_save_enabled()) { - GDScriptLanguage::get_singleton()->reload_tool_script(p_resource, false); - } - - return OK; -} - -void ResourceFormatSaverGDScript::get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const { - - if (Object::cast_to<GDScript>(*p_resource)) { - p_extensions->push_back("gd"); - } -} -bool ResourceFormatSaverGDScript::recognize(const RES &p_resource) const { - - return Object::cast_to<GDScript>(*p_resource) != NULL; -} |