This document is about: QUANTUM 3
SWITCH TO

新機能紹介

Quantum SDKがUnitypackageになりました

Unitypackageになったことで、初期設定やアップグレードが誰でも簡単になりました。将来的には、アセットストアやUPMで配布する予定です。

  • QuantumGame(以前まではquantum.codeプロジェクト)のソースは、Unityのアセット側(Assets/QuantumUser/Simulation)に移動しました。
  • Unity CodeGenステップは削除され、すべてのコード生成はUnity Editor中のQtn/DSL CodeGenで行われます。
  • Unityとの統合を整理するため、相当数のQuantumの型やスクリプトが移動/リネーム/マージされます。マイグレーション中、スクリプトのGUIDは保存され、コンパイルエラー数を減らすため、廃止されるスクリプトの旧名称がQUANTUM_ENABLED_MIGRATIONから与えられます。
  • [SerializeReference]やOdin固有のシリアライズ拡張を含む、Unity/Odinのプロパティ属性が自由に使用できます。ただし、決定論的ではないUnityのAPIが非推奨であることは変わりません。
  • 新規アセットには決定論的なAssetGuidが与えられます。これによって、すべてのQuantumアセットはローディングなしに収集されるため、処理速度が劇的に向上します。
  • AssetObjectScriptableObjectになり、AssetBaseは不要になりました。これによって、アセットのヒエラルキーはより柔軟になり、partialクラスを拡張するモデルには制限されなくなりました。
  • レガシーコードを削減するため、最小Unityバージョンが2021 LTSに引き上げられました。

例えば.Netコンソールアプリケーション上やカスタムサーバープラグイン上で、Unityに依存せずにシミュレーションDLLをコンパイルすることも可能です。

SDKの内容の詳細はQuantum Projectをご覧ください。

Quantumアセンブリ名の変更

以下のQuantumライブラリはリネームされました。

  • PhotonDeterministic.dll -> Quantum.Deterministic.dll
  • quantum.core.dll -> Quantum.Engine.dll
  • quantum.code.dll -> Quantum.Simulation.dll

入力のデルタ圧縮

入力メッセージはデフォルトでデルタ圧縮されるようになったため、通信量が劇的に削減されます。サーバーメッセージのネットワークトランスポートモードはReliableに変更され、Quantumの入力プロトコルは単純化しました。

デフォルトではデルタ圧縮が有効ですが、無効にすることも可能です。

リプレイもデルタ圧縮された入力が保存されるため、サイズが非常に小さくなります。

プレイヤー追加/削除の新プロトコル

Quantumの開始プロトコルは、最初に枠を予約せずに、実行時にプレイヤーの追加/削除ができるように変更されました。

AddPlayer()RemovePlayer()が、SendPlayerData()を置き換えます。SendPlayerData()とは異なり、AddPlayer()はスロットごとに一度だけ送信できます。

シミュレーションは、ISignalOnPlayerAddedISignalOnPlayerRemovedシグナルから、プレイヤー追加/削除に反応できます。

ビューは、CallbackLocalPlayerAddConfirmedOnLocalPlayerRemoveConfirmedから、ローカルプレイヤーのスロット追加に反応できます。同様に、OnLocalPlayerAddFailedOnLocalPlayerRemoveFailedから、そのエラーに反応できます。

AddPlayer()はサーバー側で送信頻度に制限があるため、スパムはできません。

API全体を通して、プレイヤー(PlayerRef)とプレイヤースロット(ローカルプレイヤー)を明確に区別するため、パラメーター名がわずかに変更されています。

Playerは常に実際のグローバルなプレイヤーのインデックスを参照しますが、PlayerSlotは常にローカルのプレイヤースロットを参照します。プレイヤースロットは、例えば、一つのクライアントで複数のプレイヤーを制御する際に使用されます。ローカルのプレイヤースロットを一つだけ使用するなら、そのスロットは0になります。

例えば、入力コールバックCallbackPollInputPlayerSlotプロパティを使用するようになり、QuantumGame.AddPlayer(Int32 playerSlot, RuntimePlayer data)にも、ローカルのプレイヤースロットを識別するための明確な名前のパラメーターがあります。

詳細はPlayerをご覧ください。

予測コマンド

コマンドは、次の予測フレームから直ちに実行可能になりました。これは以前から要望のあった機能ですが、新バージョンで入力プロトコルを改善したことで、この機能がついに実現できるようになりました。

