Resources, data structures, save games, oh my!

Godot Version

4.2.1

Question

Here are some general questions about how I’m structuring my data for in-game consumption and saving/loading states.

I have a bunch of locations in game, say they’re “houses with rooms”. So I have files like house01.gd defined as resource and implementing a dictionary of rooms, in such a way:

extends Resource

const rooms = {

	'kitchen':
		{
		'name':	'Kitchen',
		'floor': 0,
		'visible': true,
		'visible_at_start': true
		},

	'bedroom':
		{
		'name':	'Bedroom',
		'floor': 1,
		'visible': false,
		'visible_at_start': false
		},
...

These are kinda like “config files” or maps for the game.
At the beginning of the game or whenever a player is accessing a given house, I’d do:

var current_location  		    = preload('res://data/house01.gd')

# run some logic
# then...

func draw_rooms(current_location) -> void:
	perform_some_displaying(current_location)

So far it all fits my needs and works, now I’m wanting to save the current game state and load it back.
What I’m NOT currently doing yet is storing the game data anywhere, so I SUPPOSE my first step is to do something like:

func draw_rooms(current_location) -> void:
    perform_some_displaying(current_location)
    # when player enters a room, set it as visible, then:
    var game_state = load('res://data/GameState.tres')
    game_state.add_location_data(current_location.rooms[current_room].visible)

Where GameState is another Resource that would store all the current, ever changing, state of the game.
(Please ignore I’m loading GameState at that point, in reality it happens at script preload time, it’s just here for the sake of readability)
My assumption is that whenever I needed to save or load the game I could just use:

ResourceSaver.save(game_state, save_path)

Now to the questions:

  • is all the above making sense, design-wise, or are there better approaches to this?

  • does house01.gd even need to be a Resource? These are pretty much read-only config files that contain some sort of “map of the game”, I don’t recall why I thought they would need to be resources, but now I’m questioning that :man_facepalming:

  • if I access and change the state of the game via var game_state = load('res://data/GameState.tres') can I just run the same logic from separate scripts and they would all update the same object or do I need to somehow “share” game_state between them?

Thanks!

Hi!

I don’t know about saving, but I can advise about resources. To answer your first two questions, you’re using your resources ineffectively.

What a resource script file should be is a template that you can fill in yourself later on. In this example, I could make a “RoomResource” that contains name, floor, visible and visible at start, and give all of them the export label so I can write them in later on. I could then make a “HouseResource” that contains an array of rooms, again with the export label so I can reuse it. THEN I could create resources directly in Godot and set the properties to what I want!

I believe at the moment the way you’ve done it, because your files are GD files and not resources they won’t save.

I see what you mean.

THEN I could create resources directly in Godot and set the properties to what I want!

I guess that works if I wanted to use the editor to fill in all the per-house data, which I have not intention to.
It takes a lot more time to open the editor, click on UI and fill each field one by one, rather than just doing it using a text editor. Not to mention stuff like copy/paste one room, change one name and one parameter and ctrl+S.

That said, your suggestion would be to define an “empty” HouseResource Resource and then creating multiple instances of it based on each separate location I want to define, correct?
And each house would rely on the existence of a RoomResource Resource, the instances of which would be used inside each house resource to define its contents?

I tinkered a bit with this concept, does the below look like what you’re suggesting?

RoomResource.gd

extends Resource
class_name RoomResource

var name : String
var visible : bool

HouseResource.gd

extends Resource
class_name HouseResource

var rooms:Array = []

func add_room(n, v):
    var room : RoomResource = RoomResource.new() 
    room.name    = n
    room.visible = v

    rooms.append(room)

house_01.gc

var house : HouseResource = HouseResource.new()

# run the following for each room in the house
house.add_room('some name', true/false)


(very much pseudo-code-y, haven’t tested any of that yet)

I can see what you mean, but I use keyboard shortcuts like tab to quickly navigate the inspector to create the items I need to. However, if you don’t want to do that, then you can still use a dictionary to write them then just write some quick script to convert the dictionary into your resource.

Yep! Personally I would have something like a HouseContainerResource to keep a reference to each house, then I could just save and load this one resource instead of having to find them or track them when the save is needed.

I would do `@export house : HouseResource’ and either create a new resource in the inspector to create it “in place”, or create a file for each house in the file editor and link the two together. Does that make sense?

yeah… my secret guilt is developing a game in godot while working almost exclusively in vscode :smiley:
I usually only open the editor when I need to align objects, create/draw UI and stuff like that…
At the moment I make 95% of the game by typing code and launching it from a terminal for testing.

I would do `@export house : HouseResource’ and either create a new resource in the inspector to create it “in place”, or create a file for each house in the file editor and link the two together. Does that make sense?

Yeah it does.
I think the only difference between
var house : HouseResource = HouseResource.new()
and
@export house : HouseResource

is that the latter assumes you’ll use the editor’s UI for defining which resource you’ll put in there, right?