浏览代码

GDScript: Call implicit ready on base script first

It is generally expected that the base class is called before the
inherited clas. This commit implements this behavior for the implicit
ready function (`@onready` annotation) to make it consistent with the
expectations.
George Marques 1 年之前
父节点
当前提交
99b702ea3d

+ 13 - 10
modules/gdscript/gdscript.cpp

@@ -1958,19 +1958,22 @@ int GDScriptInstance::get_method_argument_count(const StringName &p_method, bool
 	return 0;
 }
 
+void GDScriptInstance::_call_implicit_ready_recursively(GDScript *p_script) {
+	// Call base class first.
+	if (p_script->_base) {
+		_call_implicit_ready_recursively(p_script->_base);
+	}
+	if (p_script->implicit_ready) {
+		Callable::CallError err;
+		p_script->implicit_ready->call(this, nullptr, 0, err);
+	}
+}
+
 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();
+		// Call implicit ready first, including for the super classes recursively.
+		_call_implicit_ready_recursively(sptr);
 	}
 	while (sptr) {
 		HashMap<StringName, GDScriptFunction *>::Iterator E = sptr->member_functions.find(p_method);

+ 2 - 0
modules/gdscript/gdscript.h

@@ -365,6 +365,8 @@ class GDScriptInstance : public ScriptInstance {
 
 	SelfList<GDScriptFunctionState>::List pending_func_states;
 
+	void _call_implicit_ready_recursively(GDScript *p_script);
+
 public:
 	virtual Object *get_owner() { return owner; }
 

+ 18 - 0
modules/gdscript/tests/scripts/runtime/features/onready_base_before_subclass.gd

@@ -0,0 +1,18 @@
+#GH-63329
+class A extends Node:
+	@onready var a := get_value("a")
+
+	func get_value(var_name: String) -> String:
+		print(var_name)
+		return var_name
+
+class B extends A:
+	@onready var b := get_value("b")
+
+	func _ready():
+		pass
+
+func test():
+	var node := B.new()
+	node._ready()
+	node.free()

+ 3 - 0
modules/gdscript/tests/scripts/runtime/features/onready_base_before_subclass.out

@@ -0,0 +1,3 @@
+GDTEST_OK
+a
+b