Persistence入門 - 基礎知識編
こんばんは。ハツェです。
久しぶりに面白い機能が追加されるので、紹介しようかなと思います。
動作環境は、Unity : 2022.3.22f1、VRCSDK : 3.7.2-persistence-beta.1です。
目次
Persistenceとは
Persistenceとは、VRChatでデータを保存してそれを復元することが出来る機能です。
データはローカルに保存されずにVRChat上のサーバーにアップロードされる形で保存されるため、同一アカウントであれば別クライアントでも同じワールドにJoinすることでデータを引き継ぐことが出来ます。
しかし、現状はワールドインスタンス間でのデータ共有機能はないみたいです。今後実装されるといいですね。
また、公式ドキュメントではアップロードするデータのことを「User Data」と呼んでいるため、本記事でもこれに倣っていこうと思います。
vrc-persistence-docs.netlify.app
Persistenceの必要性
後述するデータ強制削除不可の性質上、本当にPersistenceが必要かどうかは考えてから導入することをおすすめします。
もし、一度Persistenceを導入した場合、以降の開発ではセーブデータの互換性が取れるようにしていかなければなりません。ある程度の品質を求める場合に限りますが...
ですので、Persistemceを使わなくても大丈夫そうな場合には、その方法を用いた方が良いかもしれません。
User Dataの消去
Udon側からUser Dataを消去する方法はありませんが、ユーザー自身がUser Dataを消す方法は幾つか存在しています。
全User Dataを消去する場合
クライアントからは、メインメニューの設定タブを開き、デバッグ情報ページにある「Reset All User Data」を押すことで全てのワールドのUser Dataを消去することが出来ます。
Webからは、画面上部の歯車アイコンを押し、User Data欄の「Reset All User Data」を押すことで全てのワールドのUser Dataを消去することが出来ます。

特定のワールドのUser Dataだけ消去する場合
クライアントからは、そのワールドにJoinしていない状態でワールドページを開き、「Reset User Data」を押すことでそのワールドのUser Dataを消去出来ます。
Webからは、そのワールドのページを開き、「Reset User Data」を押すことでそのワールドのUser Dataを消去出来ます。

