> For the complete documentation index, see [llms.txt](https://cowsinss-organization.gitbook.io/save-and-load-add-on/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://cowsinss-organization.gitbook.io/save-and-load-add-on/how-to-use-and-guides/saving-custom-data-advanced-method.md).

# Saving Custom Data: Advanced Method

{% hint style="warning" %}
This method is only required for very specific cases where data to store is not serializable.
{% endhint %}

### Early Considerations

For most scenarios, the [simple method](/save-and-load-add-on/how-to-use-and-guides/saving-custom-data-simple-method.md) is more than enough to successfully save custom data. However, there might be situations where you need to save data that cannot be serialized ( excluding `Item_SO`s as those can be processed by [`GameDataManager` ](/save-and-load-add-on/content/03.-content/03.1-datapersistence/gamedatamanager.md)).

For those situations, you´ll need to expand [`CustomSaveData` ](/save-and-load-add-on/content/03.-content/03.5-objects-save-data/customsavedata.md)to support custom serialization.

|              Pros             |       Cons      |
| :---------------------------: | :-------------: |
| Supports Custom Serialization | Requires Coding |

{% hint style="warning" %}
This method does NOT use Attributes to mark which variables are meant to be saved. \[SaveField] as it relies on coding.
{% endhint %}

### Saving Custom Data

Imagine you´ve created a script that contains non-serializable data that needs to be saved.&#x20;

<pre class="language-csharp"><code class="lang-csharp">using UnityEngine;
using System.Collections.Generic;

<strong>public class Example : MonoBehaviour
</strong>{
    // Field that we need to save. Not Serializable
    public Dictionary&#x3C;string, int> dictionary = new Dictionary&#x3C;string, int>();
}
</code></pre>

In this example scenario, since `Dictionary<string, int>` cannot be serialized, we´ll need to create a new class that inherits from CustomSaveData, where we can place the data types to be saved. Here´s a step-by-step guide:

{% stepper %}
{% step %}

### Include cowsins.SaveLoad & cowsins libraries

```csharp
using cowsins.SaveLoad;
using cowsins;
```

{% endstep %}

{% step %}

### Ensure your class inherits from Identifiable

Your class needs to inherit from Identifiable ( or any other class that already inherits from Identifiable ) so the Save & Load add-on can effectively load the data.

```csharp
public class NonSerializableExample : Identifiable {}
```

{% endstep %}

{% step %}

### Expanding Custom SaveData

Dictionaries cannot be serialized & stored into a Json file directly, so instead, we´ll store a string array and an int array separately. For that, we need to create a new class that inherits from CustomSaveData, so it can store our custom arrays that will act as if they were a Dictionary.

{% tabs %}
{% tab title="Example Code" %}

```csharp
[System.Serializable]
public class ExampleSaveData: CustomSaveData
{
    public string[] dictionaryKeys;
    public int[] dictionaryValues;
}
```

{% endtab %}

{% tab title="Base Code Structure" %}

```csharp
[System.Serializable]
public class CustomSaveDataName : CustomSaveData
{
    // Define your Serializable data here
}
```

You can copy & paste this structure.

Make sure to modify *`CustomSaveDataName`* with the name of your new expanded CustomSaveData, and define the serializable data that you require.
{% endtab %}
{% endtabs %}
{% endstep %}

{% step %}

### Processing & Saving Fields

After our Serializable data is structured, we need to process the data from non-serializable to serializable so it can be saved. In this example, we´ll pass keys to a string array, and values to an int array.

{% tabs %}
{% tab title="Example Code" %}

```csharp
public override CustomSaveData SaveFields()
{
        string[] keys = new string[dictionary.Count];
        int[] values = new int[dictionary.Count];

        dictionary.Keys.CopyTo(keys, 0);
        dictionary.Values.CopyTo(values, 0);
        
        return new ExampleSaveData 
        {
                dictionaryKeys = keys,
                dictionaryValues = values,
                SceneName = SceneManager.GetActiveScene().name
        };
}
```

In this example, we divide the dictionary into two serializable arrays and return an expanded version of `CustomSaveData` (named `ExampleSaveData` in this case) containing these arrays. Additionally, we include the `SceneName`, which is crucial. To accomplish this, make sure to implement the following library:

```csharp
using UnityEngine.SceneManagement;
```

{% endtab %}

{% tab title="Base Code Structure" %}

```csharp
public override CustomSaveData SaveFields()
{
        // Process your non-serializable data 
        // into serializable data types
        
        return new CustomSaveDataName 
        {
                // Your assigned data goes here
                // separate them by commas (,)
                SceneName = SceneManager.GetActiveScene().name
        };
}
```

You can copy & paste this structure.

Make sure to modify *`CustomSaveDataName`* with the name of your expanded CustomSaveData, process the data and assign it to *`CustomSaveDataName`* .
{% endtab %}
{% endtabs %}
{% endstep %}

{% step %}

### Processing & Loading Fields

Loading is essentially the same process as Saving but instead of processing from Non-Serializable to Serializable, we need to convert the serializable data back to their original data types and formats. In this case, we´ll populate the dictionary based on the keys and values arrays.

{% tabs %}
{% tab title="Example Code" %}

```csharp
 public override void LoadFields(object data)
    {
         if(!(data is ExampleSaveData customData)) return;
         
         dictionary.Clear(); // Ensure the dictionary starts empty
    
         // Re-Populate Dictionary
         if (saveData.dictionaryKeys != null && saveData.dictionaryValues != null &&
             saveData.dictionaryKeys.Length == saveData.dictionaryValues.Length)
         {
             for (int i = 0; i < saveData.dictionaryKeys.Length; i++)
             {
                 dictionary[saveData.dictionaryKeys[i]] = saveData.dictionaryValues[i];
             }
         }
        base.LoadFields(data);
    }
```

{% endtab %}

{% tab title="Base Code Structure" %}

```csharp
public override void LoadFields(object data)
{    
    if(!(data is ExampleSaveData  customData)) return;
    
    // Process data from Serializable data to their original data types
    // and assign the values.
    
    base.LoadFields(data);
}
```

You can copy & paste this structure.

Ensure you assign the original data when loading the fields.

Make sure to modify *`CustomSaveDataName`* with the name of your expanded CustomSaveData.
{% endtab %}
{% endtabs %}
{% endstep %}

{% step %}

### Notify GameDataManager

At this step of the guide, your CustomSaveData logic is fully set-up, we just need a way to tell the GameDataManager that this class needs to be saved. Luckily for us, this can be done the same way as in the [Simple Method](/save-and-load-add-on/how-to-use-and-guides/saving-custom-data-simple-method.md).

Simply run the following line whenever you want to notify GameDataManager of a data change ( Whenever any of your saveable fields change )

```csharp
StoreData();
```

{% endstep %}
{% endstepper %}

{% hint style="warning" %}
Remember that this method is only required for very specific cases where data to store is not serializable.
{% endhint %}

Here´s the full code for this example:

```csharp
using System.Collections.Generic;
using cowsins;
using cowsins.SaveLoad;
using UnityEngine;
using UnityEngine.SceneManagement;

public class NonSerializableExample : Identifiable
{
    public Dictionary<string, int> dictionary = new Dictionary<string, int>();

    [System.Serializable]
    public class ExampleSaveData : CustomSaveData
    {
        public string[] dictionaryKeys;
        public int[] dictionaryValues;
    }

    public override CustomSaveData SaveFields()
    {
        string[] keys = new string[dictionary.Count];
        int[] values = new int[dictionary.Count];

        dictionary.Keys.CopyTo(keys, 0);
        dictionary.Values.CopyTo(values, 0);

        return new ExampleSaveData
        {
            dictionaryKeys = keys,
            dictionaryValues = values,
            SceneName = SceneManager.GetActiveScene().name
        };
    }

    public override void LoadFields(object data)
    {
        if (!(data is ExampleSaveData customData)) return;

        dictionary.Clear();

        if(customData.dictionaryKeys != null && customData.dictionaryValues != null && customData.dictionaryKeys.Length == customData.dictionaryValues.Length)
        {
            for(int i = 0; i < customData.dictionaryKeys.Length; i++)
            {
                dictionary[customData.dictionaryKeys[i]] = customData.dictionaryValues[i];
            }
        }

        base.LoadFields(data);
    }

    public override void LoadedState()
    {

    }
}
```

***

### Checklist

1. You need to save non-serializable data types from a custom class
2. You implemented cowsins.SaveLoad library
3. Your class inherits from Identifiable
4. You expanded CustomSaveData
5. You are processing data into Serializable Fields in SaveFields()
6. You are loading data back to its original format in LoadFields()
7. You are using StoreData() somewhere in your code to ensure data is sent to the [GameDataManager](/save-and-load-add-on/content/03.-content/03.1-datapersistence/gamedatamanager.md)

***

### What to do now? Loaded State.

Once you are done Saving & Loading data, you can run custom behaviour based on the loaded data. Whenever LoadFields is called, LoadedState() will also be called.

Check [this guide](/save-and-load-add-on/how-to-use-and-guides/loading-custom-data.md) for more Information.
