持続データを使用することで、プレイ セッション間でプレイヤーごとのデータを追跡し、保存することができます。 これにより、さまざまな進行ゲーム モードが利用可能になります。プレイヤーが席を外して戻ってきたときに目的を再開したり、離れたときと同じ状態のゲームを確認したりすることができます。
持続データは、個々のプレイヤーのプロフィールや統計といったデータを Verse に格納することで機能します。 このデータは値が変わるたびに何度でも更新できます。 このデータは持続可能であるため、複数のゲームセッションの間で維持され、プレイヤーがゲーム内でオンラインであればいつでも利用できます。
持続データを利用するゲーム モードの例として、サバイバル、タイクーン、RPG、ローグライトが挙げられます。 これらのタイプのゲーム モードでは、プレイヤーはゲームプレイの原動力となる長期的な目標を満たすアイテムを蓄積する必要があります。
Verse スクリプトで持続データを使用し、情報を格納します。情報はプレイヤーおよびモジュールごとに保存されています。 持続データをゲーム モードに実装すると、ゲームを続ける動機付けとなり、プレイヤーを引き留めることができます。
自分で持続型を実装する方法については、「持続型のプレイヤー統計データのチュートリアル」を参照してください。
持続データは Verse で作成し、使用することができますが、持続データをサポートする基本的な機能を持っているクリエイティブの仕掛けもあります。 詳細については、「持続型の仕掛け」を参照してください。
Verse における持続の意味
Verse では、モジュールで定義された変数は、スコープ内にあれば、実行中のどのゲーム インスタンスに対してもグローバルです。 セッションに関連付けられたモジュールスコープの変数を除き、モジュールスコープの変数には持続性、つまり現在のゲームを超えてデータを格納することが求められます。 そのため、モジュール スコープで使用できる型には制限事項があります。
現在、以下の型をモジュール スコープで使用できます。
| 許可されているモジュール-スコープ型 | 定義 | 制限事項 |
|---|---|---|
| 現在のゲーム セッション中に、 | データは現在のセッション中にのみ格納され、その後のラウンドでは持続しません。 |
| 持続的である、 | プレイヤーの持続データへのアクセスは、そのプレイヤーが現在のゲームに参加しているときにのみ許可されます。 |
プレイヤーがゲームから離れたり、現在のセッションにいなくなったりすると、そのゲーム セッションにプレイヤーのデータを格納したり、アクセスしたりできなくなります。 プレイヤーが戻ってきたり、同じゲームを再開したりすると、そのプレイヤーのデータへのアクセスや更新が可能になります。
Verse で持続データを作成する
各プレイヤーの持続データを独自に作成し、プレイヤーがゲームに再度参加するたびに継続的に更新したり、格納したり、呼び出したりすることができます。 マッチメイキング中、ゲームは新規プレイヤーの持続データをチェックします。 プレイヤーに持続データがある場合、そのデータがロードされ、Verse のスクリプトが使用できるようになります。
持続データがある島で、データのロードに失敗した場合、プレイヤーは島に参加することはできません。 これは、データのロードに失敗した場合の保護措置であり、持続データが上書きされるのを防ぐためです。
持続データを Verse コードで作成するには、キーとして player の型を、値として持続可能な型を使用した、グローバルの weak_map 変数を定義します。 持続性のある型の完全なリストについては「持続可能な型」を参照してください。
以下の例では、グローバルの「weak_map」変数 MySavedPlayerData で key (キー) としてプレイヤーの型が使用され、値として整数が使用されています。 この変数でプレイヤーの整数値を格納すると、複数のゲーム セッションをまたいでデータが持続し、そのプレイヤーがゲームに参加しているときはいつでもアクセスして更新できます。
var MySavedPlayerData:weak_map(player, int) = map{}
持続データを定義したら、各プレイヤーのデータを初期化する必要があります。 そうするには、プレイヤーのデータがまだ格納されていないかどうかをチェックしてから、そのプレイヤーと初期値を weak_map に追加します。
# Runs when the device is started in a running game
OnBegin<override>()<suspends>:void =
InitialSavedPlayerData:int = 0
Players := GetPlayspace().GetPlayers()
for (Player : Players):
if:
not MySavedPlayerData[Player]
set MySavedPlayerData[Player] = InitialSavedPlayerData前の例では整数の値を 1 つ格納しただけですが、クラスや配列のような他の型を使って weak_map に各プレイヤーのデータをもっと格納することができます。 使用できる持続性のある型の完全なリストについては「持続可能な型」を参照してください。
次の Verse の例では、クラスでカスタム プレイヤー プロファイルを定義する方法を示します。後で格納、更新、アクセスすることができます。 クラス player_profile_data には、獲得した XP、ランク、完了したクエストなどのプレイヤーの情報が格納されます。
player_profile_data := class<final><persistable>:
Version:int = 0
Class:player_class = player_class.Villager
XP:int = 0
Rank:int = 0
CompletedQuestCount:int = 0
QuestHistory:[]string = array{}
var PlayerProfileDataMap:weak_map(player, player_profile_data) = map{}格納できるデータの量には、プレイヤー当たりおよび島当たりで制限があります。 データを保存するときは必ず、「FitsInPlayerMap」関数を使用して、更新によって合計サイズがどう変化するかをチェックすることをお勧めします。 詳細については、「持続データが制限内であるかをテストする」を参照してください。
各プレイヤーの持続データの作成方法と、その初期化の方法が分かったところで、Verse で持続データを扱う推奨方法についてのベストプラクティスも忘れずチェックしましょう。
島の公開済みバージョン間でデータを修正する
現在のバージョンの島を公開した後、持続データを更新したとしても、以前のバージョンの島のときの格納データも、それ以降のバージョンの島でサポートしなければなりません。
それを徹底するため、UEFN では後方互換性チェックが実行され、Verse のコードが現在公開されているバージョンと互換性がない場合はコンパイルに失敗するようになっています。 この後方互換性チェックは、以下の場合に実行されます。
UEFN ツールバーの [Launch Session (セッションを開始)] をクリックする。
UEFN ツールバーの [Push Changes (変更をプッシュ)] または [Push Verse Changes (Verse の変更をプッシュ)] をクリックする。
初めて島を公開する。
島の新しい公開バージョンをアクティブ化する。
この後方互換性チェックは基本的に、スコープがモジュールである weak_map 変数の値型を対象とする型チェックです。 整数のような単純な型の場合、島が公開された後に型を変更することはできません。 structs も同様です。島が公開された後に構造体の定義を変更することはできません。
現在、島を公開した後でもデータを追加できる持続型は、新しいフィールドにデフォルト値がある class 型のみです。 つまり、以前のバージョンで保存されたデータをロードすると、新しいフィールドとそのデフォルト値が含まれることになります。 持続データとしてクラスを使用するための詳細については「ベストプラクティス」を参照してください。
島の持続データをリセットする
島の持続データを強制的にリセットする必要がある場合は、プレイヤーが島に入ったときに持続データのデフォルト値を Verse で weak_map に割り当てることで可能です。
プレイヤーのデータがすでにリセットされているかどうかを知るには、クラスにバージョン値を含めて、持続データの一部となる新しい変更でそれを更新します。 これは以下のベストプラクティスの一つに過ぎないので他の方法についても必ずチェックしてください。
Verse における持続型
スコープがモジュールである weak_map 変数で使用可能な持続型には以下が挙げられます。
| タイプ | 説明 |
|---|---|
配列内の要素の型が持続可能であれば、配列も持続可能です。 | |
キャラクター値は持続可能です。 | |
キャラクター値は持続可能です。 | |
次の条件を満たすクラスは持続可能です。
| |
カラー値は持続可能です。 | |
持続指定子で定義すると、列挙型を持続可能にできます。 | |
浮動小数値は持続可能です。 | |
整数値は持続可能です。 | |
ロジック値は持続可能です。 | |
キー型と値型の両方が持続可能であれば、マップも持続可能な値になります。 | |
値が持続可能であれば、オプションも持続可能です。 | |
次の条件を満たす構造体は持続可能です。
島を公開した後に、持続可能な構造体を変更することはできません。 そのため、スキーマが一定であることが分かっている場合にのみ、持続可能型の構造体を使用することをお勧めします。 タプル | |
すべての要素型が持続可能であれば、タプルも持続可能です。 | |
Vector2 値は持続可能です。 | |
Vector2i 値は持続可能です。 | |
Vector3 値は持続可能です。 |
持続データでテストする
最新バージョンの島を公開する前に持続データの動作をテストする場合は、島設定仕掛けで、持続動作:プレイテスト セッション設定と持続動作:編集セッション設定の両方で以下の動作を設定できます。
| 持続データの動作 | 説明 |
|---|---|
ライブからインポートする | ライブ データがある場合は、ライブ データからセッション データをインポートします。 そのためには、島がライブで公開されており、プレイヤーがライブ バージョンの島でプレイしていることが必要です。 ライブ データが利用可能な場合、プレイ テスト セッションのデータはライブ データのコピーでシードされます。 これは、島ロジックの変更に伴う持続データの問題をテストするのに非常に便利です。 |
新しいユーザーをシミュレート | 初めて島をプレイするかのように、新しい持続データでプレイヤーをスタートさせます。 |
持続データの動作設定は、プレイテスト時に適用されます。 持続データを使ったテストには、以下の 2 種類のシナリオがあります。
セッションの編集: 持続データの動作設定は、UEFNからのセッションローンチ時に適用されます。 つまり、持続データは、1 つのセッション内で複数のゲームにまたがって維持されます。 そのセッションを終了して新しいセッションを再起動すると、持続データはリセットされ、その動作設定は再適用されます。
プレイテスト セッション: プレイテストをクリエイター ポータルで設定すると、プレイテスターがプレイテスト コードまたはプライベート リンク コードで参加したときに、持続データの動作設定が適用されます。 持続データの動作設定は、プレイヤーが最初に参加したときにのみ適用されます。 プレイヤーがプレイテストから離脱し、再びプレイテストに参加した場合、そのデータはセッションをまたいで持続し、持続データの動作設定は再適用されません。 持続データをリセットするには、新しいプレイテスト リンク コードを作成する必要があります。
持続データの管理と更新に影響を与える島の更新については、UEFN からのセッションの起動と、リンクコードを使用したプレイテストの両方のシナリオでテストすることをお勧めします。 持続データに加えた変更は、必ずライブ データとシミュレートした新しいユーザー データの両方でテストしてください。 そうすることで、現在、島でプレイしているプレイヤーと新しくプレイするプレイヤーのどちらにも、確実に更新が適用されるようになります。
島の新しいバージョンを公開する影響
島が公開されると、プレイヤーのデータがweak_mapに格納される際にプレイヤーの持続型レコードが作成されます。 このデータは格納され、次回以降に島に訪れるたびにロードされます。
島の新しいバージョンが公開されると、持続データは自動的に新しいバージョンに統合されます。 詳細は、「島の公開済みバージョン間でデータを修正する」を参照してください。
公開済みの島をロールバックする影響
クリエイターポータルを通じて島を以前のバージョンにロールバックすると、全てのユーザーの持続データがリセットされます。
現在のところ、ロールバックによってデータが影響を受けたことをプレイヤーに通知するサポートはありません。
この仕様により、最近のプレイヤー データの更新が失われ、完全にリセットされることもあります。 ロールバックが内部的に持続データに影響を与えるようなロジックの変更を含んでいない場合でも同様です。
ロールバック機能は持続データに影響を与えるため、最終手段としてのみ使用することをお勧めします。
制限事項
以下は、Verse で持続データを扱う際の制限事項です。
持続オブジェクトの最大サイズ
weak_map に格納できるプレイヤー 1 人当たりのデータ量には限界があります。
weak_mapレコードとは、1つのweak_map要素に関連付けられたデータの総量です。 1 つの weak_map レコードの最大データサイズは、プレイヤー 1 人当たり 256 キロバイト (KB) です。
「weak_map」値が保存されるとき、データの保存に必要なメモリの総量が計算されます。
上限である 256KB を超える恐れのあるデータの例を以下に挙げます。
およそ 24,000 個の
floatまたはint値。約 200,000 文字のテキスト。 これは平均的な小説の約 60 ページ分の量です。
プレイヤー レコードに 256KB を超えるデータを保存しようとすると、失敗して Verse のランタイム エラーが発生します。
FitsInPlayerMap Verse ヘルパー関数を使用すれば、保存の失敗を回避できます。 関数 FitsInPlayerMap は保存の対象となるレコードのコピーを取り、そのサイズをチェックします。 レコードを保存できる場合は、関数の呼び出しは成功します。レコードが大きすぎる場合は失敗します。
特にデータの動的な array または map を扱ったり、それらに新しい要素を追加したりする場合に、関数 FitsInPlayerMap が便利です。 以前に持続レコードにあった int、float、または logic を更新しても、持続レコードのサイズは変わりません。
島当たりの持続プレイヤー Weak Map の最大数
1 つの島は最大 4 個の持続変数、つまり 4 個の weak_map 変数を player をキー型として持つことができます。 この要件は Verse コンパイラにより課されています。
必須のクラス型付き Weak Map
持続変数の最大数の制限が満たされている場合、1 つ以上の持続変数の weak_map 値はクラスである必要があります。 これは、後で島を公開する際の後方互換性を満たしつつも後からデータを変数に追加することができるようにするためです。