Search code examples
godotgdscript

How to get which node invoked getter function?


Is it possible to get which node/object has invoked the setter function?

why am I asking this?

atm I have custom animation player:

tool
extends Animation

func track_insert_key(track_idx : int, time : float, key, transition : float = 1) -> void:
    var track_path=track_get_path(track_idx)
    var key_node=<some_function>.get_node(track_path)
    
    if(key_node.get_class()=="some_node"):
         # do something before setting keyframe

    .track_insert_key(track_idx, time, key, transition)

but I can eliminate the need of a custom animation player if I could intercept who called the getter function, maybe something like this:

tool
extends Node2D

var custom_variable=0 setget ,get_custom_variable

func get_custom_variable(by):
    print("called by=",by)
    if(by.get_class()=="Animation"):
       # do something before setting keyframe

so is anything like this possible? or some similar approach which eliminates the need of a custom AnimationPlayer?


Solution

  • THIS ANSWER DOES NOT WORK ON TOOL SCRIPTS RUNNING ON THE EDITOR


    We cannot exactly get the calling Node, but we can have an idea of the caller.

    We can get an iterate over the stack trace like this:

    var stack := get_stack()
    for item in stack:
        prints(item)
    

    The get_strack function returns an Array that contains a Dictionary per entry of the call stack, with these keys:

    • "function": The name of the calling method.
    • "line": The line number of the call.
    • "source": The path of the calling script.

    So, no, we are not getting the instance that is calling.

    By the way, the first entry (index 0) returned by get_stack corresponds to the call to get_stack. So you want the second entry (index 1). Furthermore, the result will only have one entry if your script is not being called from a script (e.g. the engine is calling a method such as _ready or _process, or it is resuming from yield):

    var stack := get_stack()
    var path_of_the_script := ""
    if stack.size() == 1:
        prints("called from external code")
    else:
        path_of_the_script = stack[1].source
    

    Beyond that, we could look into ProjectSettings.get_setting("_global_script_classes") to find out the name of the class (if it is an script with class_name):

    var stack := get_stack()
    var path_of_the_script := ""
    if stack.size() == 1:
        prints("called from external code")
    else:
        path_of_the_script = stack[1].source
        var class_id := path_of_the_script
        if ProjectSettings.has_setting("_global_script_classes"):
            for x in ProjectSettings.get_setting("_global_script_classes"):
                if x.path == path_of_the_script:
                    class_id = x.class
    
        prints("called from:", class_id)
    

    And that would be the name of the script class that is calling your method, if it has one. Hopefully that is useful enough.