How do I use a custom resource that's been saved by ResourceSaver.save?

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By Phasers

My current method doesn’t work but I’m not really sure why

I am saving a custom resource like this:

var w = GameWorld.new(100, 100)
w.add_new_world_item(GROUND_TILE_TYPES[0], Vector2(1, 1))
ResourceSaver.save("res://saves/world_2.tres", w)

GameWorld is a custom resource which looks like this:

extends Resource
class_name GameWorld, "res://world/world_icon.png"

export(int) var width: int = 100
export(int) var height: int = 100

export(Array, Vector2) var gates := []
export(Dictionary) var world_items = {}
export(Array) var world_item_ids = []

func _init(width: int, height: int):
	self.width = width
	self.height = height
	self.gates = get_gate_positions_from_dimensions(width, height)
	self.world_items = {}
	self.world_item_ids = []

func add_new_world_item(type, position) -> void:
...

And world_items in GameWorld is a dictionary int → WorldItem which is another CustomResource (no idea if that makes a difference)

The world is correctly saved here:
enter image description here

The contents of this look like:

[gd_resource type="Resource" load_steps=5 format=2]

[ext_resource path="res://world/game_world.gd" type="Script" id=1]
[ext_resource path="res://game/vegetation/item_types/grass_1.tres" type="Resource" id=2]
[ext_resource path="res://world/world_item.gd" type="Script" id=3]

[sub_resource type="Resource" id=1]
script = ExtResource( 3 )
world_item_type = ExtResource( 2 )
position = Vector2( 1, 1 )

[resource]
script = ExtResource( 1 )
width = 100
height = 100
gates = [ Vector2( 50, 0 ), Vector2( 50, 100 ) ]
world_items = {
0: SubResource( 1 )
}
world_item_ids = [ 0 ]

I then have a node which takes in a GameWorld as an exported variable:
enter image description here

And drag world_2 to it like so:
enter image description here

But when running and trying to access world like this I get all kinds of errors which basically amount to world not being an instance of GameWorld

When I call world.get_script() it returns [Object:null] but if I call it on a newly created GameWorld (via GameWorld.new(…)) I get [GDScript:1239]

And none of the properties/methods are there: print(world.world_items) fails with Invalid get index 'world_items' (on base: 'Resource').

I don’t really understand why I this isn’t working; especially because I can generate GameWorld at runtime and populate it but when I try and load it from a .tres file it doesn’t think it’s a GameWorld anymore? Am I just being dumb?

:bust_in_silhouette: Reply From: spaceyjase

I think this is failing because the _init method has no default values; godot doesn’t know how to create your object because it doesn’t understand width and height. This would usually create an error in the debugger (see below). Note here:

Make sure that every parameter has a default value. Otherwise, there will be problems with creating and editing your resource via the inspector.

If you change your _init method to the following, it should work:

func _init(w: int = 100, h: int = 100):    # note default values

(the error in the debugger may look like E 0:00:01.012 _create_instance: Condition "r_error.error != Variant::CallError::CALL_OK" is true. Returned: nullptr <C++ Source> modules/gdscript/gdscript.cpp:115 @ _create_instance()).

Yes! Thank you, it took me another few hours to figure out that it was to do with the init constructor, after recreating a bare-minimum example and slowly breaking it. Though I didn’t realise initial values would fix it.

I was getting an entirely different error in the Godot console though

ERROR: Condition "r_error.error != Variant::CallError::CALL_OK" is true. Returned: nullptr

Which was an extremely unhelpful message.

Many thanks!!

Phasers | 2021-11-22 19:58