Godot thinks a custom resource is of type string when accessing it by index variable

Godot Version

4.6.1 stable

Question

Hi all,

class_name WeaponsResource
extends Resource

@export var weapons: Array[WeaponType]
const WEAPONS: WeaponsResource = preload("uid://cfw0gxop7hifl")
func select_next_weapon() -> void:
	var current: int = WEAPONS.weapons.find(active_weapon)
	var max: int = WEAPONS.weapons.size() - 1
	current = current + 1 if current + 1 <= max else 0
	if WEAPONS.weapons[0] is WeaponType:
		print("This works")
	if WEAPONS.weapons[current] is WeaponType:
		print("This doesn't")

I’m getting the following error message when using the “current” variable.

Expression is of type "res://resources/weapon_type.gd" so it can't be of type "WeaponType".

What is going on here? I don’t get it.

I solved the issue by doing this, but what the heck?

var next_weapon_data = WEAPONS.weapons[current]
if next_weapon_data is WeaponType:
	select_weapon(next_weapon_data)

Any idea why Godot doesn’t understand this?

Thank you!

Yes. The short answer is that GDScript does not offer the type meta support other languages do.

See this post for more details: Inconsistent Invalid index type for dictionary - #10 by gertkeno

Interesting. However I don’t understand how this explains my example. I’m just replacing a hardcoded 0 with an integer variable to access an array. Why does this change what Godot thinks is inside the array, especially if the array is statically typed?

How is WEAPONS defined? Everything inside your weapons array should be a WeaponType so the is check seems superfluous, Godot should throw an exception if something non-WeaponType is added to the array.

Is this a run time error or compile time?

This code is terrifying and desperately needs parenthesis; max is also a function you may be shadowing. And a modulus should make this better

current = (current + 1) % max
1 Like

Compile time. The error pops up immediately. And yes the array contains only WeaponType resources.

const WEAPONS: WeaponsResource = preload("uid://cfw0gxop7hifl")
class_name WeaponsResource
extends Resource

@export var weapons: Array[WeaponType]

Something ain’t right here. Smells like circular dependencies.

Can you reproduce the error in a minimal example?

1 Like

a const preload for this resource seems strange, I’d remove both in favor of var and load. I’m sure that would fix the error as it’s compille-time

Using var with load does indeed fix the problem, interesting.

Guess I have to learn about load vs preload and when to use them.

preload marks the resource as a dependency for the script, this dependency can cause a lot of trouble that’s hard to narrow down and the only benefit I can think of is with threaded loading. Small, contained resources are a good fit for preload and @export (which similarly marks dependencies). But anything large or with their own dependencies may be better used with load and @export_file (which then must be loaded later in your script).

The benefit of these dependencies will be simplifying threaded loading to one request and get. When exporting the game you may be able to leverage a special export setting to “export selected scenes and their dependencies” yet this will still require tweaking even with the most dependent of dependency graphs.

1 Like