Unity Json

JsonUtility Sérialisation/Désérialisation dans Unity

JsonUtility est une classe fournie avec Unity, facilitant la sérialisation et la désérialisation du contenu basé sur le format JSON.

Table des matières

Introduction au JSON

JSON, ou JavaScript Object Notation, est un format texte standard pour représenter des données structurées basé sur la syntaxe d’objet JavaScript. Dans Unity, il permet de transformer du texte en une instance de classe C#.

Exemple JSON :

{"id":1,"username":"VectorFocus"} Cela équivaut à l’instance de classe C# suivante :


public class User
{
    public int id;
    public string username;
}

var user = new User()
{
    id = 1,
    username = "VectorFocus"
};
        

Sérialisation avec JsonUtility.ToJson

Pour sérialiser un objet en une chaîne JSON, vous pouvez utiliser la méthode JsonUtility.ToJson.

public class User
{
    public int id;
    public string username;
}

var user = new User()
{
    id = 1,
    username = "VectorFocus"
};

// {"id":1,"username":"VectorFocus"}
string json = JsonUtility.ToJson(user);
        

Désérialisation avec JsonUtility.FromJson

Pour désérialiser une chaîne au format JSON en un objet, vous pouvez utiliser JsonUtility.FromJson.

string json = "{\"id\":1,\"username\":\"VectorFocus\"}";
User user = JsonUtility.FromJson<User>(json);
        

Désérialisation vers Monobehaviour et ScriptableObject avec JsonUtility.FromJsonOverwrite

JsonUtility.FromJsonOverwrite permet la désérialisation du JSON dans des classes héritant de UnityEngine.Object (Monobehaviour et ScriptableObject). Il peut également être utilisé pour des classes plus simples en passant un objet en tant que deuxième paramètre à mettre à jour, au lieu de créer un nouvel objet.

using UnityEngine;

public class JsonMonobehaviour : MonoBehaviour
{
    public int number;
    public string informations;

    private void Start()
    {
        string json = "{\"number\":6,\"informations\":\"my data\"}";
        JsonUtility.FromJsonOverwrite(json, this);
    }
}
        

Masquer les champs avec JsonUtility

Les champs peuvent être masqués de la sérialisation en utilisant l’attribut [NonSerialized]. Les champs privés et les getters/setters sont également ignorés.


using UnityEngine;
using System;

public class JsonMonobehaviour : MonoBehaviour
{
    public int number;
    public string informations;

    // masquer de JsonUtility
    [NonSerialized]
    public int field;

    // masquer de JsonUtility
    private int _field2;

    // masquer de JsonUtility
    public int Field3 { get; set; }
}
        

Utiliser les Getters/Setters avec JsonUtility

Les getters et setters peuvent être directement sérialisés en utilisant l’attribut [field: SerializeField]. Cependant, le champ se verra attribuer une clé non conviviale (par exemple, k__BackingField).


[field: SerializeField]
public int Field3 { get; set; }
        

Utiliser les tableaux avec JsonUtility

Les tableaux ou listes peuvent être directement définis dans la structure pour les types simples (int, string, etc.).


public class User
{
    public int id;
    public string username;
    public List<int> points = new List<int>();
    public int[] pointsArray;
}
        

Utiliser des types personnalisés avec JsonUtility

Les types personnalisés peuvent être utilisés dans votre structure ; attribuez simplement l’attribut [System.Serializable] à votre classe ou struct personnalisée.


    public class User
    {
        public int id;
        public string username;

        // un seul groupe
        public Group group;

        // fonctionne avec les listes et les tableaux aussi
        public List<Group> groups = new List<Group>();
    }

    [System.Serializable]
    public class Group
    {
        public string name;
    }

Thread d’arrière-plan avec JsonUtility

Si vos données JSON deviennent énormes et que JsonUtility devient lent : Unity JsonUtility Main Thread Il peut être intéressant d’exécuter la sérialisation dans un autre thread pour éviter que le thread principal ne soit bloqué et que le jeu ne se fige. Depuis Unity 2019.1.6, nous pouvons utiliser JsonUtility dans un thread d’arrière-plan. Vous ne devez pas altérer un objet qui est utilisé dans la fonction pendant son exécution.


using System.Collections;
using System.Threading;
using UnityEngine;
using UnityEngine.Events;

public class JsonBackground : MonoBehaviour
{
    public class User
    {
        public int id;
        public string username;
    }

    private void Start()
    {
        string json = "{\"id\":1,\"username\":\"VectorFocus\"}";

        FromJsonBackground<User>(json, (user) =>
        {
            // actions avec l'utilisateur
        });
    }

    public void FromJsonBackground<T>(string data, UnityAction<T> unityAction)
    {
        StartCoroutine(FromJsonBackgroundCoroutine<T>(data, unityAction));
    }

    private IEnumerator FromJsonBackgroundCoroutine<T>(string data, UnityAction<T> unityAction)
    {
        T convertData = default(T);

        var thread = new Thread(() =>
        {
            convertData = JsonUtility.FromJson<T>(data);
        });

        thread.Start();

        while (thread.IsAlive)
        {
            yield return null;
        }

        unityAction.Invoke(convertData);
    }
}

Je ne suis pas un grand fan de ce code, je ne suis pas satisfait du mélange de thread et de coroutine. Un autre problème est ajouté : si la coroutine est arrêtée, le thread continuera à s’exécuter. Je n’ai pas encore trouvé de solution à ce problème, car Thread.Abort est obsolète et CancellationToken ne semble pas pouvoir répondre à ce besoin.

Thread d’arrière-plan avec Task et Async

Vous pouvez utiliser les fonctionnalités Task et async/await de C# dans Unity pour effectuer ces opérations en arrière-plan. N’oubliez pas d’appeler les opérations liées à Unity sur le thread principal lorsque c’est nécessaire.

using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.Events;

public class JsonBackgroundTask : MonoBehaviour
{
    public class User
    {
        public int id;
        public string username;
    }

    private void Start()
    {
        string json = "{\"id\":1,\"username\":\"VectorFocus\"}";
        FromJsonTask<User>(json, (user) =>
        {
            // actions avec l'utilisateur
        });

        AwaitSyntax();
    }

    public async void AwaitSyntax()
    {
        // si vous préférez sans rappel avec await
        string json = "{\"id\":1,\"username\":\"VectorFocus\"}";
        var user = await FromJsonGetTask<User>(json);
    }

    public async void FromJsonTask<T>(string json, UnityAction unityAction)
    {
        var data = await Task.Run(() => JsonUtility.FromJson<T>(json));
        unityAction?.Invoke(data);
    }

    public Task FromJsonGetTask<T>(string json)
    {
        return Task.Run(() => JsonUtility.FromJson<T>(json));
    }
}

J’ai le même problème ici qu’avec le code utilisant le thread, la tâche continuera même si l’objet est détruit. Vous pouvez modifier le code pour ajouter un CancellationToken, mais il ne semble pas possible d’arrêter l’exécution de JsonUtility une fois qu’elle a commencé.

EditorJsonUtility dans le contexte de l’éditeur

EditorJsonUtility est un utilitaire similaire à JsonUtility mais conçu spécifiquement pour l’éditeur Unity. Il offre plus de contrôle sur la sérialisation et la désérialisation dans les scripts de l’éditeur.


using UnityEditor;
using UnityEngine;

public class EditorJsonExample
{
    [MenuItem("Tools/Deserialize JSON")]
    private static void DeserializeJson()
    {
        User user = new User() { id = 1 };
        string json = EditorJsonUtility.ToJson(user);
    }
}
        

Illustration originale par J S de Pixabay

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *