From 99b702ea3d12952b842055a4d5d4b1928ed69186 Mon Sep 17 00:00:00 2001 From: George Marques Date: Tue, 30 Apr 2024 11:50:10 -0300 Subject: [PATCH] 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. --- modules/gdscript/gdscript.cpp | 23 +++++++++++-------- modules/gdscript/gdscript.h | 2 ++ .../features/onready_base_before_subclass.gd | 18 +++++++++++++++ .../features/onready_base_before_subclass.out | 3 +++ 4 files changed, 36 insertions(+), 10 deletions(-) create mode 100644 modules/gdscript/tests/scripts/runtime/features/onready_base_before_subclass.gd create mode 100644 modules/gdscript/tests/scripts/runtime/features/onready_base_before_subclass.out diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp index f238958f259..73abf71bde4 100644 --- a/modules/gdscript/gdscript.cpp +++ b/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::Iterator E = sptr->member_functions.find(p_method); diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h index 7bd68ac0b17..51267ecb840 100644 --- a/modules/gdscript/gdscript.h +++ b/modules/gdscript/gdscript.h @@ -365,6 +365,8 @@ class GDScriptInstance : public ScriptInstance { SelfList::List pending_func_states; + void _call_implicit_ready_recursively(GDScript *p_script); + public: virtual Object *get_owner() { return owner; } diff --git a/modules/gdscript/tests/scripts/runtime/features/onready_base_before_subclass.gd b/modules/gdscript/tests/scripts/runtime/features/onready_base_before_subclass.gd new file mode 100644 index 00000000000..99156adb286 --- /dev/null +++ b/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() diff --git a/modules/gdscript/tests/scripts/runtime/features/onready_base_before_subclass.out b/modules/gdscript/tests/scripts/runtime/features/onready_base_before_subclass.out new file mode 100644 index 00000000000..b417ce67cae --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/features/onready_base_before_subclass.out @@ -0,0 +1,3 @@ +GDTEST_OK +a +b