godotengine / godot

Godot Engine – Multi-platform 2D and 3D game engine
https://godotengine.org
MIT License
91.39k stars 21.26k forks source link

Existence of Static Function Prevents Access of Unrelated Static Variable #98374

Open BluntBSE opened 1 month ago

BluntBSE commented 1 month ago

Tested versions

Reproducible in 4.2stable, 4.3 stable

System information

Windows 11 - Godot 4.2stable, Godot 4.3 stable

Issue description

I truly do not know why this is the case, but in my project the very existence of the below code causes a crash when attempting to access an unrelated static variable. This function is not called before the crash occurs.

class_name CardHelpers
...
static func arrow_to_target_k(origin:CardStub, target:PilotButton)->void:
    #TODO: Add color and/or texture as arguments
    var arrow:TargetArrow = load("res://engine/common/ui_scenes/target_arrow.tscn").instantiate()
    origin.add_child(arrow)
    arrow.unpack(origin.global_position, target.global_position)

The existence of "arrow_to_target_k" causes a crash elsewhere in the project when attempting to access a static variable.

This code:

class_name CardHelpers
....

static func card_by_id(id:String, origin:String)->LogicalCard:
    if origin == "pilot":
        return PilotCardLib.lib[id]

causes the error below:

Invalid access to property or key 'lib' on a base object of type 'GDScript'.

Steps to reproduce

Hit "new game" after running this branch: https://github.com/BluntBSE/ultra_mayor_2/tree/non_crashing_example to see intended behavior

Hit "new game" after running this branch: https://github.com/BluntBSE/ultra_mayor_2/tree/crashing_example

to see the crash

Minimal reproduction project (MRP)

Steps to reproduce not exactly known. Crashing/non crashing branches posted above.

Bugsquad edit: Fix codeblock formatting.

BluntBSE commented 1 month ago

I was able to narrow this down a little further: func arrow_to_target_k(origin:CardStub)->void: pass

This useless function will cause the crash if the function is set to take an argument of the custom class, CardStub. If the function is defined as accepting no arguments, or an argument of type int, it does not crash.

pineapplemachine commented 1 month ago

Are there parsing errors in CardStub? I've encountered similar errors to this that I was able to resolve by fixing errors in the scripts being referenced. It seemed that anything that tried to reference the script with errors sometimes ended up failing to parse, and anything that tried to reference that script and its members, and so on.

HolonProduction commented 1 month ago

Here is a reduced MRP: ultra_mayor_2_reduced.zip

It boils down to a bad resolution order when initializing static variables. PilotLibs static init creates LogicPilots which require PilotCardLibs static vars to be initialized, but we try to init PilotLibs static vars first.

@BluntBSE workaround for you: put a variable var _dummy: PilotCardLib into your main menu to ensure that its static variables are intialized before PilotLib initializes its static vars.

BluntBSE commented 1 month ago

@HolonProduction How are you able to tell which things are initialized first? I suppose I assumed (perhaps naively) that static vars were all sort of initialized on their own before the program started.

Your workaround definitely works, I just don't know how you figured that out. This also suggests to me that it's time to change how all these are stored. I was using this static variable as a placeholder for what should probably be a collection of resources.

cranky-corvid commented 1 month ago

@BluntBSE If you implement static func _static_init() -> void, it will be called whenever the static variables of the class are initialized, so you can check exactly when they're getting initialized and from where.

I don't know all the specifics, but I did previously find that if I load a resource subclass for the first time, regular member variables are initialized first, and only then the static variables.

dalexeev commented 1 month ago

May be related: