#Unique name access failing

1 messages · Page 1 of 1 (latest)

jagged surge
#

Hi! 👋

I'm a newbie, trying to get https://github.com/Maaack/Godot-Game-Template set up as a starting point after doing a few tutorials. Most of everything appears to be working and I've even been able to add some simple GarageBand audio files without any issue following the instructions.

However, I've run into a specific problem where when I try to access the options menu from the pause menu, I get a NPE on a %UniqueName access. I made several changes between verifying it all worked and discovering it wasn't working, and unfortunately I didn't commit often enough to be able to track it backwards (hubris, yo) to figure out what broke. I feel as if the most likely culprit was me clearing inheritance on all of the actual game scenes that inherited from the base classes in the addons (as Maaack recommends here https://github.com/Maaack/Godot-Game-Template/blob/main/addons/maaacks_game_template/docs/MainMenuSetup.md when moving to actually extend out from the template). However, this cannot be undone (in my case, even thru git), and it feels like a lot of work to redo everything I did, so I came here to ask for help before that.

GitHub

Godot template with a main menu, options menus, pause menu, credits, scene loader, extra tools, and an example game scene. - Maaack/Godot-Game-Template

GitHub

Godot template with a main menu, options menus, pause menu, credits, scene loader, extra tools, and an example game scene. - Maaack/Godot-Game-Template

#

Here's the actual error:

E 0:00:04:778   overlaid_menu_container.gd:10 @ @menu_scene_setter(): Node not found: "%MenuContainer" (relative to "Control").
  <C++ Error>   Method/function failed. Returning: nullptr
  <C++ Source>  scene/main/node.cpp:1878 @ get_node()
  <Stack Trace> overlaid_menu_container.gd:10 @ @menu_scene_setter()
                pause_menu.gd:29 @ open_options_menu()
                pause_menu.gd:63 @ _on_options_button_pressed()

This is overlaid_menu_container, line 10 is start of the for loop on the %MenuContainer access.

@export var menu_scene : PackedScene :
    set(value):
        var _value_changed = menu_scene != value
        menu_scene = value
        if _value_changed:
            for child in %MenuContainer.get_children():
                child.queue_free()
            if menu_scene:
                var _instance = menu_scene.instantiate()
                %MenuContainer.add_child(_instance)

This is pause_menu, line 29 if the first line of the function and line 63 is just the connector for the button that calls the function so I'm excluding it:

func open_options_menu() -> void:
    var options_scene := options_packed_scene.instantiate()
    add_child(options_scene)
    _disable_focus.call_deferred()
    await options_scene.tree_exiting
    _enable_focus.call_deferred()
#

Okay, that's all I can think may be useful, but happy to get more deets if necessary. This is the first time I've asked for help for Godot, so no clue what is useful yet

cerulean gulch
#

it will have something to do with the node(s) to which you've applied this script. They don't have a unique named MenuContainer in their packed scene (probably just as an oversight!). What you've shown us there on the left has a MenuContainer, but I don't see it on the right

#

(PauseMenu, I mean)

jagged surge
#

It's present on MiniOptionsOverlaidMenu but not PauseMenu. However, PauseMenu loads MiniOptionsOverlaidMenu as a PackedScene, and then MiniOptionsOverlaidMenu loads MiniOptionsMenuWithReset in the same method.

I'm not even sure exactly what that means, tbh, but my thought is that means it should be included in the hierarchy and thus accessible, but it just isn't. Obviously that thought is likely wrong, but that's where I'm getting stuck, changing some values around that doesn't seem to do anything and this is kinda hard to google without finding advice just to right click and make unique over and over, haha

cerulean gulch
#

PauseMenu needs a child named MenuContainer before you are allowed to make reference to it. I think you're telling me a story about how it will have a child named MenuContainer after it loads a packed scene? But %MenuContainer.add_child(_instance) actually uses a child of that name, so it's not allowed to be contained in the subtree of _instance.

jagged surge
#

PauseMenu even has a check if the options scene is set before allowing that option to the list of buttons:

func _hide_options_if_unset() -> void:
    if options_packed_scene == null:
        %OptionsButton.hide()
#

That's what my thought is, yeah. But the code that is trying to access it is actually in another file entirely from PauseMenu - does that matter to what you're saying?

#

No, I'm wrong, sorry.

#

Checking

cerulean gulch
#

(actually horrible fun fact, I'm being very specific about "the packed scene that contains it". You're not allowed to use a different packed scene's unique named node at all; it's only unique & accessible with the %percent_syntax for scripts in the same packed scene itself.)

jagged surge
#

Ah, okay, good to know, I didn't realize that and it does invalidate my prior theory. I can articulate the problem again tho

cerulean gulch
#

I have told you the answer! One thing that might help is to print get_node_path() everywhere before you use %MenuContainer in your code

#

one of those lines will print right before it crashes, and that node has your script applied while not being in the same packed scene as a descendent unique node named exactly MenuContainer. No subscenes, no runtime instantiation, etc.

jagged surge
#

What if two scenes have the same-named node that has a unique reference?

cerulean gulch
#

I'm being very specific about "the packed scene that contains it". You're not allowed to use a different packed scene's unique named node at all; it's only unique & accessible with the %percent_syntax for scripts in the same packed scene itself.

#

it's fine, but scripts can't "cross the barrier"

jagged surge
#

OverlaidMenuContainer has a %MenuContainer unique name. MiniOptionsOverlaidMenu inherits from OverlaidMenuContainer and it has its own %MenuContainer in the list of nodes, but for whatever reason, MiniOptionsOverlaidMenu does not actually have its own script, it references the same script the OverlaidMenuContainer script.

So to combine that with what you're saying, the fix should be to add MiniOptionsOverlaidMenu's own script, since if it tries to fallback into the function that exists in the parent script, it will fail because the unique name reference can't be seen by the child at that point. Does that all sound correct?

cerulean gulch
#

yup, that sounds right. You can even reuse the same script as in the parent as long as you attach it again in the child scene so it's evaluated locally

jagged surge
#

attach it again in the child scene

How do I do that? It's currently set in the Inspector in the Godot editor.

I do love me some resused code.

cerulean gulch
#

you set it in the inspector in the godot editor! Sure, it might look the same, but it will have the "reset" circlearrow to revert to the inherited value (, from its ancestor scene, which is in fact the same value :->)

#

btw this is a janky ass edge

#

you may just be facing a bug when inherited scenes are combined with unique names that are not unique in the fully evaluated child.

#

but there's every chance what I'm suggesting could work 😄