summaryrefslogtreecommitdiff
path: root/modules/gdscript/gdscript.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'modules/gdscript/gdscript.cpp')
-rw-r--r--modules/gdscript/gdscript.cpp370
1 files changed, 239 insertions, 131 deletions
diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp
index d415684d10..10babad378 100644
--- a/modules/gdscript/gdscript.cpp
+++ b/modules/gdscript/gdscript.cpp
@@ -51,7 +51,7 @@
#endif
#ifdef TOOLS_ENABLED
-#include "editor/editor_settings.h"
+#include "editor/editor_paths.h"
#endif
///////////////////////////
@@ -62,7 +62,7 @@ GDScriptNativeClass::GDScriptNativeClass(const StringName &p_name) {
bool GDScriptNativeClass::_get(const StringName &p_name, Variant &r_ret) const {
bool ok;
- int v = ClassDB::get_integer_constant(name, p_name, &ok);
+ int64_t v = ClassDB::get_integer_constant(name, p_name, &ok);
if (ok) {
r_ret = v;
@@ -82,7 +82,7 @@ Variant GDScriptNativeClass::_new() {
RefCounted *rc = Object::cast_to<RefCounted>(o);
if (rc) {
- return REF(rc);
+ return Ref<RefCounted>(rc);
} else {
return o;
}
@@ -92,6 +92,21 @@ Object *GDScriptNativeClass::instantiate() {
return ClassDB::instantiate(name);
}
+Variant GDScriptNativeClass::callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
+ if (p_method == SNAME("new")) {
+ // Constructor.
+ return Object::callp(p_method, p_args, p_argcount, r_error);
+ }
+ MethodBind *method = ClassDB::get_method(name, p_method);
+ if (method) {
+ // Native static method.
+ return method->call(nullptr, p_args, p_argcount, r_error);
+ }
+
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
+ return Variant();
+}
+
GDScriptFunction *GDScript::_super_constructor(GDScript *p_script) {
if (p_script->initializer) {
return p_script->initializer;
@@ -113,6 +128,7 @@ void GDScript::_super_implicit_constructor(GDScript *p_script, GDScriptInstance
return;
}
}
+ ERR_FAIL_NULL(p_script->implicit_initializer);
p_script->implicit_initializer->call(p_instance, nullptr, 0, r_error);
}
@@ -180,7 +196,7 @@ Variant GDScript::_new(const Variant **p_args, int p_argcount, Callable::CallErr
}
r_error.error = Callable::CallError::CALL_OK;
- REF ref;
+ Ref<RefCounted> ref;
Object *owner = nullptr;
GDScript *_baseptr = this;
@@ -198,7 +214,7 @@ Variant GDScript::_new(const Variant **p_args, int p_argcount, Callable::CallErr
RefCounted *r = Object::cast_to<RefCounted>(owner);
if (r) {
- ref = REF(r);
+ ref = Ref<RefCounted>(r);
}
GDScriptInstance *instance = _create_instance(p_args, p_argcount, owner, r != nullptr, r_error);
@@ -262,6 +278,11 @@ void GDScript::_get_script_method_list(List<MethodInfo> *r_list, bool p_include_
GDScriptFunction *func = E.value;
MethodInfo mi;
mi.name = E.key;
+
+ if (func->is_static()) {
+ mi.flags |= METHOD_FLAG_STATIC;
+ }
+
for (int i = 0; i < func->get_argument_count(); i++) {
PropertyInfo arginfo = func->get_argument_type(i);
#ifdef TOOLS_ENABLED
@@ -269,7 +290,9 @@ void GDScript::_get_script_method_list(List<MethodInfo> *r_list, bool p_include_
#endif
mi.arguments.push_back(arginfo);
}
-
+#ifdef TOOLS_ENABLED
+ mi.default_arguments.append_array(func->get_default_arg_values());
+#endif
mi.return_val = func->get_return_type();
r_list->push_back(mi);
}
@@ -304,16 +327,23 @@ void GDScript::_get_script_property_list(List<PropertyInfo> *r_list, bool p_incl
for (int i = 0; i < msort.size(); i++) {
props.push_front(sptr->member_info[msort[i].name]);
}
+
+#ifdef TOOLS_ENABLED
+ r_list->push_back(sptr->get_class_category());
+#endif // TOOLS_ENABLED
+
+ for (const PropertyInfo &E : props) {
+ r_list->push_back(E);
+ }
+
+ props.clear();
+
if (!p_include_base) {
break;
}
sptr = sptr->_base;
}
-
- for (const PropertyInfo &E : props) {
- r_list->push_back(E);
- }
}
void GDScript::get_script_property_list(List<PropertyInfo> *r_list) const {
@@ -325,14 +355,14 @@ bool GDScript::has_method(const StringName &p_method) const {
}
MethodInfo GDScript::get_method_info(const StringName &p_method) const {
- const Map<StringName, GDScriptFunction *>::Element *E = member_functions.find(p_method);
+ HashMap<StringName, GDScriptFunction *>::ConstIterator E = member_functions.find(p_method);
if (!E) {
return MethodInfo();
}
- GDScriptFunction *func = E->get();
+ GDScriptFunction *func = E->value;
MethodInfo mi;
- mi.name = E->key();
+ mi.name = E->key;
for (int i = 0; i < func->get_argument_count(); i++) {
mi.arguments.push_back(func->get_argument_type(i));
}
@@ -344,9 +374,9 @@ MethodInfo GDScript::get_method_info(const StringName &p_method) const {
bool GDScript::get_property_default_value(const StringName &p_property, Variant &r_value) const {
#ifdef TOOLS_ENABLED
- const Map<StringName, Variant>::Element *E = member_default_values_cache.find(p_property);
+ HashMap<StringName, Variant>::ConstIterator E = member_default_values_cache.find(p_property);
if (E) {
- r_value = E->get();
+ r_value = E->value;
return true;
}
@@ -412,11 +442,7 @@ void GDScript::set_source_code(const String &p_code) {
}
#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);
- }
-
+void GDScript::_update_exports_values(HashMap<StringName, Variant> &values, List<PropertyInfo> &propnames) {
for (const KeyValue<StringName, Variant> &E : member_default_values_cache) {
values[E.key] = E.value;
}
@@ -424,6 +450,10 @@ void GDScript::_update_exports_values(Map<StringName, Variant> &values, List<Pro
for (const PropertyInfo &E : members_cache) {
propnames.push_back(E);
}
+
+ if (base_cache.is_valid()) {
+ base_cache->_update_exports_values(values, propnames);
+ }
}
void GDScript::_add_doc(const DocData::ClassDoc &p_inner_class) {
@@ -520,6 +550,9 @@ void GDScript::_update_doc() {
List<PropertyInfo> props;
_get_script_property_list(&props, false);
for (int i = 0; i < props.size(); i++) {
+ if (props[i].usage & PROPERTY_USAGE_CATEGORY || props[i].usage & PROPERTY_USAGE_GROUP || props[i].usage & PROPERTY_USAGE_SUBGROUP) {
+ continue;
+ }
ScriptMemberInfo scr_member_info;
scr_member_info.propinfo = props[i];
scr_member_info.propinfo.usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
@@ -650,7 +683,7 @@ bool GDScript::_update_exports(bool *r_err, bool p_recursive_call, PlaceHolderSc
if (base.is_empty() || base.is_relative_path()) {
ERR_PRINT(("Could not resolve relative path for parent class: " + path).utf8().get_data());
} else {
- path = base.get_base_dir().plus_file(path);
+ path = base.get_base_dir().path_join(path);
}
}
} else if (c->extends.size() != 0) {
@@ -679,6 +712,8 @@ bool GDScript::_update_exports(bool *r_err, bool p_recursive_call, PlaceHolderSc
member_default_values_cache.clear();
_signals.clear();
+ members_cache.push_back(get_class_category());
+
for (int i = 0; i < c->members.size(); i++) {
const GDScriptParser::ClassNode::Member &member = c->members[i];
@@ -704,6 +739,9 @@ bool GDScript::_update_exports(bool *r_err, bool p_recursive_call, PlaceHolderSc
}
_signals[member.signal->identifier->name] = parameters_names;
} break;
+ case GDScriptParser::ClassNode::Member::GROUP: {
+ members_cache.push_back(member.annotation->export_info);
+ } break;
default:
break; // Nothing.
}
@@ -744,13 +782,13 @@ bool GDScript::_update_exports(bool *r_err, bool p_recursive_call, PlaceHolderSc
if ((changed || p_instance_to_update) && placeholders.size()) { //hm :(
// update placeholders if any
- Map<StringName, Variant> values;
+ HashMap<StringName, Variant> values;
List<PropertyInfo> propnames;
_update_exports_values(values, propnames);
if (changed) {
- for (Set<PlaceHolderScriptInstance *>::Element *E = placeholders.front(); E; E = E->next()) {
- E->get()->update(propnames, values);
+ for (PlaceHolderScriptInstance *E : placeholders) {
+ E->update(propnames, values);
}
} else {
p_instance_to_update->update(propnames, values);
@@ -773,10 +811,10 @@ void GDScript::update_exports() {
return;
}
- Set<ObjectID> copy = inheriters_cache; //might get modified
+ HashSet<ObjectID> copy = inheriters_cache; //might get modified
- for (Set<ObjectID>::Element *E = copy.front(); E; E = E->next()) {
- Object *id = ObjectDB::get_instance(E->get());
+ for (const ObjectID &E : copy) {
+ Object *id = ObjectDB::get_instance(E);
GDScript *s = Object::cast_to<GDScript>(id);
if (!s) {
continue;
@@ -824,7 +862,7 @@ Error GDScript::reload(bool p_keep_state) {
// Loading a template, don't parse.
#ifdef TOOLS_ENABLED
- if (basedir.begins_with(EditorSettings::get_singleton()->get_project_script_templates_dir())) {
+ if (EditorPaths::get_singleton() && basedir.begins_with(EditorPaths::get_singleton()->get_project_script_templates_dir())) {
return OK;
}
#endif
@@ -851,7 +889,7 @@ Error GDScript::reload(bool p_keep_state) {
}
// TODO: Show all error messages.
_err_print_error("GDScript::reload", path.is_empty() ? "built-in" : (const char *)path.utf8().get_data(), parser.get_errors().front()->get().line, ("Parse Error: " + parser.get_errors().front()->get().message).utf8().get_data(), false, ERR_HANDLER_SCRIPT);
- ERR_FAIL_V(ERR_PARSE_ERROR);
+ return ERR_PARSE_ERROR;
}
GDScriptAnalyzer analyzer(&parser);
@@ -867,7 +905,7 @@ Error GDScript::reload(bool p_keep_state) {
_err_print_error("GDScript::reload", path.is_empty() ? "built-in" : (const char *)path.utf8().get_data(), e->get().line, ("Parse Error: " + e->get().message).utf8().get_data(), false, ERR_HANDLER_SCRIPT);
e = e->next();
}
- ERR_FAIL_V(ERR_PARSE_ERROR);
+ return ERR_PARSE_ERROR;
}
bool can_run = ScriptServer::is_scripting_enabled() || parser.is_tool();
@@ -885,7 +923,7 @@ Error GDScript::reload(bool p_keep_state) {
GDScriptLanguage::get_singleton()->debug_break_parse(_get_debug_path(), compiler.get_error_line(), "Parser Error: " + compiler.get_error());
}
_err_print_error("GDScript::reload", path.is_empty() ? "built-in" : (const char *)path.utf8().get_data(), compiler.get_error_line(), ("Compile Error: " + compiler.get_error()).utf8().get_data(), false, ERR_HANDLER_SCRIPT);
- ERR_FAIL_V(ERR_COMPILATION_FAILED);
+ return ERR_COMPILATION_FAILED;
} else {
return err;
}
@@ -914,7 +952,7 @@ ScriptLanguage *GDScript::get_language() const {
return GDScriptLanguage::get_singleton();
}
-void GDScript::get_constants(Map<StringName, Variant> *p_constants) {
+void GDScript::get_constants(HashMap<StringName, Variant> *p_constants) {
if (p_constants) {
for (const KeyValue<StringName, Variant> &E : constants) {
(*p_constants)[E.key] = E.value;
@@ -922,26 +960,26 @@ void GDScript::get_constants(Map<StringName, Variant> *p_constants) {
}
}
-void GDScript::get_members(Set<StringName> *p_members) {
+void GDScript::get_members(HashSet<StringName> *p_members) {
if (p_members) {
- for (Set<StringName>::Element *E = members.front(); E; E = E->next()) {
- p_members->insert(E->get());
+ for (const StringName &E : members) {
+ p_members->insert(E);
}
}
}
-const Vector<Multiplayer::RPCConfig> GDScript::get_rpc_methods() const {
- return rpc_functions;
+const Variant GDScript::get_rpc_config() const {
+ return rpc_config;
}
Variant GDScript::callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
GDScript *top = this;
while (top) {
- Map<StringName, GDScriptFunction *>::Element *E = top->member_functions.find(p_method);
+ HashMap<StringName, GDScriptFunction *>::Iterator E = top->member_functions.find(p_method);
if (E) {
- ERR_FAIL_COND_V_MSG(!E->get()->is_static(), Variant(), "Can't call non-static function '" + String(p_method) + "' in script.");
+ ERR_FAIL_COND_V_MSG(!E->value->is_static(), Variant(), "Can't call non-static function '" + String(p_method) + "' in script.");
- return E->get()->call(nullptr, p_args, p_argcount, r_error);
+ return E->value->call(nullptr, p_args, p_argcount, r_error);
}
top = top->_base;
}
@@ -956,17 +994,17 @@ 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);
+ HashMap<StringName, Variant>::ConstIterator E = top->constants.find(p_name);
if (E) {
- r_ret = E->get();
+ r_ret = E->value;
return true;
}
}
{
- const Map<StringName, Ref<GDScript>>::Element *E = subclasses.find(p_name);
+ HashMap<StringName, Ref<GDScript>>::ConstIterator E = subclasses.find(p_name);
if (E) {
- r_ret = E->get();
+ r_ret = E->value;
return true;
}
}
@@ -1015,22 +1053,26 @@ Error GDScript::load_byte_code(const String &p_path) {
Error GDScript::load_source_code(const String &p_path) {
Vector<uint8_t> sourcef;
Error err;
- FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err);
+ Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ, &err);
if (err) {
- ERR_FAIL_COND_V(err, err);
+ const char *err_name;
+ if (err < 0 || err >= ERR_MAX) {
+ err_name = "(invalid error code)";
+ } else {
+ err_name = error_names[err];
+ }
+ ERR_FAIL_COND_V_MSG(err, err, "Attempt to open script '" + p_path + "' resulted in error '" + err_name + "'.");
}
uint64_t len = f->get_length();
sourcef.resize(len + 1);
uint8_t *w = sourcef.ptrw();
uint64_t r = f->get_buffer(w, 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)) {
+ if (s.parse_utf8((const char *)w) != OK) {
ERR_FAIL_V_MSG(ERR_INVALID_DATA, "Script '" + p_path + "' contains invalid unicode (UTF-8), so it was not loaded. Please ensure that scripts are saved in valid UTF-8 unicode.");
}
@@ -1042,7 +1084,7 @@ Error GDScript::load_source_code(const String &p_path) {
return OK;
}
-const Map<StringName, GDScriptFunction *> &GDScript::debug_get_member_functions() const {
+const HashMap<StringName, GDScriptFunction *> &GDScript::debug_get_member_functions() const {
return member_functions;
}
@@ -1184,38 +1226,32 @@ void GDScript::_save_orphaned_subclasses() {
void GDScript::_init_rpc_methods_properties() {
// Copy the base rpc methods so we don't mask their IDs.
- rpc_functions.clear();
+ rpc_config.clear();
if (base.is_valid()) {
- rpc_functions = base->rpc_functions;
+ rpc_config = base->rpc_config.duplicate();
}
GDScript *cscript = this;
- Map<StringName, Ref<GDScript>>::Element *sub_E = subclasses.front();
+ HashMap<StringName, Ref<GDScript>>::Iterator sub_E = subclasses.begin();
while (cscript) {
// RPC Methods
for (KeyValue<StringName, GDScriptFunction *> &E : cscript->member_functions) {
- Multiplayer::RPCConfig config = E.value->get_rpc_config();
- if (config.rpc_mode != Multiplayer::RPC_MODE_DISABLED) {
- config.name = E.value->get_name();
- if (rpc_functions.find(config) == -1) {
- rpc_functions.push_back(config);
- }
+ Variant config = E.value->get_rpc_config();
+ if (config.get_type() != Variant::NIL) {
+ rpc_config[E.value->get_name()] = config;
}
}
if (cscript != this) {
- sub_E = sub_E->next();
+ ++sub_E;
}
if (sub_E) {
- cscript = sub_E->get().ptr();
+ cscript = sub_E->value.ptr();
} else {
cscript = nullptr;
}
}
-
- // Sort so we are 100% that they are always the same.
- rpc_functions.sort_custom<Multiplayer::SortRPCConfig>();
}
GDScript::~GDScript() {
@@ -1234,6 +1270,14 @@ GDScript::~GDScript() {
memdelete(E.value);
}
+ if (implicit_initializer) {
+ memdelete(implicit_initializer);
+ }
+
+ if (implicit_ready) {
+ memdelete(implicit_ready);
+ }
+
if (GDScriptCache::singleton) { // Cache may have been already destroyed at engine shutdown.
GDScriptCache::remove_script(get_path());
}
@@ -1263,9 +1307,9 @@ GDScript::~GDScript() {
bool GDScriptInstance::set(const StringName &p_name, const Variant &p_value) {
//member
{
- const Map<StringName, GDScript::MemberInfo>::Element *E = script->member_indices.find(p_name);
+ HashMap<StringName, GDScript::MemberInfo>::Iterator E = script->member_indices.find(p_name);
if (E) {
- const GDScript::MemberInfo *member = &E->get();
+ const GDScript::MemberInfo *member = &E->value;
if (member->setter) {
const Variant *val = &p_value;
Callable::CallError err;
@@ -1306,13 +1350,13 @@ bool GDScriptInstance::set(const StringName &p_name, const Variant &p_value) {
GDScript *sptr = script.ptr();
while (sptr) {
- Map<StringName, GDScriptFunction *>::Element *E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._set);
+ HashMap<StringName, GDScriptFunction *>::Iterator E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._set);
if (E) {
Variant name = p_name;
const Variant *args[2] = { &name, &p_value };
Callable::CallError err;
- Variant ret = E->get()->call(this, (const Variant **)args, 2, err);
+ Variant ret = E->value->call(this, (const Variant **)args, 2, err);
if (err.error == Callable::CallError::CALL_OK && ret.get_type() == Variant::BOOL && ret.operator bool()) {
return true;
}
@@ -1327,16 +1371,16 @@ bool GDScriptInstance::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);
+ HashMap<StringName, GDScript::MemberInfo>::ConstIterator E = script->member_indices.find(p_name);
if (E) {
- if (E->get().getter) {
+ if (E->value.getter) {
Callable::CallError err;
- r_ret = const_cast<GDScriptInstance *>(this)->callp(E->get().getter, nullptr, 0, err);
+ r_ret = const_cast<GDScriptInstance *>(this)->callp(E->value.getter, nullptr, 0, err);
if (err.error == Callable::CallError::CALL_OK) {
return true;
}
}
- r_ret = members[E->get().index];
+ r_ret = members[E->value.index];
return true; //index found
}
}
@@ -1344,9 +1388,9 @@ bool GDScriptInstance::get(const StringName &p_name, Variant &r_ret) const {
{
const GDScript *sl = sptr;
while (sl) {
- const Map<StringName, Variant>::Element *E = sl->constants.find(p_name);
+ HashMap<StringName, Variant>::ConstIterator E = sl->constants.find(p_name);
if (E) {
- r_ret = E->get();
+ r_ret = E->value;
return true; //index found
}
sl = sl->_base;
@@ -1357,9 +1401,9 @@ bool GDScriptInstance::get(const StringName &p_name, Variant &r_ret) const {
// Signals.
const GDScript *sl = sptr;
while (sl) {
- const Map<StringName, Vector<StringName>>::Element *E = sl->_signals.find(p_name);
+ HashMap<StringName, Vector<StringName>>::ConstIterator E = sl->_signals.find(p_name);
if (E) {
- r_ret = Signal(this->owner, E->key());
+ r_ret = Signal(this->owner, E->key);
return true; //index found
}
sl = sl->_base;
@@ -1370,14 +1414,12 @@ bool GDScriptInstance::get(const StringName &p_name, Variant &r_ret) const {
// Methods.
const GDScript *sl = sptr;
while (sl) {
- const Map<StringName, GDScriptFunction *>::Element *E = sl->member_functions.find(p_name);
+ HashMap<StringName, GDScriptFunction *>::ConstIterator E = sl->member_functions.find(p_name);
if (E) {
- Multiplayer::RPCConfig config;
- config.name = p_name;
- if (sptr->rpc_functions.find(config) != -1) {
- r_ret = Callable(memnew(GDScriptRPCCallable(this->owner, E->key())));
+ if (sptr->rpc_config.has(p_name)) {
+ r_ret = Callable(memnew(GDScriptRPCCallable(this->owner, E->key)));
} else {
- r_ret = Callable(this->owner, E->key());
+ r_ret = Callable(this->owner, E->key);
}
return true; //index found
}
@@ -1386,13 +1428,13 @@ bool GDScriptInstance::get(const StringName &p_name, Variant &r_ret) const {
}
{
- const Map<StringName, GDScriptFunction *>::Element *E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._get);
+ HashMap<StringName, GDScriptFunction *>::ConstIterator E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._get);
if (E) {
Variant name = p_name;
const Variant *args[1] = { &name };
Callable::CallError err;
- Variant ret = const_cast<GDScriptFunction *>(E->get())->call(const_cast<GDScriptInstance *>(this), (const Variant **)args, 1, err);
+ Variant ret = const_cast<GDScriptFunction *>(E->value)->call(const_cast<GDScriptInstance *>(this), (const Variant **)args, 1, err);
if (err.error == Callable::CallError::CALL_OK && ret.get_type() != Variant::NIL) {
r_ret = ret;
return true;
@@ -1430,10 +1472,10 @@ void GDScriptInstance::get_property_list(List<PropertyInfo> *p_properties) const
List<PropertyInfo> props;
while (sptr) {
- const Map<StringName, GDScriptFunction *>::Element *E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._get_property_list);
+ HashMap<StringName, GDScriptFunction *>::ConstIterator E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._get_property_list);
if (E) {
Callable::CallError err;
- Variant ret = const_cast<GDScriptFunction *>(E->get())->call(const_cast<GDScriptInstance *>(this), nullptr, 0, err);
+ Variant ret = const_cast<GDScriptFunction *>(E->value)->call(const_cast<GDScriptInstance *>(this), nullptr, 0, err);
if (err.error == Callable::CallError::CALL_OK) {
ERR_FAIL_COND_MSG(ret.get_type() != Variant::ARRAY, "Wrong type for _get_property_list, must be an array of dictionaries.");
@@ -1456,6 +1498,9 @@ void GDScriptInstance::get_property_list(List<PropertyInfo> *p_properties) const
if (d.has("usage")) {
pinfo.usage = d["usage"];
}
+ if (d.has("class_name")) {
+ pinfo.class_name = d["class_name"];
+ }
props.push_back(pinfo);
}
@@ -1479,12 +1524,59 @@ void GDScriptInstance::get_property_list(List<PropertyInfo> *p_properties) const
props.push_front(sptr->member_info[msort[i].name]);
}
+#ifdef TOOLS_ENABLED
+ p_properties->push_back(sptr->get_class_category());
+#endif // TOOLS_ENABLED
+
+ for (const PropertyInfo &prop : props) {
+ p_properties->push_back(prop);
+ }
+
+ props.clear();
+
sptr = sptr->_base;
}
+}
+
+bool GDScriptInstance::property_can_revert(const StringName &p_name) const {
+ Variant name = p_name;
+ const Variant *args[1] = { &name };
+
+ const GDScript *sptr = script.ptr();
+ while (sptr) {
+ HashMap<StringName, GDScriptFunction *>::ConstIterator E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._property_can_revert);
+ if (E) {
+ Callable::CallError err;
+ Variant ret = E->value->call(const_cast<GDScriptInstance *>(this), args, 1, err);
+ if (err.error == Callable::CallError::CALL_OK && ret.get_type() == Variant::BOOL && ret.operator bool()) {
+ return true;
+ }
+ }
+ sptr = sptr->_base;
+ }
+
+ return false;
+}
- for (const PropertyInfo &E : props) {
- p_properties->push_back(E);
+bool GDScriptInstance::property_get_revert(const StringName &p_name, Variant &r_ret) const {
+ Variant name = p_name;
+ const Variant *args[1] = { &name };
+
+ const GDScript *sptr = script.ptr();
+ while (sptr) {
+ HashMap<StringName, GDScriptFunction *>::ConstIterator E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._property_get_revert);
+ if (E) {
+ Callable::CallError err;
+ Variant ret = E->value->call(const_cast<GDScriptInstance *>(this), args, 1, err);
+ if (err.error == Callable::CallError::CALL_OK && ret.get_type() != Variant::NIL) {
+ r_ret = ret;
+ return true;
+ }
+ }
+ sptr = sptr->_base;
}
+
+ return false;
}
void GDScriptInstance::get_method_list(List<MethodInfo> *p_list) const {
@@ -1493,7 +1585,6 @@ void GDScriptInstance::get_method_list(List<MethodInfo> *p_list) const {
for (const KeyValue<StringName, GDScriptFunction *> &E : sptr->member_functions) {
MethodInfo mi;
mi.name = E.key;
- mi.flags |= METHOD_FLAG_FROM_SCRIPT;
for (int i = 0; i < E.value->get_argument_count(); i++) {
mi.arguments.push_back(PropertyInfo(Variant::NIL, "arg" + itos(i)));
}
@@ -1506,7 +1597,7 @@ void GDScriptInstance::get_method_list(List<MethodInfo> *p_list) const {
bool GDScriptInstance::has_method(const StringName &p_method) const {
const GDScript *sptr = script.ptr();
while (sptr) {
- const Map<StringName, GDScriptFunction *>::Element *E = sptr->member_functions.find(p_method);
+ HashMap<StringName, GDScriptFunction *>::ConstIterator E = sptr->member_functions.find(p_method);
if (E) {
return true;
}
@@ -1518,10 +1609,22 @@ bool GDScriptInstance::has_method(const StringName &p_method) const {
Variant GDScriptInstance::callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
GDScript *sptr = script.ptr();
+ if (unlikely(p_method == SNAME("_ready"))) {
+ // Call implicit ready first, including for the super classes.
+ while (sptr) {
+ if (sptr->implicit_ready) {
+ sptr->implicit_ready->call(this, nullptr, 0, r_error);
+ }
+ sptr = sptr->_base;
+ }
+
+ // Reset this back for the regular call.
+ sptr = script.ptr();
+ }
while (sptr) {
- Map<StringName, GDScriptFunction *>::Element *E = sptr->member_functions.find(p_method);
+ HashMap<StringName, GDScriptFunction *>::Iterator E = sptr->member_functions.find(p_method);
if (E) {
- return E->get()->call(this, p_args, p_argcount, r_error);
+ return E->value->call(this, p_args, p_argcount, r_error);
}
sptr = sptr->_base;
}
@@ -1536,10 +1639,10 @@ void GDScriptInstance::notification(int p_notification) {
GDScript *sptr = script.ptr();
while (sptr) {
- Map<StringName, GDScriptFunction *>::Element *E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._notification);
+ HashMap<StringName, GDScriptFunction *>::Iterator E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._notification);
if (E) {
Callable::CallError err;
- E->get()->call(this, args, 1, err);
+ E->value->call(this, args, 1, err);
if (err.error != Callable::CallError::CALL_OK) {
//print error about notification call
}
@@ -1579,15 +1682,13 @@ ScriptLanguage *GDScriptInstance::get_language() {
return GDScriptLanguage::get_singleton();
}
-const Vector<Multiplayer::RPCConfig> GDScriptInstance::get_rpc_methods() const {
- return script->get_rpc_methods();
+const Variant GDScriptInstance::get_rpc_config() const {
+ return script->get_rpc_config();
}
void GDScriptInstance::reload_members() {
#ifdef DEBUG_ENABLED
- members.resize(script->member_indices.size()); //resize
-
Vector<Variant> new_members;
new_members.resize(script->member_indices.size());
@@ -1599,6 +1700,8 @@ void GDScriptInstance::reload_members() {
}
}
+ members.resize(new_members.size()); //resize
+
//apply
members = new_members;
@@ -1863,7 +1966,7 @@ void GDScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_so
//when someone asks you why dynamically typed languages are easier to write....
- Map<Ref<GDScript>, Map<ObjectID, List<Pair<StringName, Variant>>>> to_reload;
+ HashMap<Ref<GDScript>, HashMap<ObjectID, List<Pair<StringName, Variant>>>> to_reload;
//as scripts are going to be reloaded, must proceed without locking here
@@ -1876,11 +1979,11 @@ void GDScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_so
continue;
}
- to_reload.insert(script, Map<ObjectID, List<Pair<StringName, Variant>>>());
+ to_reload.insert(script, HashMap<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[script];
+ HashMap<ObjectID, List<Pair<StringName, Variant>>> &map = to_reload[script];
while (script->instances.front()) {
Object *obj = script->instances.front()->get();
@@ -1897,7 +2000,7 @@ void GDScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_so
#ifdef TOOLS_ENABLED
while (script->placeholders.size()) {
- Object *obj = script->placeholders.front()->get()->get_owner();
+ Object *obj = (*script->placeholders.begin())->get_owner();
//save instance info
if (obj->get_script_instance()) {
@@ -1907,7 +2010,7 @@ void GDScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_so
obj->set_script(Variant());
} else {
// no instance found. Let's remove it so we don't loop forever
- script->placeholders.erase(script->placeholders.front()->get());
+ script->placeholders.erase(*script->placeholders.begin());
}
}
@@ -1919,7 +2022,7 @@ void GDScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_so
}
}
- for (KeyValue<Ref<GDScript>, Map<ObjectID, List<Pair<StringName, Variant>>>> &E : to_reload) {
+ for (KeyValue<Ref<GDScript>, HashMap<ObjectID, List<Pair<StringName, Variant>>>> &E : to_reload) {
Ref<GDScript> scr = E.key;
scr->reload(p_soft_reload);
@@ -2084,7 +2187,7 @@ bool GDScriptLanguage::handles_global_class_type(const String &p_type) const {
String GDScriptLanguage::get_global_class_name(const String &p_path, String *r_base_type, String *r_icon_path) const {
Vector<uint8_t> sourcef;
Error err;
- FileAccessRef f = FileAccess::open(p_path, FileAccess::READ, &err);
+ Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ, &err);
if (err) {
return String();
}
@@ -2101,7 +2204,7 @@ String GDScriptLanguage::get_global_class_name(const String &p_path, String *r_b
if (c->icon_path.is_empty() || c->icon_path.is_absolute_path()) {
*r_icon_path = c->icon_path;
} else if (c->icon_path.is_relative_path()) {
- *r_icon_path = p_path.get_base_dir().plus_file(c->icon_path).simplify_path();
+ *r_icon_path = p_path.get_base_dir().path_join(c->icon_path).simplify_path();
}
}
if (r_base_type) {
@@ -2118,8 +2221,8 @@ String GDScriptLanguage::get_global_class_name(const String &p_path, String *r_b
} else {
Vector<StringName> extend_classes = subclass->extends;
- FileAccessRef subfile = FileAccess::open(subclass->extends_path, FileAccess::READ);
- if (!subfile) {
+ Ref<FileAccess> subfile = FileAccess::open(subclass->extends_path, FileAccess::READ);
+ if (subfile.is_null()) {
break;
}
String subsource = subfile->get_as_utf8_string();
@@ -2129,7 +2232,7 @@ String GDScriptLanguage::get_global_class_name(const String &p_path, String *r_b
}
String subpath = subclass->extends_path;
if (subpath.is_relative_path()) {
- subpath = path.get_base_dir().plus_file(subpath).simplify_path();
+ subpath = path.get_base_dir().path_join(subpath).simplify_path();
}
if (OK != subparser.parse(subsource, subpath, false)) {
@@ -2186,6 +2289,8 @@ GDScriptLanguage::GDScriptLanguage() {
strings._set = StaticCString::create("_set");
strings._get = StaticCString::create("_get");
strings._get_property_list = StaticCString::create("_get_property_list");
+ strings._property_can_revert = StaticCString::create("_property_can_revert");
+ strings._property_get_revert = StaticCString::create("_property_get_revert");
strings._script_source = StaticCString::create("script/source");
_debug_parse_err_line = -1;
_debug_parse_err_file = "";
@@ -2213,9 +2318,13 @@ GDScriptLanguage::GDScriptLanguage() {
GLOBAL_DEF("debug/gdscript/warnings/treat_warnings_as_errors", false);
GLOBAL_DEF("debug/gdscript/warnings/exclude_addons", true);
for (int i = 0; i < (int)GDScriptWarning::WARNING_MAX; i++) {
- String warning = GDScriptWarning::get_name_from_code((GDScriptWarning::Code)i).to_lower();
- bool default_enabled = !warning.begins_with("unsafe_");
- GLOBAL_DEF("debug/gdscript/warnings/" + warning, default_enabled);
+ GDScriptWarning::Code code = (GDScriptWarning::Code)i;
+ Variant default_enabled = GDScriptWarning::get_default_value(code);
+ String path = GDScriptWarning::get_settings_path_from_code(code);
+ GLOBAL_DEF(path, default_enabled);
+
+ PropertyInfo property_info = GDScriptWarning::get_property_info(code);
+ ProjectSettings::get_singleton()->set_custom_property_info(path, property_info);
}
#endif // DEBUG_ENABLED
}
@@ -2258,13 +2367,13 @@ void GDScriptLanguage::add_orphan_subclass(const String &p_qualified_name, const
}
Ref<GDScript> GDScriptLanguage::get_orphan_subclass(const String &p_qualified_name) {
- Map<String, ObjectID>::Element *orphan_subclass_element = orphan_subclasses.find(p_qualified_name);
+ HashMap<String, ObjectID>::Iterator orphan_subclass_element = orphan_subclasses.find(p_qualified_name);
if (!orphan_subclass_element) {
return Ref<GDScript>();
}
- ObjectID orphan_subclass = orphan_subclass_element->get();
+ ObjectID orphan_subclass = orphan_subclass_element->value;
Object *obj = ObjectDB::get_instance(orphan_subclass);
- orphan_subclasses.erase(orphan_subclass_element);
+ orphan_subclasses.remove(orphan_subclass_element);
if (!obj) {
return Ref<GDScript>();
}
@@ -2273,7 +2382,7 @@ Ref<GDScript> GDScriptLanguage::get_orphan_subclass(const String &p_qualified_na
/*************** RESOURCE ***************/
-RES ResourceFormatLoaderGDScript::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
+Ref<Resource> ResourceFormatLoaderGDScript::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
if (r_error) {
*r_error = ERR_FILE_CANT_OPEN;
}
@@ -2316,8 +2425,8 @@ String ResourceFormatLoaderGDScript::get_resource_type(const String &p_path) con
}
void ResourceFormatLoaderGDScript::get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types) {
- FileAccessRef file = FileAccess::open(p_path, FileAccess::READ);
- ERR_FAIL_COND_MSG(!file, "Cannot open file '" + p_path + "'.");
+ Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::READ);
+ ERR_FAIL_COND_MSG(file.is_null(), "Cannot open file '" + p_path + "'.");
String source = file->get_as_utf8_string();
if (source.is_empty()) {
@@ -2334,38 +2443,37 @@ void ResourceFormatLoaderGDScript::get_dependencies(const String &p_path, List<S
}
}
-Error ResourceFormatSaverGDScript::save(const String &p_path, const RES &p_resource, uint32_t p_flags) {
+Error ResourceFormatSaverGDScript::save(const Ref<Resource> &p_resource, const String &p_path, 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);
+ {
+ Error err;
+ Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::WRITE, &err);
- ERR_FAIL_COND_V_MSG(err, err, "Cannot save GDScript file '" + p_path + "'.");
+ ERR_FAIL_COND_V_MSG(err, err, "Cannot save GDScript file '" + p_path + "'.");
- file->store_string(source);
- if (file->get_error() != OK && file->get_error() != ERR_FILE_EOF) {
- memdelete(file);
- return ERR_CANT_CREATE;
+ file->store_string(source);
+ if (file->get_error() != OK && file->get_error() != ERR_FILE_EOF) {
+ 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);
+ GDScriptLanguage::get_singleton()->reload_tool_script(p_resource, true);
}
return OK;
}
-void ResourceFormatSaverGDScript::get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const {
+void ResourceFormatSaverGDScript::get_recognized_extensions(const Ref<Resource> &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 {
+bool ResourceFormatSaverGDScript::recognize(const Ref<Resource> &p_resource) const {
return Object::cast_to<GDScript>(*p_resource) != nullptr;
}