送信したコマンドは、次の予測フレームに追加され、検証済みでないフレームでも実行可能になります。実際に予測されるティック値は99.9%正確です。

これにより、コマンドの応答性が向上し、変更を速やかにゲームプレイに反映できます。

Webhook

Webhookは、独自のバックエンドによってゲームの安全性を高めるものです。ルーム作成・ルーム参加・RuntimePlayerRuntimeConfigは、HTTPリクエストを使用するバックエンドから傍受・検証できます。

Webhookによって、サーバーから直接リプレイのストリーミングも可能です。

これらは、Photonのダッシュボードから有効化・設定できます。

詳細はWebhook Online API Documentationをご覧ください。

Quantum 3 AppId

Quantum 3のアプリケーションは、Photon Dashboard上から、Quantum 3 AppIdを作成する必要があります。

詳細はQuantum Asteroids Tutorial - Project Setupをご覧ください。

Photon Realtime 5

Realtimeの新メジャーバージョンには.Netのasync拡張が含まれるため、ネットワーク接続周りの記述・制御がしやすくなります。

Photon Realtimeのリリースノートを必ずお読みください。

Photonクライアントの接続を開始し、Photonのルームに参加するには、以下のようにawaitでメソッドを呼ぶだけです。

C#

MatchmakingArguments connectionArguments = new MatchmakingArguments {
    PhotonSettings = PhotonServerSettings.Default.AppSettings,
    PluginName = "QuantumPlugin",
    MaxPlayers = 8,
    UserId = Guid.NewGuid().ToString(),
    NetworkClient = new RealtimeClient { ClientType = ClientAppType.Quantum }
};

RealtimeClient client = await MatchmakingExtensions.ConnectToRoomAsync(connectionArguments);

デフォルトでは、すべてのエラーは例外として投げられます。async APIの呼び出しは、try/catchブロックで囲う必要があります。

Realtime拡張の詳細はPhoton Async Extensionsをご覧ください。

SessionRunnerクラス

QuantumRunnerSessionContainerSessionRunnerクラスにマージされ、Quantum Gameプロジェクトに置かれました。このクラスは、Photon Realtime 5ライブラリを使用しています。

Quantumのゲームセッションは、asyncでも非asyncでも開始できます。

C#

SessionRunner.Arguments sessionRunnerArguments = new SessionRunner.Arguments {
    RunnerFactory = QuantumRunnerUnityFactory.DefaultFactory,
    GameParameters = QuantumRunnerUnityFactory.CreateGameParameters,
    ClientId = client.UserId,
    RuntimeConfig = runtimeConfig,
    SessionConfig = QuantumDeterministicSessionConfigAsset.DefaultConfig,
    GameMode = DeterministicGameMode.Multiplayer,
    PlayerCount = 8,
    StartGameTimeoutInSeconds = 10,
    Communicator = new QuantumNetworkCommunicator(client),
};

QuantumRunner runner = (QuantumRunner)await SessionRunner.StartAsync(sessionRunnerArguments);

awaitが完了するのは、Quantumの開始プロトコルが完了し、最初のスナップショットを受信した時です。

接続してからQuantumのシミュレーションをオンラインで開始するまでの最も簡単な方法については、QuantumSampleConnection.unityシーンをお試しください。

新しいSDKサンプル

新しいSDKには、シンプルなAsteroidsゲームサンプルが付属しており、QuantumHubからインストールできます。

新しいデモメニュー

新しいデモメニューは、Quantum 2.1のロビーメニューサンプルを置き換えたものになります。(Unity.UIでの)見た目のアップグレードと、二つのシンプルなオンラインモード(ランダムマッチメイキング・部屋コード共有)を実装しています。

デモメニューのコードとプレハブは、SDKのunitypackageで配布されており、QuantumHubのTutorials&Sampleセクションからインストールできます。

拡張可能性と接続ロジックの複雑性の制御はトレードオフですが、これらが適切なバランスになるように設計されています。メニューパーツの実装やプレハブは、Fusionなどの他のSDKでも使用されています。

Quantum 3 Demo Menu
Quantum 3 Demo Menu
Quantum 3 Demo Menu
Quantum 3 Demo Menu
Quantum 3 Demo Menu

デモシーンではTextMeshProを使用しています。最初にデモシーンが開いた時に、TMPインストールのポップアップが表示されます。

