Unity向けJSONシリアライザー＆デシリアライザーのDJSONを使おう！

# 自作のJSONシリアライザー＆デシリアライザーです
使い方は、普通にJsonUtilityや、Newtonsoft.Jsonと似たようなものだと思います。
特徴としては、List,Dictionaryが使える！
Unityの基本的な型を使える！（Vector3,Quaternion,Matrix4x4など）
Unityの専門的な型でも使える！（Rect,Ray,Gradient,AnimationCurveなど）
enumも文字列として保存、復元が出来る！
多分それなりに高速。

# インストール
1. Windows -> PackageManagerを選びます
2. ＋ボタンを押して、Add Package from git URLを選びます
3. https://github.com/sasame/DJSON.git を指定します

# 使い方（テストコード）
~~~ sample.cs
using NUnit.Framework;
using UnityEngine;
using UnityEngine.TestTools;


public class EditorTestScript
{
    class A
    {
        public Vector2 value;
        public int number;
    }

    [Test]
    public void TestJSON_A()
    {
        var a = new A();
        a.value = new Vector2(1.3f, -2.8f);
        a.number = 123;

        var jsonString = DJSON.Serialize(a);
        Debug.Log(jsonString);

        var test = DJSON.Deserialize<A>(jsonString);
        Debug.Log(test.value);
        Debug.Log(test.number);
    }
}
~~~


<details open><summary>Dictionaryを扱うテスト</summary>

~~~SampleDictionary.cs
using NUnit.Framework;
using UnityEngine;
using UnityEngine.TestTools;


public class EditorTestScript
{
    [Test]
    static public void Test_DJSON_Dictionary()
    {
        var dic = new Dictionary<string, string>();
        dic["ABC"] = "abc";
        dic["DEF"] = null;
        dic["TEST"] = "test";
        var str = DJSON.Serialize(dic);
        Debug.Log(str);

        var o = DJSON.Deserialize<Dictionary<string, string>>(str);
        Debug.Log(o);
    }
}
~~~

</details>



<details open><summary>AnimationCurveを扱うテスト</summary>

~~~SampleEtc.cs
using NUnit.Framework;
using UnityEngine;
using UnityEngine.TestTools;


public class EditorTestScript
{
    [System.Serializable]
    class TestAnimation
    {
        public Vector3 pos;
        public Vector3 rot;
        public Vector3 scl;
        public Dictionary<string, AnimationCurve> curves;
    }

    static Dictionary<string, TestAnimation> _testData2 = new Dictionary<string, TestAnimation>()
    {
        {
            "ABC", new TestAnimation()
            {
                pos = new Vector3(1f, 2f, 3f),
                rot = new Vector3(10f, 15f, 45f),
                scl = new Vector3(1f, 2f, 1.5f),
                curves = new Dictionary<string,AnimationCurve>()
                {
                    {
                        "rot.y",
                        new AnimationCurve(new Keyframe[]
                        {
                            new Keyframe(1f,2f,3f,4f),
                            new Keyframe(1.1f,1.2f,1.3f,1.4f),
                            new Keyframe(5f,4f,3f,2f),
                        })
                    },
                    {
                        "scl.x",
                        new AnimationCurve(new Keyframe[]
                        {
                            new Keyframe(1f,2f,3f,4f),
                            new Keyframe(1.1f,1.2f,1.3f,1.4f),
                            new Keyframe(4f,3f,2f,1f),
                            new Keyframe(0f,1f,2f,3f),
                            new Keyframe(5f,4f,3f,2f),
                        })
                    },
                }
            }
        },
        {
            "DEF",
            new TestAnimation()
            {
                pos = Vector3.zero,
                rot = Vector3.zero,
                scl = Vector3.one,
                curves = new Dictionary<string, AnimationCurve>()
                {
                    {
                        "pos.x",
                        new AnimationCurve(new Keyframe[]
                        {
                            new Keyframe(1f,2f),
                            new Keyframe(3f,4f),
                        })
                    }
                }
            }
        }
    };

    [Test]
    static public void Test_DJSON()
    {
        var str = DJSON.Serialize(_testData2);
        Debug.Log(str);

        var o = DJSON.Deserialize<Dictionary<string, TestAnimation>>(str);
        Debug.Log(o);
    }
}
~~~

</details>

# 型の判らないデータはどう処理するの？
サーバーから、送られてくるデータはどういう型で受け取れば良いのか判らないデータもあると思います。
そんなものDeserializeできないじゃん。と思われるかもしれません。
DJSON.Parseという関数があるので、それを使えば対応できます。
~~~
var dic = DJSON.Parse(str) as Dictionary<object, object>;
var userId = System.Convert.ToInt32(dic["userId"]);
var body = dic["body"] as string;
~~~
連想配列であれば、こういう感じで受け取れます。
配列はList&lt;object&gt;、連想配列はDictionary&lt;object,object&gt;で受け取ることができます。

逆に、JSON文字列化させるときも、上記のようなデータ型から文字列化することが可能です。
~~~
string jsonString = DJSON.ToJson(dic);
~~~

# おまけ
普通に考えたら、Gradientや、AnimationCurveなどの変数はフィールド変数として見えて無いので、JSONに変換できるわけがない！と思われるかもしれません。
普通では出来ないので、Unityの基本的な型だけを特別処理しています。
例えば、Gradientであれば、下記のような必要な要素の詰まった別クラスを書いておきます。
~~~ 
class subGradient
{
    public GradientColorKey[] colorKeys;
    public GradientAlphaKey[] alphaKeys;
    public GradientMode mode;
};
~~~
その上で、相互変換用のコードを作って。
~~~
// Gradient
_dicUnitySerializer[typeof(Gradient)] = new Serializer(typeof(subGradient),
    (o) => {
        var v = (Gradient)o;
        return new subGradient() {
            colorKeys = v.colorKeys,
            alphaKeys = v.alphaKeys,
            mode = v.mode
        };
    },
    (o) => {
        var v = (subGradient)o;
        return new Gradient()
        {
            colorKeys = v.colorKeys,
            alphaKeys = v.alphaKeys,
            mode = v.mode
        };
    });
~~~
これによって、JSON化不可能なクラスを可能なクラスに相互変換することを可能にしています。
こういう造りになっているので、DJSON.AppendSerializerという関数を使えば、もっと他にも普通にはシリアライズ不可能なクラスを可能にすることも可能な拡張を入れてあります。

このクラス、構造体の対応が足りないやバグ等がある場合、コメントなどでお知らせ頂けるとできるだけ早く対応したいと思っています。


# なんでこれを作ったか
もちろん既存のJsonUtilityやJsonConvertなどに不満があったというのが大きいのですが。
Unityエディター拡張で、複数のオブジェクトを扱いたくて、その上それぞれインスペクタで値を編集したいというときに、Unityの基本的なシリアライザーでは無理が出てきたというところがあったり。
それ以外にも、セーブデータをJSONで扱いたいときに、Vector2Intすらもシリアライズ出来ないようなものでは困ってしまうということで作りました。（当然ながらネットワークにデータを置くにしても、JSONだと扱いやすいわけだし）