ellis-matthew4 / XDL

A JSON-based dialogue system that uses a simple scripting language based on RenPy
12 stars 1 forks source link

Serialization function improvement #8

Closed ellis-matthew4 closed 5 years ago

ellis-matthew4 commented 5 years ago

This thread is to come up with a better serialization function. The main problem with the current one is that it serializes the whole stack. One possible workaround is to save just the current line, current script, and current label, then call the label upon load and quickly iterate through each line until a match is found. However, this does not work well in Godot because Dictionaries aren't meant to be directly compared.

realkotob commented 5 years ago

Why not use the id/key of the line? Then it can be called directly instead of searching for it.

ellis-matthew4 commented 5 years ago

@asheraryam This could also work, but if the dialogue file is changed, then the key could be wrong. Another problem is any lower layers of the stack need to be serialized as well. Just thinking to myself here: maybe create a state model of the stack that updates upon call() and return?

realkotob commented 5 years ago

If the dialogue file changes, then I think these approaches would have issues as well.

That's why just take the simplest approach and save the key/id of the line, and if needed later for backwards compatibility, read the version number of the save file and convert it. e.g. instead of going to going to line 12, go to line 2 on a different scene.

A lot of things can go wrong with saving the stack. What if you add a DLC update that adds new content, then trying to go back through the stack and reloading the save file might lead the players to be somewhere else!

In roguelikes they usually only save the seed for the world and they use it to procedurally generate the world instead of saving everything, which has worked for decades and everyone does it now too, but this breaks between every few versions when new content is added to the world generation code.

Backwards compatibility issues are still a major issue in all games and software with no silver bullet, it's just case-by-case fixes. That's why I suggest using a simple solid cheap approach (saving the line ID) which should work for most cases.

One easy way to keep things backwards compatible without too much effort, you can have the key/ID of the lines be separate from their position and order, so if you delete line 4, line 5 still has the key 5, so the keys would be 1-2-3-5 and loading the save game would still work. If the game was saved at line 4, then I guess just go to the line directly before it (3). The godot engine recently was fixed to save the IDs of the assets this way, so if you remove one asset from a scene it would not change all the other IDs (it used to save the IDs using the asset order which means all the IDs were changed if an asset at the top was removed).

This won't work in all cases of course, such as when you add entirely new scenes and reroute the dialogue trees completely, in which case you'll need the regular old if-statements for version number.

ellis-matthew4 commented 5 years ago

This is definitely an interesting idea, I'll have to keep it in mind. I will have to save the stack in some form or other, however. Otherwise, the game wouldn't be able to remember the context of the current scene, so when the current scene ends, the game won't have anywhere to go. Example: label1 is 15 lines long, label2 is 15 lines long label1 calls label2 on label1-line10, saving label1-lines[11:15] to the stack and pushing label2 assume we save the game on lable2-line14 If the stack isn't saved, the game loads a stack containing only label2-lines[14:15] One solution would be to have a list/dictionary model of the stack, formatted as [ 0: { "labelName" : lineNumber }, 1: { "labelName" : lineNumber, ... ]

ellis-matthew4 commented 5 years ago

Update to the problem: The solution to stack serialization I posted a few hours ago does not account for anonymous labels created by menus. If the player tried to save in a branch created by a menu, the save would be invalid. This could be resolved by removing anonymity by changing menu syntax to something like: menu:\n \toption "Menu option here": <call | jump> <labelName> Rather than what we have now: menu:\n \toption "Menu option here":\n \t\tblah "blah blah"\n \t\treturn

ellis-matthew4 commented 5 years ago

Final solution, will be included in the next update: I am removing anonymous labels and the new option syntax mentioned before will be adopted.