Quantum.Unityのアセンブリ定義は、TMPのUnitypackage(com.unity.textmeshpro)が見つかった際にQUANTUM_ENABLE_TEXTMESHPROを設定するため、QuantumのメニューのスクリプトはTMPが無効でもコンパイルされます。

メニューのカスタマイズ方法についての情報はSample Menu Customizationをご覧ください。

RuntimeConfigとRuntimePlayerのJSONシリアライゼーション

これらファイルの手動のシリアライゼーションは、JSONに置き換わりました。ファイルがQuantumプロトコルで送信されることは変わりませんが、JSON文字列で圧縮されます。

元々のシリアライゼーションは常にメンテナンスを必要とし、面倒で、エラーの原因になっていました。さらに、WebhookのHTTPリクエストでコンフィグを送信する際に、受信したバックエンド側は、正しくデシリアライズするために元のC#コードが必要でした。

SerializeUserData()メソッドは廃止されました。

コンフィグをバイト列にシリアライズするには、QuantumGame.RuntimePlayerSerializerが必要です。これは開始時にSessionRunner.Argumntsで設定できて、通常はデフォルトのQuamtumのJSONシリアライザーであるQuantumJsonSerializerに設定されます。

C#

var runtimeConfig = new RuntimeConfig();
var runtimeConfigBinary = RuntimePlayer.ToByteArray(runtimeConfig, new QuantumJsonSerializer());
var runtimeConfigOther = RuntimePlayer.FromByteArray(runtimeConfigBinary, new QuantumJsonSerializer());
// make sure to check if runtimeConfig and runtimeConfigOther are equal to validate the json serialization

RuntimePlayer(またはコマンド)のシリアライズ済みバイナリの最大サイズは、24kBです。もし、複数のクライアントがこの方法で大きなデータチャンクを送信した場合、一つの入力メッセージには収まらないため、サーバーが受け入れるのは次のティックになります。

Quantum Hub

重要な設定ファイルが見つからない時に、Quantum Hubがポップアップします。Fusion SDKによって、Hubウィンドウの使用が、ユーザーファイル(packageに含まれないもの)のインストールや生成を行う最も便利な方法であることが証明されました。セットアップが必要なのは一度のみで、ファイルはプロジェクトと一緒にバージョン管理されます。

Quantum 3 Hub

Quantum CodeDoc Inspectors

Quantum Unity Inspectorsはビジュアルが更新され、XMLのインラインコードコメントからトグル可能なヘルプテキストが生成されます。

Quantum 3 Code Doc

データ駆動のシステムセットアップ

Quantumで起動するシステムの選択は、ゲームモードやマップ選択によって変わります。SystemsConfigアセットを使用して、データ駆動アプローチが導入されました。異なるシステムとサブシステムの組み合わせは、RuntimeConfigアセットで参照されるようになりました。

System Configs Asset

Quantum 2.1の静的なSystemSetup.CreateSystems()は動作しますが、廃止が検討されていて警告ログが出ます。このクラスは、Quantum 2.1のプロジェクトをアップグレードし、コンテンツを移行した後に削除できます。

システムは、以下の順で作成されます。(DeterministicSystemSetup.CreateSystems()をご覧ください)

  • 古いSystemSetup.CreateSystems()クラスとメソッドが存在する場合(リフレクションでチェックされます):これが呼び出され、残りはスキップされます
  • 与えられたSystemsConfigに登録がある場合:システムが作成・追加され、処理を継続します
  • 与えられたSystemsConfigが無効、または登録がない場合:デフォルトのシステムが作成・追加され、処理を継続します
  • 最後にDeterministicSystemSetup.AddSystemsUser()が呼び出され、仕上げを行います

古:file: quantum_code/quantum.code/SystemSetup.cs

C#

namespace Quantum {
  public static class SystemSetup {
    public static SystemBase[] CreateSystems(RuntimeConfig gameConfig, SimulationConfig simulationConfig) {
      return new SystemBase[] {
          // ..
      }
    }
  }
}

新:file: Assets/QuantumUser/Simulation/SystemSetup.User.cs

C#

namespace Quantum {
  using System.Collections.Generic;

