はじめかた

値をバイト列に、型を JSON に詰める。

更新日 2026-09-11

バイト列に詰める

ByteWriter がバッファを組み立て、ByteReader が同じ順番で読み戻します。

using Udonite.Serialization;

byte[] payload = new ByteWriter()
    .WriteInt32(playerId)
    .WriteString(name)
    .ToArray();

ByteReader reader = new ByteReader(payload);
int id = reader.ReadInt32();
string readName = reader.ReadString();

どちらも Udonite Net のメッセージガイドで詳しく扱っています。もともとそのために作られたもの——NetworkEventSerialize(ByteWriter)/Deserialize(ByteReader) です。とはいえこの二つ自体はネットワーク専用ではありません。両端を自分でコントロールできる、コンパクトで自己完結したバイナリの形が欲しいところならどこでも使えます。保存フォーマットでも、ファイルでも。

バッファの終わりを超えて読んでも例外にはなりません。 ログを出して、その型のデフォルト値を返します。Udon には巻き戻すための例外処理がなく、壊れたバッファや途中で切れたバッファが読み込み側のビヘイビアを道連れにしてはいけないからです。

型を JSON に詰める

型は IJsonSerializable を実装することで参加します——自分で ToJson()/FromJson() を書きます。Udon にはその走査を代わりにやってくれる reflection がないからです。

using Udonite.Serialization;
using VRC.SDK3.Data;

public class Player : IJsonSerializable
{
    public string Name;
    public int Score;

    public DataToken ToJson()
    {
        DataDictionary dict = new DataDictionary();
        dict.Add("name", Name);
        dict.Add("score", Score);
        return dict;
    }

    public void FromJson(DataToken token)
    {
        DataDictionary dict = token.DataDictionary;
        Name = dict["name"].String;
        Score = (int)dict["score"].Double;
    }
}

数値は .Int ではなく必ず .Double で読みます。 JSON の数値は、たとえ整数として書いたものでも TokenType.Double として読み戻されます。.Int はそこで例外を投げます。これは VRCJson 自体の性質であって、このパッケージが覆い隠せるものではありません。

シリアライズ・デシリアライズの呼び出し側には DataToken は一切出てきません。

Player player = new Player { Name = "Ada", Score = 42 };

string json = Json.Serialize(player);          // {"name":"Ada","score":42}、失敗すれば null
Player restored = Json.Deserialize<Player>(json); // 新しい Player、不正な JSON なら null

Deserialize<T> はインスタンスを自分で組み立てます。T には引数なしのコンストラクターが要ります(where T : new())。これはコンパイラが呼び出し箇所で解決する制約であって、実行時のものではありません。ほかのジェネリック制約と同じ扱いです。reflection ではなく、Udon にそれがなくても動きます。

自動で調べられるものは何もありません。 ToJson() が触れなかったフィールドは送られませんし、IJsonSerializable をまったく実装していない型は Serialize<T> に対してコンパイルエラーになります——実行時に一部だけシリアライズされたオブジェクトになることは絶対にありません。

決まった型を持たない JSON を組み立てる

IJsonSerializable の裏付けがない、その場限りで組み立てる JSON には、DataToken を直接扱う非ジェネリックのオーバーロードがあります。

DataDictionary dict = new DataDictionary();
dict.Add("ok", true);

string json = Json.Serialize(dict);          // または Json.Serialize(dict, pretty: true)
DataToken? parsed = Json.Deserialize(json);

DataToken がどうしても必要になるのはここだけです。VRChat 自身の JSON 値モデルそのものだからです——オブジェクトには DataDictionary、配列には DataList、それより単純なものにはスカラーなトークンが対応します。

次に読むもの

リファレンス は両方のメンバー一覧です。

問題が発生しました 再読み込み