# Infinite Save Scripting

## Step 1: Create a Script

Create a script or multiple scripts that will handle all save menu functionality.

For this example, we will create a single script called `InfiniteSavesExample.cs`.

Start the script by adding the member variables that can be set from the inspector.

```csharp
public class InfiniteSavesExample : MonoBehaviour
{
    [SerializeField]
    private Button saveSlotPrefab;
    
    [SerializeField]
    private Button saveSlotCreator;
    
    [SerializeField]
    private Transform content;
    
    [SerializeField]
    private Text timeElapsedText;
    
    [SerializeField]
    private Toggle modeToggle;
}
```

Remember to add a GameObject to the scene and add this script to it. At this point, we should have everything to populate the inspector properties.

<figure><img src="https://1507369417-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FkorEE1oahhwAkGIn7ek0%2Fuploads%2FBd4zVH2gnDuPJKZ5jG4p%2Fimage.png?alt=media&#x26;token=2d05528e-c801-4773-8538-f926dbce1b11" alt=""><figcaption></figcaption></figure>

### Properties

**Save Slot Prefab:** the save slot button prefab.

**Save Slot Creator:** the button that will create a new save.

**Content:** the scroll view's content object.

**Time Elapsed Text:** the text object that will display the time elapsed.

**Mode Toggle:** the toggle that will toggle the mode between load and save mode.

## Step 2: Other Script Members

We will create other members that won't be visible in the inspector.

```csharp
public class InfiniteSavesExample : MonoBehaviour
{
        private const string timeElapsedKey = "TimeElapsed";

        [SerializeField]
        private Button saveSlotPrefab;
        
        [SerializeField]
        private Button saveSlotCreator;
        
        [SerializeField]
        private Transform content;
        
        [SerializeField]
        private Text timeElapsedText;
        
        [SerializeField]
        private Toggle modeToggle;

        private List<Button> slots = new();

        private float timeElapsed;

        private bool loadMode { get => modeToggle.isOn; }
}
```

**timeElapsedKey:** the key (or ID) of the time elapsed for saving purposes.

**slots:** a list of buttons that will store all of the instantiated save slots.

**timeElapsed:** the time elapsed as a float.

**loadMode:** the isOn value of the toggle.

If load mode is true, we will make the save slots load a save. If it's false (save mode), we will make the save slots overwrite a save.

## Step 3: Instantiate Existing Saves

When we enter play mode, we need to first load any existing saves that the player may have made in a previous session.

We can do this using the Start method.

```csharp
private void Start()
{
    // Instantiate slots for existing saves
    foreach (var save in SaveStorage.instance.saves.Values) 
    {
        CreateNewSaveSlot(save);
    }
}
```

## Step 4: Increment Time

In the Update method, we will increment the time elapsed. This will be the only data that will be saved and loaded for this example.

```csharp
private void Update()
{
    // Increment time per frame
    timeElapsed += Time.deltaTime;
    timeElapsedText.text = $"Time Elapsed: {timeElapsed}";
}
```

## Step 5: Saving and Loading Data

We will create 3 methods for saving and loading. The first one will load the data from a save file.

```csharp
/// <summary>
/// Loads a save.
/// </summary>
/// <param name="saveFile">The save file.</param>
public void LoadSave(SaveFile saveFile)
{
    timeElapsed = saveFile.GetData<float>(timeElapsedKey);
}
```

The second one will save (or overwrite) the data in the save file.

```csharp
/// <summary>
/// Overwrites a save.
/// </summary>
/// <param name="saveFile">The save file.</param>
public void OverwriteSave(SaveFile saveFile)
{
    // Save the time elapsed
    saveFile.AddOrUpdateData(timeElapsedKey, timeElapsed);
    saveFile.Save();
}
```

The third one will be used by the save slots and will load or overwrite the data depending on the mode.

```csharp
/// <summary>
/// Loads or overwrites the save based on the active mode.
/// </summary>
/// <param name="saveFile">The save file.</param>
public void LoadOrOverwriteSave(SaveFile saveFile)
{
    if (loadMode)
    {
        LoadSave(saveFile);
    }
    else
    {
        OverwriteSave(saveFile);
    }
}
```

## Step 6: Create New Save

We have methods that require a save file, but no save file is being created yet. A save file should be created when the 'Create New Save' button is pressed, along with a save slot.

So, let's create some methods for this. The first method will create a new save file.

```csharp
/// <summary>
/// Creates a new save.
/// </summary>
public void CreateNewSave()
{
    // Create the save file data
    SaveFileSetupData saveFileSetupData = new()
    {
        fileName = $"InfiniteExampleSave{SaveStorage.instance.saveCount}",
        saveLocation = SaveLocation.DataPath,
        filePath = "StylishEsper/ESave/Examples/Any RP Examples",
        fileType = FileType.Json,
        encryptionMethod = EncryptionMethod.None,
        addToStorage = true
    };

    SaveFile saveFile = new SaveFile(saveFileSetupData);

    // Save the time elapsed
    // Techincally, nothing is being overwitten at this stage since it is an empty save file
    OverwriteSave(saveFile);

    // Create ths save slot for this data
    CreateNewSaveSlot(saveFile);
}
```

At the end, CreateNewSaveSlot is called. This has not been created yet.  The CreateNewSaveSlot method will instantiate a new save slot, edit the save slot's text, and give the save slot an on-click event that will call LoadOrOverwriteSave.

```csharp
/// <summary>
/// Creates a save slot for a save file.
/// </summary>
/// <param name="saveFile">The save file.</param>
public void CreateNewSaveSlot(SaveFile saveFile)
{
    // Instantiate the save slot
    var slot = Instantiate(saveSlotPrefab, content);
    var slotText = slot.transform.GetChild(0).GetComponent<Text>();
    slotText.text = $"Save Slot {slots.Count}";

    // Move save creator to the bottom
    saveSlotCreator.transform.SetAsLastSibling();

    // Add on-click event for loading
    slot.onClick.AddListener(() => LoadOrOverwriteSave(saveFile));

    slots.Add(slot);
}
```

We still need the save slot creator button to have an on-click event that creates a new save. This can be done by updating our Start method.

```csharp
private void Start()
{
    // Instantiate slots for existing saves
    foreach (var save in SaveStorage.instance.saves.Values) 
    {
        CreateNewSaveSlot(save);
    }

    // Save slot creator on-click event
    saveSlotCreator.onClick.AddListener(CreateNewSave);
}
```

Done! You can now test it in play mode.
