Can't access global dictionary

Godot Version

4.3 `

Question

I have created a dictionary (and sub-dictionary) in my global script. My global script is named Setup. It is preloaded correctly because I can access the values.

I can access it in my Main node no problem

print(Setup.chest_map[2]["key_needed"])

However I can’t access it in my Player node, no matter what syntax I try.
As it is global, I thought the same command would work, since Setup variables should be accesible from anywhere.

print(Setup.chest_map[2]["key_needed"])

Can someone please assist me in explaining why I can’t access the globals? As Setup is a script file, I can’t reference a node on the node tree, nor do I think I should have to, it’s global.

this is a bad way of doing things. a bad way of accessing a dictionary and also this dictionary seems to be nested.

chest_map contains a key 2 with a value that is a dictionary, and that contains the key "key_needed" with a value. (what is the value?)
if this is a boolean and you need a bunch of bools to check if a bunch of items exist or not and nothing else, it is better to use a bitmask (layer), as you can store multiple bools in a single int:
item1 1
item2 2
item3 4
item4 8
…16
…32
…64
…128
…etc, this can go very high in a single int.

myitems : int = 0

if item1 and item3 are true, myitems would have a value of 5 (1 + 4).

1 - use the get method when retrieving data from a dictionary, as it is safe. you can define a default value to be returned if the key does not exist.

chest_map.get(2, {}).get("key_needed", false)
first default here is {}, an empty dictionary. the default of the returned dictionary is then false. because if the dictionary doesn’t exist we are returning an empty one, “key_needed” doesn’t exist and it returns false.

2 - do not nest dictionaries. you can use a resource instead or more descriptive names, like "level_1_key_needed".

the problem is if the first dictionary doesn’t have the key you will have a problem, and if the “sub-dictionary” is empty or doesn’t have the key, you will also have a problem.

3 - try printing the dictionary
print(Setup.chest_map)
this would probably return a memory location, so you probably have to iterate and print each value of the dictionary


for i in Setup.chest_map:
    print(i, Setup.chest_map[i])

4 - check if the dictionary is not being altered somewhere else, look at the order of execution. if you are printing at ready of Player, maybe the dictionary hasn’t been filled yet.

1 Like

Are you getting an error?

1 Like

Thanks for the info. Here’s a some more information on my nested dictionaries.

In this game, there are eight different game profiles that can be randomly selected. Each one has the eight chests in it which may or may not require a key to open and may contain other items. This dictionaries, as stated before, are setup in a global script.

var chest1 = {}
var chest2 = {}
var chest3 = {}
var chest4 = {}
var chest5 = {}
var chest6 = {}
var chest7 = {}
var chest8 = {}
var chest_map = {}

Each profile is hard-coded with values for eight chests…

var number_of_game_profiles: int = 8
var sel = 0

func load_game_profile() -> void:
	
	#randomly select which chest map is to be used
	sel = randi_range(0,number_of_game_profiles)
	#print("chest map selected: ", sel)
	
	match sel:
		0:
			chest1["contains"] = "C3"
			chest1["key_needed"] = ""
			chest2["contains"] = "G3"
			chest2["key_needed"] = "K1"
			chest3["contains"] = "FA"
			chest3["key_needed"] = "K1"
            ....etc.

…and then all the chests are loaded into the chest_map dictionary.

chest_map = {1:chest1, 2:chest2, 3:chest3, 4:chest4, 5:chest5, 6:chest6, 7:chest7, 8:chest8}

As all the dictionaries are hand populated during game design, there is no chance of having a blank key or key error.
I do like your suggestion to use ‘get’ as that allows me to simplify my logic for chests that do not require a key.

chest_map.get(2, {}).get("key_needed", false)

In note #4, you state that “maybe the dictionary hasn’t been filled yet”. Won’t the global script run before any other scripts? Remember, the chest_map is readable in the main scene. If my understanding is wrong, how do I ensure that the global script finishes processing before the rest of the scripts start?

And once again, thanks for your insights.

I don’t know why you do this.

chest_map = {1:chest1, 2:chest2, 3:chest3, 4:chest4, 5:chest5, 6:chest6, 7:chest7, 8:chest8}

what is this code? I’m not sure you can just assign a dictionary like that
chest_map = {1 : object}
I think I read an issue in godot proposals recently where they are asking for dictionaries to accept this kind of assignment, and it was denied because it’s not a good idea.

try assigning them one by one, that might solve it, plus it will comply more with the gdscript style guide:

chest_map[1] = chest1
chest_map[2] = chest2

what do you mean by that?
either use an export, or get the data from a file. but this looks bad:

instead, create an autoload with dictionaries and assign them directly:


match sel:
	_:
		chest1 = DataManager.chest_variation_1.duplicate()

1 - autoloads run in the order they appear in globals. maybe your autoloads are not in the correct order.
2 - It depends on when the code is executed. first the tree is created and _ready is run when the script is ready, but there’s also enter_tree, and after that is process.
and autoloads are Nodes too, they will appear if you click on the remote button while running the game.

chest_map = {1:chest1, 2:chest2, 3:chest3, 4:chest4, 5:chest5, 6:chest6, 7:chest7, 8:chest8}

There is nothing syntactically wrong with this code.

Its easy to test the idea:

func _ready() -> void:
	var cow:Dictionary = {"I say":"moo"}
	var sheep:Dictionary = {"I say":"baa"}
	
	var test:Dictionary = {1:cow, 2:sheep}
	printt(test[1]["I say"], test[2]["I say"])

Output:
moo baa

I still say that until we know what the exact problem is, we can’t really help him.
So again I ask the OP, is there an error message?

Thank you everyone for your help.
Sancho2:
The error was:

Invalid access to property or key 'Chest1:<StaticBody2D#30098326799>' on a base object of type 'Array[Node]'.

I have since determined, it wasn’t the access to the dictionary that was the problem, but the syntax of the command I was using.