所有権モード
概要
権限によって、ネットワークオブジェクトのプロパティへの書き込みが許可されるクライアントが決定します。サーバーが受け入れるのは権限を持つクライアントの値のみで、その他のクライアントには読み取り専用のコピーが送信されます。Fusionには複数の所有権モードが用意されていて、FusionSharedReplicatorノードから権限の割り当てや移行方法を制御できます。
プロパティの設定/同期方法については、プロパティの同期をご覧ください。
このページで説明される権限移行API(want_authority・authority_requested・authority_responseシグナル)はFusionSharedReplicatorで動作します。クライアントサーバートポロジーでは異なる権限モデルが使用されます。詳細は予測と入力をご覧ください。
Owner Mode
ユースケースに合わせてモードを選択してください:
| 用例 | モード |
|---|---|
| プレイヤーアバター・装備アイテム・ペット | Player Attached |
| ピックアップアイテム・乗り物・インタラクション可能な小道具 | Transaction |
| 高速移動する物理オブジェクト(ボール・ホッケーのパック) | Dynamic |
| スコアボード・試合タイマー・シングルトン | Master Client |
Transaction
サーバーが所有権の移行を確認します。クライアント間で権限を移行する方法は2つあります。
Live Handshake(オブジェクトを所有したまま移行):別のクライアントが所有しているオブジェクトに対してwant_authority(true)を呼び出します。所有者側では、誰がリクエストしたかを含むauthority_requestedシグナルが発火するので、移行を許可する場合はtrue、拒否する場合はfalseを返します。その後、リクエストしたクライアント側は、その結果を含むauthority_responseを受信します。拒否された場合は、通常want_authority(false)を呼び出して、保留中の意思を破棄します。
Orphan-then-Claim(先にオブジェクトの権限を放棄):現在の所有者がwant_authority(false)を呼び出すと、オブジェクトは孤立(get_owner_id() == 0)状態になります。他のクライアントは、authority_requested/authority_responseのやり取り無しで、want_authority(true)を直接呼び出してオブジェクトの権限を取得できます。所有者の切断時もオブジェクトは孤立するため、同様の方法で権限を取得できます。
オブジェクトの孤立中、プロパティは最後に複製された値のまま維持されます。書き込み権限を持つクライアントがいないため、別のクライアントがオブジェクトの権限を取得するまで状態は凍結されます。複数のクライアントが同時に孤立オブジェクトの取得を試みた場合、サーバーは最初に処理したリクエストを受け付け、それ以外を黙って無視します。権限の取得が成功したかどうかは、has_authority()を確認するか、authority_changedを購読してください。
GDScript
# ピックアップアイテムや乗り物の例
func _on_interact(player):
$FusionSharedReplicator.want_authority(true) # 接触時にリクエストする
func _on_exit(player):
$FusionSharedReplicator.want_authority(false) # 手放した時に解放する
Player Attached
移行の仕組みはTransactionと同様ですが、1つ重要な違いがあり、所有しているプレイヤーが切断されると、オブジェクトはサーバーによって自動的にデスポーンされるという点です。プレイヤーのアバター・プレイヤー所有のアイテムなど、所有者より長く存在してはいけないオブジェクトにはこれを使用してください。
Dynamic
サーバー確認を待つと遅く感じられるような、ハイペースな所有権移行のために設計された権限予測です。このモードでは、authority_requested/authority_responseは発火しません。移行全体は、呼び出しごとの送信レート更新間隔によって制御されます。
want_authority(true)は、クライアントはローカルで即座に所有権を割り当て、最大の送信レートでデータ送信を開始します。サーバーが受け入れた場合、特別な処理は行われず、クライアントはそのまま権限者になります。サーバーがリクエストを拒否した場合(別のクライアントのリクエストが先に到達した場合など)は、権限は元に戻されます。
want_authority(false)は、クライアントは送信レートを下げて所有権を放棄する意思を示します。これによって、サーバーは別のクライアントの予測的なリクエストを受け入れることができるようになります。他のクライアントに権限が引き継がれたことがサーバーに確認された後、クライアントは自動的に権限を再リクエストすることはありません。
| 呼び出し | update_interval |
|---|---|
want_authority(true) | 1(毎ティック) |
want_authority(false) | 16(低レート) |
権限者の送信レートを下げることで、サーバーが動的なリクエストを受け入れやすくなります(新しいクライアントが新しいデータを送信するための十分な余裕を持たせられるためです)。第二引数に大きな値を指定して送信レートを下げる(例:want_authority(false, 32))ことで、より確実に解放しやすくなります。
GDScript
# 物理ボール - センターラインで所有権が移行される(ポンゲームのパターン)
func _physics_process(delta):
if not $FusionSharedReplicator.has_authority():
if ball_crossed_my_half():
$FusionSharedReplicator.want_authority(true) # predictive claim
else:
if ball_left_my_half():
$FusionSharedReplicator.want_authority(false) # yield ownership
else:
apply_physics(delta)
Master Client
現在のマスタークライアントによって常に所有されます。want_authority()呼び出しは無視されます。マスタークライアントが切断された場合、Photonは新しいマスタークライアントを割り当て、所有権は自動的に移行されるため、アプリケーション側での処理は不要です。シングルトンで共有される状態(スコアボード・試合のタイマー・GameManagerオブジェクトなど)に使用してください。
権限のリクエストと放棄
GDScript
$FusionSharedReplicator.has_authority() # 自身が現在の所有者か?
$FusionSharedReplicator.get_owner_id() # どのプレイヤーがこのオブジェクトを所有しているか?
$FusionSharedReplicator.want_authority(true) # 所有権をリクエストする
$FusionSharedReplicator.want_authority(false) # 所有権を放棄する
want_authorityメソッドは、オプションで第二引数(update_interval)を受け取り、クライアントがプロパティ更新を送信する頻度(ティック単位)を制御できます。これは主にDynamicモードに関連します。
authority_changed シグナル
authority_changedシグナルは、モードに関係なく、所有権が変わるたびにFusionSharedReplicatorノードで発火します。権限移行に反応するには、このシグナルに接続してください:
GDScript
func _ready():
$FusionSharedReplicator.authority_changed.connect(_on_authority_changed)
func _on_authority_changed(has_authority: bool):
if has_authority:
print("I now own this object")
authority_requested シグナル
現在所有しているオブジェクトに対して、別のクライアントが所有権をリクエストすると、FusionSharedReplicatorでauthority_requested(requester_id)シグナルが発火します。権限の移行を許可する場合はtrueを、所有権を維持する場合はfalseを返してください。Fusionは返された値に基づいて、その意思と送信レート更新を内部的に処理します。このシグナルはTransactionとPlayer Attachedモードで適用され、DynamicやMaster Clientモードでは発火しません。
GDScript
func _ready():
$FusionSharedReplicator.authority_requested.connect(_on_authority_requested)
func _on_authority_requested(requester_id: int) -> bool:
return not _is_busy_with(self)
複数のシグナルハンドラーが接続されている場合は、いずれかのハンドラーがtrueを返すと移行が許可されます。
authority_response シグナル
want_authority(true)呼び出し後に、Transaction/Player-Attachedハンドシェイクが解決されると、リクエスト元はauthority_response(accepted: bool)から結果を受け取ります。拒否された場合は、これを使用して保留中の意思を削除してください:
GDScript
func _ready():
$FusionSharedReplicator.authority_response.connect(_on_authority_response)
func _on_authority_response(accepted: bool) -> void:
if not accepted:
$FusionSharedReplicator.want_authority(false)
孤立したオブジェクトでは、このシグナルは発火しません(交渉すべき所有者がいないため)。直接的なリクエストが成功したかどうかを確認するにはauthority_changedを購読してください。Dynamic/Master Clientでは、このシグナルは決して発火しません。