  public static partial class DeterministicSystemSetup {
    static partial void AddSystemsUser(ICollection<SystemBase> systems, RuntimeConfig gameConfig, SimulationConfig simulationConfig, SystemsConfig systemsConfig) {
      systems.Add(new TestSystemMainThreadGroup("TestSystemsGroup", new SystemMainThread[] { new TestSystemImmediateRemoveDestroy(), }));
      systems.Add(new TasksTestSystem());

3Dカプセル形状

Quantum Physicsが、ついに2D/3Dのカプセル形状に対応しました。

最大コンポーネント数

最大コンポーネント数が512に引き上げられ、qtnファイル内で調整できるようになりました。

#pragma max_components 512

Entity Viewフレームワーク

UnityスクリプトのEntityViewComponentを使用することで、ゲーム状態に素早く反応するビューのコードを追加できます。

Entity View Component

Entity Viewプール

QuantumEntityViewPoolを使用して、EntityViewを簡単にプールできます。

Entity View

Character Controllerアドオン

新しいカプセル状の衝突判定に基づく、新しいKinematic Character Controllerが、アドオンとして使用可能になりました。

Quantum 3 KCC Addon

決定論的なナビメッシュのベイク

Quantumのナビメッシュのベイクが決定論的になりました。実行時にナビメッシュを生成するゲームには朗報です。デフォルトのパイプラインはまだ、Unityの(決定論的ではない)メッシュのインポートに依存していますが、最終的には置き換わります。

ナビメッシュのベイクは、UnityからQuantumGameのシミュレーションコードに移動しました。(個別のリリースノートをご覧ください)

ダッシュボードのオプション

デフォルトでは、Quantum3のアプリケーションは、非プロトコルメッセージとプレイヤープロパティをブロックします。これらのレガシーな機能は、潜在的には悪意ある人によって、マッチメイキングやQuantum製アプリケーションのゲームプレイが阻害されてしまう可能性があります。この機能をアンロックするには、各AppIdで明示的にダッシュボードのプロパティを設定する必要があります。

  • BlockNonProtocolMessages (true/false)
  • BlockPlayerProperties (true/false)

BlockRoomProperties(新)

データ型:boolean (true/false)

プラグインは、ルーム作成後にクライアントから設定されるすべてのルームプロパティをキャンセルします。ただし、StartQuantumプロパティは除きます。ルームプロパティの初期値は、Webhookからも取得可能です。

注意:これはOpenIsVisibleにも影響します。

AllowedLobbyProperties(新)

データ型:string (有効なセパレーターは、, か ; かスペース)

最大プロパティ数:3

最大stringプロパティ長:64

マスターサーバー上でのマッチメイキングのパフォーマンスを維持するため、クライアントがロビープロパティとして送信できるプロパティのリストを設定します。このプロパティが設定されると、クライアントから送信されたリストに含まれないプロパティは除外されます。これは、プラグインのログのRestricted LobbyPropertyでわかります。

デフォルトでプロパティのデータ型は以下に制限されます:bool, byte, short, int, long, string

MaxPlayerSlots(新)

データ型:int

デフォルトでは、クライアントはゲームがサポートしている数の分だけローカルプレイヤーを作成できます。この値を設定することで、このAppIDで実行されるすべてのゲームで、作成できる数を制限できます。この値は、Webhookからも設定できます。

StartPropertyBlockedTimeSec(新)

データ型:int

値を0より大きく設定すると、ルームが作成されてから最小秒数が経過するまで、Quantumの開始がブロックされます。これは、ゲームが開始される前に、プレイヤーに十分な参加時間を確保するために使用できます。

StartPropertyForcedTimeSec(新)

データ型:int

値を0より大きく設定すると、ルームが作成されてからQuantumが開始されるまでの最大秒数になります。設定時間が経過すると、ルームプロパティのStartQuantumプロパティが(もしまだ設定されていなければ)trueに設定されます。

HideRoomAfterStartSec(新)

データ型:int

値を0より大きく設定すると、Quantumが開始されてから設定秒数まで、ルームがパブリックな検索やリストから隠されます。ルームの可視性を管理して、既に開始中のゲームに新規プレイヤーが参加しないことを保証できます。

CloseRoomAfterStartSec(新)

データ型:int

値を0より大きく設定すると、Quantumが開始されてから設定秒数まで、ルームへの参加が不許可になります。ルームへの参加を不許可にすることで、新規プレイヤーの参加を拒み、ゲームセッションのライフサイクルの管理に使用できます。

Back to top