Browse Source

Merge pull request #62255 from vnen/gdscript-implicit-onready

GDScript: Use implicit method for @onready variables
Rémi Verschelde 3 years ago
parent
commit
56b8d579b2
3 changed files with 39 additions and 13 deletions
  1. 20 0
      modules/gdscript/gdscript.cpp
  2. 1 0
      modules/gdscript/gdscript.h
  3. 18 13
      modules/gdscript/gdscript_compiler.cpp

+ 20 - 0
modules/gdscript/gdscript.cpp

@@ -1254,6 +1254,14 @@ GDScript::~GDScript() {
 		memdelete(E.value);
 		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.
 	if (GDScriptCache::singleton) { // Cache may have been already destroyed at engine shutdown.
 		GDScriptCache::remove_script(get_path());
 		GDScriptCache::remove_script(get_path());
 	}
 	}
@@ -1541,6 +1549,18 @@ 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) {
 Variant GDScriptInstance::callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
 	GDScript *sptr = script.ptr();
 	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) {
 	while (sptr) {
 		HashMap<StringName, GDScriptFunction *>::Iterator E = sptr->member_functions.find(p_method);
 		HashMap<StringName, GDScriptFunction *>::Iterator E = sptr->member_functions.find(p_method);
 		if (E) {
 		if (E) {

+ 1 - 0
modules/gdscript/gdscript.h

@@ -120,6 +120,7 @@ class GDScript : public Script {
 
 
 	GDScriptFunction *implicit_initializer = nullptr;
 	GDScriptFunction *implicit_initializer = nullptr;
 	GDScriptFunction *initializer = nullptr; //direct pointer to new , faster to locate
 	GDScriptFunction *initializer = nullptr; //direct pointer to new , faster to locate
+	GDScriptFunction *implicit_ready = nullptr;
 
 
 	int subclass_count = 0;
 	int subclass_count = 0;
 	RBSet<Object *> instances;
 	RBSet<Object *> instances;

+ 18 - 13
modules/gdscript/gdscript_compiler.cpp

@@ -1990,18 +1990,18 @@ GDScriptFunction *GDScriptCompiler::_parse_function(Error &r_error, GDScript *p_
 
 
 	// Parse initializer if applies.
 	// Parse initializer if applies.
 	bool is_implicit_initializer = !p_for_ready && !p_func && !p_for_lambda;
 	bool is_implicit_initializer = !p_for_ready && !p_func && !p_for_lambda;
-	bool is_initializer = p_func && !p_for_lambda && String(p_func->identifier->name) == GDScriptLanguage::get_singleton()->strings._init;
-	bool is_for_ready = p_for_ready || (p_func && !p_for_lambda && String(p_func->identifier->name) == "_ready");
+	bool is_initializer = p_func && !p_for_lambda && p_func->identifier->name == GDScriptLanguage::get_singleton()->strings._init;
+	bool is_implicit_ready = !p_func && p_for_ready;
 
 
-	if (!p_for_lambda && (is_implicit_initializer || is_for_ready)) {
+	if (!p_for_lambda && (is_implicit_initializer || is_implicit_ready)) {
 		// Initialize class fields.
 		// Initialize class fields.
 		for (int i = 0; i < p_class->members.size(); i++) {
 		for (int i = 0; i < p_class->members.size(); i++) {
 			if (p_class->members[i].type != GDScriptParser::ClassNode::Member::VARIABLE) {
 			if (p_class->members[i].type != GDScriptParser::ClassNode::Member::VARIABLE) {
 				continue;
 				continue;
 			}
 			}
 			const GDScriptParser::VariableNode *field = p_class->members[i].variable;
 			const GDScriptParser::VariableNode *field = p_class->members[i].variable;
-			if (field->onready != is_for_ready) {
-				// Only initialize in _ready.
+			if (field->onready != is_implicit_ready) {
+				// Only initialize in @implicit_ready.
 				continue;
 				continue;
 			}
 			}
 
 
@@ -2123,6 +2123,8 @@ GDScriptFunction *GDScriptCompiler::_parse_function(Error &r_error, GDScript *p_
 		p_script->initializer = gd_function;
 		p_script->initializer = gd_function;
 	} else if (is_implicit_initializer) {
 	} else if (is_implicit_initializer) {
 		p_script->implicit_initializer = gd_function;
 		p_script->implicit_initializer = gd_function;
+	} else if (is_implicit_ready) {
+		p_script->implicit_ready = gd_function;
 	}
 	}
 
 
 	if (p_func) {
 	if (p_func) {
@@ -2140,7 +2142,7 @@ GDScriptFunction *GDScriptCompiler::_parse_function(Error &r_error, GDScript *p_
 #endif
 #endif
 	}
 	}
 
 
-	if (!p_for_lambda) {
+	if (!is_implicit_initializer && !is_implicit_ready && !p_for_lambda) {
 		p_script->member_functions[func_name] = gd_function;
 		p_script->member_functions[func_name] = gd_function;
 	}
 	}
 
 
@@ -2208,11 +2210,19 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, const GDScriptPar
 	for (const KeyValue<StringName, GDScriptFunction *> &E : p_script->member_functions) {
 	for (const KeyValue<StringName, GDScriptFunction *> &E : p_script->member_functions) {
 		memdelete(E.value);
 		memdelete(E.value);
 	}
 	}
+	if (p_script->implicit_initializer) {
+		memdelete(p_script->implicit_initializer);
+	}
+	if (p_script->implicit_ready) {
+		memdelete(p_script->implicit_ready);
+	}
 	p_script->member_functions.clear();
 	p_script->member_functions.clear();
 	p_script->member_indices.clear();
 	p_script->member_indices.clear();
 	p_script->member_info.clear();
 	p_script->member_info.clear();
 	p_script->_signals.clear();
 	p_script->_signals.clear();
 	p_script->initializer = nullptr;
 	p_script->initializer = nullptr;
+	p_script->implicit_initializer = nullptr;
+	p_script->implicit_ready = nullptr;
 
 
 	p_script->tool = parser->is_tool();
 	p_script->tool = parser->is_tool();
 	p_script->name = p_class->identifier ? p_class->identifier->name : "";
 	p_script->name = p_class->identifier ? p_class->identifier->name : "";
@@ -2456,15 +2466,10 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, const GDScriptPar
 Error GDScriptCompiler::_parse_class_blocks(GDScript *p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state) {
 Error GDScriptCompiler::_parse_class_blocks(GDScript *p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state) {
 	//parse methods
 	//parse methods
 
 
-	bool has_ready = false;
-
 	for (int i = 0; i < p_class->members.size(); i++) {
 	for (int i = 0; i < p_class->members.size(); i++) {
 		const GDScriptParser::ClassNode::Member &member = p_class->members[i];
 		const GDScriptParser::ClassNode::Member &member = p_class->members[i];
 		if (member.type == member.FUNCTION) {
 		if (member.type == member.FUNCTION) {
 			const GDScriptParser::FunctionNode *function = member.function;
 			const GDScriptParser::FunctionNode *function = member.function;
-			if (!has_ready && function->identifier->name == "_ready") {
-				has_ready = true;
-			}
 			Error err = OK;
 			Error err = OK;
 			_parse_function(err, p_script, p_class, function);
 			_parse_function(err, p_script, p_class, function);
 			if (err) {
 			if (err) {
@@ -2498,8 +2503,8 @@ Error GDScriptCompiler::_parse_class_blocks(GDScript *p_script, const GDScriptPa
 		}
 		}
 	}
 	}
 
 
-	if (!has_ready && p_class->onready_used) {
-		//create a _ready constructor
+	if (p_class->onready_used) {
+		// Create an implicit_ready constructor.
 		Error err = OK;
 		Error err = OK;
 		_parse_function(err, p_script, p_class, nullptr, true);
 		_parse_function(err, p_script, p_class, nullptr, true);
 		if (err) {
 		if (err) {