Passing save file resources through network?

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

So, i just finalized the structure of my game, and i managed to use Resource as save file: each node with data to be saved owns a custom made resources, which contains all the export var needed, that are saved locally (server side) with ResourceSaver
It works flawlessy and it is super fast both to save and load, even with thousands of resources in game.

The game is supposed to be multiplayer, and i need the ability to share those custom made resources between server and client using NetworkedMultiplayerENet.
However, if i send a rpc call with a resource as argoument, the client will receive the simple resource object ID, not the actual resource content.

I found this scary post:
https://forum.godotengine.org/15457/what-the-best-way-share-resources-between-server-and-client

Is there a way to achieve this?
Please tell me i dont have to start all over

:bust_in_silhouette: Reply From: Wakatta

Ok let’s ignore those scary people.

Firstly you’ll want to use inst2dict() on your server side then encrypt that data and send it to the client where you use dict2inst() and add_child() to reconstruct or duplicate the tree structure.

Words of caution

When using the above method there are some values that you will have to replace…i.e if your instance is a node derivative then the nodepath and node name need extra attention

If your resource is a binary file like an image simply convert it to a PoolByteArray then repeat the above.

that’s it, one day spent searching online and found nothing, and there was a single function that did what i needed.
Thank you!!

I think it should work, but i tried right now by simply replacing rpc("function", resource) with rpc("function", inst2dic(resource)) and it did not work, i suppose because my single save file resource is actually nested (the “main save file” contains a dictionary of resources for each object of the game).

Before start working on a way to break down each resource to a dictionary, is there a built in function to inst2dic nested resources?

Andrea | 2021-09-28 17:22

Is there a built in function to inst2dic nested resources?

Hmm that’s quite tricky, not to my knowledge and also ints2dict may only save the resource itself and all it’s members excluding additional (nested) instances.

I think it should work, but i tried right now by simply replacing and it did not work

quite odd. Is any data even being sent?

Wakatta | 2021-09-28 23:16

Sorry i was too generic in my comment: it works, the data is sent and the resource correctly reconstructed on client side, but as soon as the client start opening one of the nested resources, it stops because this second layer has not been transformed in a dictionary (again, only the object id is passed).
So i basically shifted the problem to the second layer of nested resources.

I was hoping there was a way to serialize a resource completely in a dictionary, because Godot is already able to do it with ResourceSaver in a file, but I suppose i will have to change the save structure and send the client each resource individually with inst2dict

Andrea | 2021-09-29 06:53

Or another option you can go with is saving then sending the file itself

Wakatta | 2021-09-29 09:50

If that’s possible it would solve everything!
I can’t find much information on the topic, how i am suppose to send it? Will inst2dict still work? Or can I send the file directly as argument?

Andrea | 2021-09-29 10:12

Solved! i passed the file as an argument using get_buffer()
Basically, on server:

func save_on_server():
  ResourceSaver.save(resource_used_as_savefile, path)
  var file=File.new()
  file.open(path, File.READ)
  rpc(load_on_client(file.get_buffer(file.get_len()))
  file.close()

on client:

func load_on_client(buffer):
 var file=File.new()
 file.open(path_to_temp, File.WRITE)
 file.store_buffer(buffer)
 file.close()
 resource_used_as_savefile=load(path_to_temp)

Note: path_to_temp points to a file that doesnt have to necessarely exist.
Note2: the file has the .res extensions, it works with .tres as well (using get_as_text() and store_string() instead of buffer, but it seems slower to me)

Thanks Wakatta for your suggestions!

Andrea | 2021-10-02 11:01