Persistenceの種類
Persistenceには、二種類のAPIが存在します。
以下、それぞれについて紹介しますが、なるべくPlayer Objectを使用することを推奨します。
- Player Data
- Player Object
Player Data
Player Dataとは、キーバリュー型でUser Dataを構築し、それをVRChatのサーバーに保存するような仕組みのAPIです。
Player Data自体は、Udon Behaviourからは独立しているため、どのUdonからも利用可能ですが、データが送られてくるタイミングは RequestSerialization になっています。
また、Player Dataに保存出来るデータの型は、下記公式ドキュメントに記載されているものになります。
vrc-persistence-docs.netlify.app
キーとそのデータを追加するだけで保存出来るため、簡単に保存データを追加出来るというのがメリットです。
しかし、キーが重複した場合にデータが意図せず上書きされてしまったり、キーが削除出来ないという性質上、使用しなくなったキーが大量発生してしまったりするデメリットもあるため、アップデートを逐一行う規模の大きいワールド制作や頒布物、販売物への利用には適していません。
とりあえず、自分のワールドで保存ギミックを軽く扱うぐらいの場合にのみ使用することをお勧めします。
Player Object
Player Objectとは、GameObjectの状態そのものをVRChatのサーバーに保存するような仕組みのAPIです。
そのため、GameObjectにアタッチしているUdonの同期変数はもちろん、VRCObjectSync のようなコンポーネントの同期状態も保存出来るようです。
Player Objectは、NetworkIDをキーにしているようなので、別のGameObjectにしたりNetworkIDを意図的に別の値にしない限り、データは保存され続けることになります。
そのため、Player Dataで問題になる「キーの重複」が頒布物のインポート等で起こることがなく、ワールドをアップデートしていく過程においても比較的保全性があるため、基本的にはこちらを使用することを推奨します。
データのアップロード制限
現状は、Player Dataで100KB、Player Objectで100KBまでそれぞれアップロードすることが出来ます。
これを超えた容量をアップロードしようとした場合、アップロードだけは失敗するため、次回以降のJoin時にデータが復元出来なくなります。
また、容量を超えたアップロードをした際、現状は特にエラー等が吐き出されたりしないため、自前で容量チェックする必要がありそうです。
容量系のイベントを追加してほしいというCannyは上がっているので、投票しておくといいかも...?
feedback.vrchat.com
データの復元と保存タイミング
データが復元するタイミングは、ユーザーがインスタンスにJoinした後の OnPlayerRestored イベント発生時です。
復元させるデータ量によっては、Start や OnPlayerJoined よりも後に OnPlayerRestored が発生する可能性もあるため、保存データを扱う際は OnPlayerRestored 以降で扱うようにする必要があります。
また、データが保存されるタイミングは、Player DataはキーにデータをSetした時、Player Objectでは同期変数の値を更新して再同期させた時になります。
ワールドJoin時は自動でデータを復元してくれますが、Left時には自動でデータを保存してくれないため、注意が必要です。
次回
基礎知識としては以上になります。
次回は、Player Objectを使った例を紹介していきます。
hatuxes.hatenablog.jp
ダウンロードした画像をuGUIで表示してみよう
こんばんは。ハツェです。
約一年ぶりですね。最近は面白いUdonのアップデートが無くて退屈していました。
今回は、URLの画像をVRChat上に表示してみようという記事です。
動作環境は、Unity : 2019.4.31f1、VCC : 1.0.6、SDK - Worlds : 3.1.11、U# : 1.1.7です。
目次
今回の概要
Web上にある画像をVRChatに落として表示する方法について解説します。
いわゆるVideoPlayerの画像バージョンと言ったところですね。
あくまでもU#での実装方法について話しますので、UdonGraphでの実装は公式ドキュメントをご参照ください。
前提知識
サンプルを紹介する前に、幾つか必要となる知識についてご紹介します。
VRCImageDownloader
画像をWebからダウンロードしてくれるクラスです。
VRCImageDownloader.DownloadImage()を呼ぶことで、Webからダウンロードを実行してくれます。
ただし、このクラスはIDisposableを実装しているため、使い終わったらしっかりと破棄する必要があります。
また、この関数には5秒に一回のみという秒数制限が付いており、これより多くの回数ダウンロードしようとすると、意図しない挙動になることがあります。
ダウンロードした画像をマテリアルに反映する方法
VRCImageDownloader.DownloadImage()関数は、四つの引数が指定出来ます。
url: ダウンロードする画像のURLを指定します。
material: ダウンロードした画像を割り当てるマテリアルを指定します。
udonBehaviour: ダウンロード後にイベントを実行するUdonBehaviourを指定します。
textureInfo: ダウンロードする画像の詳細設定を記述したものを指定します。テクスチャの割り当て先もここで指定します。(_MainTextみたいな)
urlを指定しないと、ダウンロードが開始されません。
materialを指定すると、ダウンロード後にtextureInfo.MaterialPropertyで指定したシェーダー変数へ自動的にダウンロードテクスチャを割り当てます。nullでも問題はありません。
udonBehaviourがnullの場合、ダウンロード後に一切イベント関数が呼ばれなくなります。ただし、これがnullの場合、内部的にエラーが出るため、基本的には自身のudonを参照しておくのが良いです。
また、DownloadImage()関数はIVRCImageDownloadを返します。いわゆるTaskみたいなものです。
これにダウンロード状況や、ダウンロードしたテクスチャ等が格納されます。詳しくはこちら。
ダウンロード時に実行されるイベント関数
UdonBehaviourには、OnImageLoadSuccess(result)とOnImageLoadError(result)の二つのイベント関数が追加されています。
OnImageLoadSuccessはダウンロード成功時、OnImageLoadErrorはダウンロード失敗時にそれぞれ呼ばれます。
今回はこのイベント関数を使用して、Imageコンポーネントにダウンロードした画像を割り当てます。
実際にサンプルを作成してみる
ここからは、VRChat上でURLを指定してCubeをインタラクトすると、画像をダウンロードし、その後表示するというサンプルを作っていきます。
表示させる対象がRawImageであるため、今回はDownloadImage()の自動反映処理を使わず、ダウンロード後の動作を自作していきます。
また、今回作成するサンプルは全てローカルで動作するものであるため、同期させる場合はURLを同期しておくと良いと思います。
完成図
画像を表示するImageとURLを指定するVRCInputField、及びダウンロードを実行させるインタラクトCubeで構成します。

サンプルコード
部分解説
ダウンロードする部分
実際にダウンロードを実行している部分は、以下の部分です。
// ダウンロード実行 _task = _imageDownloader.DownloadImage(_urlInputfield.GetUrl(), null, targetUdon, info);
URLの指定はVRCUrlを渡せば良いので、VRCInputFieldからURLを取得して渡しています。
これで、VRChat上からURLを指定出来るようになります。
反対に、URLを固定したい場合はVRCUrlを宣言すれば良いでしょう。
テクスチャの割り当て
該当部分は以下の通りです。(見やすいように記述を変更しています)
// ダウンロード成功時 public override void OnImageLoadSuccess(IVRCImageDownload result) { ... // テクスチャ反映 _target.texture = result.Result; ... }
ダウンロードしたテクスチャの割り当ては、OnImageLoadSuccessイベントで行っています。
OnImageLoadSuccessイベントは、VRCImageDownloader.DownloadImage()の第三引数に自身のudonを設定しておかないと呼ばれないため、注意が必要です。
サンプルコードでは、ついでにサイズをダウンロードした画像の解像度に合わせています。
ロード状況の可視化
該当部分は以下の通りです。(見やすいように記述を変更しています)
private void Update() { ... // ロードバーを動かす _loadingBar.value = _task.Progress; ... }
ダウンロード開始するタイミングで、IVRCImageDownloadを受け取っておくことでダウンロード進行状況を取得出来ます。
でも、現時点だと0と1でしか取得出来てないです...。バグなのかダウンロード速度が高速なのかは不明です...。
実行

あとがき
今回は指定したURLから、画像をダウンロードする方法について紹介しました。
画像と同じ方法で文字列も取得できるようになっています。こちら
文字列が外部から取得できるようになったので、天気予報とかをログイン時に表示出来たりしそうで面白いですね。
色々面白い使い方を模索して頂ければと思います。