Saving & Loading

Obviously, many games require the ability to save and load!

📜 Content

1. Built-in Saving

The saving subsystem allows you to save and load Dialogic timeline states, game thumbnails (screenshots), and extra information to Savegame slots.
You want to save the player position or the last seen text? The built-in save system has it all covered!

Be aware that Savegames uses their name as a folder name; operating systems restrict the allowed characters for folder names. It's recommended to rely on the Latin alphabet, numbers, and underscores.

If you don't care about Savegame slots, you can do the following:

# Example signal handling.
func _on_save_game_button_pressed() -> void:
    Dialogic.Save.save()

func _on_load_game_button_pressed() -> void:
    Dialogic.Save.load()

However, these methods will take screenshots too, which may affect performance slightly.
If you want to prevent this from happening, it gets a bit more verbose:

# Example signal handling.
func _on_save_game_button_pressed() -> void:
    Dialogic.Save.save("", false, Dialogic.Save.ThumbnailMode.NONE)

func _on_load_game_button_pressed() -> void:
    Dialogic.Save.load()

1.1 Take a thumbnail

If you would like to use thumbnails per Savegame slot, it's recommended to take the screenshot before opening your Save & Load layer.
This can be achieved by calling Dialogic.Save.take_thumbnail() before you show the layer; for instance, in the button signal connection, open the layer.

If you go this route, you need to instruct the Dialogic.Save.save(...) method to store only and not take a screenshot.

Dialogic.Save.save(slot_name_variable, false, Dialogic.Save.ThumbnailMode.STORE_ONLY, slot_extra_info)

This snippet will automatically take the thumbnail saved at Dialogic.Save.latest_thumbnail and use it.

1.2 Saving Extra Info

By default, Savegames contain information about Dialogic's timeline and Dialogic variables. If you want to store specific information about a Savegame, we can achieve this by using Dialogic.Save.set_slot_info(slot_name:String, info: Dictionary) and Dialogic.Save.get_slot_info(slot_name: String) methods.
However, the Dialogic.Save.save(...) method can simplify our work and skip calling the set method.

Extra information is not loaded into the Dialogic state info. In other words, it solely serves to provide information about a Savegame.

In the following code snippet, we will save the last used text line and the current time as extra information.

var extra_info := {}
extra_info["text"] = Dialogic.current_state_info["text"]
extra_info["date"] = Time.get_datetime_string_from_system(false, true)

Dialogic.Save.save(slot_name, false, Dialogic.Save.ThumbnailMode.STORE_ONLY, extra_info)

1.2.1 Accessing Extra Info

Now, if you want to display your Savegames on your custom Savegame layer, you can access them via Dialogic.Save.get_slot_info.

Here is an example on how to access a specific Savegame's extra data:

# Safety check, whether our Savegame even exists.
if Dialogic.Save.has_slot(save_game_name):
     var slot_info_dictionary := Dialogic.Save.get_slot_info(save_game_name)
     var date: String = slot_info_dictionary.get("date", "")
     var text: String = slot_info_dictionary.get("text", "")

This example checks if a Savegame save_game_name exists and if so, gets its extra data. From there on, you are free to do anything with the data. For instance, display it on your custom Savegame layer.

1.3 Global data

The simple approach to storing your game data slot-independently is to use the Dialogic.Settings subsystem.
You can directly store the information on it:

Dialogic.Settings.text_speed = 0.05

On save, the data will be automatically stored in the global save file

However, if you want to write to the global save file directly, you can use the Dialogic.Save subsystem:

func set_player_name(name: String) -> void:
    # Setting a name for the key `player_name`.
    Dialogic.Save.set_global_info("player_name", name)

There is no rule for the global info key's value; being consistent is good, though.

If you are interested in storing the history of visited texts, take a look at the next chapter.

1.4 Saving Visited Events

When you play a visual novel and use multiple saves, you may find yourself discovering texts you already read, even on entirely different story branches.
By default, Dialogic does not save the events players have already visited; however, there are two main ways to get it working.

  1. The first approach is via the Dialogic Editor. Head to the Settings tab and select History. From here on, you can decide if you want the already-visited events must auto-save.

  2. This approach is a bit different: The following snippet will manually save the history to a file. Use this in case the player has reached the end of the game (credits?) and you want to ensure that the visited events are properly updated a last time.

var slot_name := "slot-3-page-2"

func _save_game() -> void:
     Dialogic.History.save_visited_history()
     Dialogic.Save.save(slot_name)

func _load_game() -> void:
     Dialogic.History.load_visited_history()
     Dialogic.Save.load(slot_name)

func _reset_visited_history() -> void:
     Dialogic.History.reset_already_visited_history()

If you prefer to set the configuration via code, take a look at the following snippet:

func _ready() -> void:
    Dialogic.History.save_already_visited_history_on_save = true
    Dialogic.History.save_already_visited_history_on_autosave = true

The example values will cause the visited event history to automatically save on Auto-Save and normal Saves.

2. Handling Savegame Slots

A save game slot is identified by its slot name, a unique word that you, as a developer, decide.
One way to name the slots could be by their index and the current save game page (if you intend to have many save games). This could result in slots named slot_3_page_4.

2.1 Check if a Savegame Slot exists

When you create your own save/load layer, you may want to check whether any of these slots even exist.

func load_save_game_slot(slot_name: String) -> void:
    if Dialogic.Save.has_slot(slot_name):
        # Do your logic...

However, you may also use Dialogic.Save.add_empty_slot(slot_name: String) and populate the missing slots. If you check using the snippet, it's not necessary at all, though.

2.2 Delete a Savegame Slot

You can delete a save game slot by using the Dialogic.Save.delete_slot(slot_name: String) method.

3. Manual Saving

If you want to roll your own save and load system, you can use Dialogic.get_full_state() -> Dictionary to get the state of Dialogic and then continue saving it the way you want to.
Once you are read to load the data back, you will have to use Dialogic.load_full_state(state: Dictionary) to get your data back into Dialogic.

Overall, it's better to have an idea why you want to do manual saving and take inspiration from Dialogic's save and load methods.
There is a chance that Dialogic already supports your specific loading and saving requirements.