#memo

indiedev太郎

フレームワークについて

マルチプレイの実装みてて、今あらためてフレームワークの役割をちゃんと見ておく必要ある、これはかなり初期にやっておくべきだった感ある
まず適当にゲーム起動して、WorldOutlinerで何があるかみる、ViewOptionsからサーバーに何がありクライアントになにがあるかも見る

ふつうFPS
プレイ人数: n

サーバー側
GameMode(*)
GameSession(*)
GameNetworkManager(*)
GameState
ParticleEventManager
HUD
PlayerController x n
PlayerCameraManager x n
PlayerState x n
CameraActor x n

クライアント側
GameState
ParticleEventManager
HUD
PlayerController x 1
PlayerCameraManager x 1
PlayerState x n
CameraActor x n

とりあえずこのリスト見ながらクラスを見ていく
プログラム実行順は、Level->GameMode->各位

Game

アウトライナでは確認できないけれど、ゲームオブジェクトの中心的存在で、最初に作成される
パーシスタントレベルのロードなどを行い、いろいろなインスタンスを作成していく
クライアントにユニークな存在で、唯一サーバーからレプリケーションされないクラス(のはず)

GameMode

Unreal Engine | GameMode

サーバー側にしか存在せず、クライアント側ではGetGameModeはNullになってしまう
クライアントはゲーム参加時、サーバーのGameModeにログインして良いか尋ねに行き、ログインが成功した場合そのユーザー用に作成されたPlayerControllerがOnPostLogin関数で帰ってくるので、ユーザーごとの初期化処理みたいなのはそこで記述する

GameSession

GameModeが生成する、のでサーバー側のみ存在する
同時接続可能最大人数とかの設定や、新しくプレイヤーが参加した時にコントローラー作成とか、プレイヤーをbanしたり、そういったプレイヤー入退出全般の処理をやっている、自分で書いた処理でアクセスするのは稀になりそう

GameNetworkManager

サーバーのみに存在

GameState

全クライアントに存在する、サーバークライアント間で一つのインスタンスを共有している
なのでプレイヤー全員が共通のプロパティを乗せる、試合のラウンド数、共通のクエスト目標、、、
クライアントでは、レベルBPのBeginでも絶対にアクセスできる唯一の変数なので、サーバーに通知する必要のないクライアント固有のプロパティみたいな物も置ける、例えばマップのロードは完了しているか等

PlayerController

各クライアントに唯一ユニークに発行されるので、クライアントのみの処理や、サーバーへの値送信はこのインスタンスで行う
Listenサーバーの場合は全クライアント+自分のPlayerControllerを持っている、いずれの場合もGetPlayerControllerのインデックス番号0が必ず自分のContorollerとなっている
サーバーのGameModeがログイン処理の過程で生成するので、クライアントの特にゲーム参加の初期段階では、LevelBP等からアクセスできる保証はない
サーバーに値を送信するときは、そのイベントが実行されたインスタンスをクライアントがOwningしているかどうかで棄却するかを決定するのだけれど、PlayerControllerがこのOwningの中心的存在で、アクタをスポーンするとき、Owning引数に自分のPlayerControllerの参照を渡すことで、新たに生成したアクタもクライアントがOwningしているという扱いになり、そのアクタでもサーバーに対してのイベントが行えるようになる(代表的なのがPlayerPawn)

PlayerCameraManager

PlayerControllerが生成する、ゲーム中のカメラの挙動全般の処理をやる

PlayerState

全クライアントに存在する
PlayerName、Pingなど、ユーザーの個人情報みたいな変数が詰まっている
PlayerControllerが作成されるとき、同時にPlayerStateも発行されて(観戦者じゃないなら)紐付けられるので、クライアントではPlayerController経由で自分のPlayerStateにアクセスすることができる

APlayerState::SetPlayerName
SetPlayerNameを実行すると、PlayerNameの実際の変更に関係なく、クライアントかListenサーバーホストでOnRep_PlayerNameを実行するようになっている
この場合、違う名前をセットした場合、PlayerName自身のReplicatedUsingで2回(なぜ…)、この関数内の呼出で計3回OnRep_PlayerNameが動く

APlayerState::OnRep_PlayerName
初回アクセス時の名前変更か、ゲーム中の名前変更かでAPlayerController::ClientReceiveLocalizedMessageを違う引数で実行
Unreal Engine | APlayerController::ClientReceiveLocalizedMessage
メンバ変数のbHasBeenWelcomedのset, getはこの関数内部でしか使用されてない

UEngineMessageは抽象クラスULocalMessageを継承したクラスで、マルチプレイのプレイヤーの状態変更に応じたメッセージをコンソールに送ったりする


参考
Unreal Engine | ゲームプレイ フレームワークのクイック リファレンス
Unreal Engine | ブループリントのマルチプレイヤー機能