7年前、Unreal Engine 4 で一度steamのフレンド機能を利用したオンラインマルチプレーヤーゲームを作ったことがあったが、その時はUEに対する理解度の低さやマルチプレーヤー特有の知識が必要でかなり苦労をした記憶がある。
あれから7年経ちUEも5になり、自分の制作知識や技術も上がってきたことで心理的・技術的ハードルがだいぶ下がってきたこともあり、そろそろオンラインマルチについてしっかり学んでおこうかなという気になった。
オンラインマルチプレイ機能の実装について躓いたところや学んだ知見を未来の自分のためにここに記しておく。
・Run on Server - Multicast という基本的な手法について
Run on Server は文字通りサーバーで実行だが、その後マルチキャストにしたカスタムイベントをつなぐという基本的な手法について理解が追いついておらずぼんやりとした雰囲気で当時は作っていた。
Run on Server は文字通りこのカスタムイベントはサーバーで実行しなさい、という命令で、その後ろにマルチキャストのカスタムイベントを置くと、サーバーでマルチキャストを実行しなさい、という命令になる。マルチキャストのカスタムイベントは全てのゲームクライアントで実行しなさい、ということ。
例えば、プレーヤーBが敵の攻撃を受けて血を流して死ぬとする。プレーヤーBのキャラクターBP内でその処理を書いてもプレーヤーBの画面でしかBは血を吐いて死なない。全てのプレーヤーの画面でBが血を吐いて死ぬ、という事象を発生させるには、サーバーから「みんなプレーヤーBの死を一斉に起こしてね」という指示が必要。Run on Server でマルチキャストのカスタムイベントを実行するというのはそういう理屈。サーバーに向かって、「”みんなにプレーヤーBの死を一斉に引き起こしてね”と指示しなさい」という命令をしている。
・レプリケートについて
レプリケートは、サーバー内で変更があったらその変更を自動的に随時受け取り更新します、という設定。重要なのが、クライアントで発生した変更を随時サーバーへ送ります、という機能はない。サーバーからクライアントへ一方通行。
例えば、プレーヤーはそれぞれヘルスという変数を持っていて、その変数はレプリケートがオンになっているとする。プレーヤーAのヘルスが初期値10で、プレーヤーAが毒薬を飲んでAのクライアントでヘルスが5になっても、サーバーでは10のままなので、自動的にすぐ10に戻される。ちゃんとみんなでヘルスの減少を共有するなら、Run on Server のカスタムイベントでプレーヤーAのヘルスを5にする必要がある。レプリケートされる変数であれば自動でサーバーからクライアントに同期されるので、マルチキャストは不要。
・一斉に全員にBP内のカスタムイベントを実行させる処理について
セッション参加直後、各プレーヤーに名前を入力してもらい、各キャラクターの頭上に名前を表示する、という機能を実装しようとしたとき躓いた。
名前を入力してOKボタンを押したら、キャラクターBP内のRun on Serverカスタムイベントへ飛んで、入力した自分の名前をplayer stateに保存し、マルチキャストで自分のplayer state から自分の名前を確認し、自キャラの頭上にそれぞれの名前を表示する、という記述をした。しかしこのロジックではだめで、他人の名前は表示されなかった。
これは先程のヘルスの例を思い出してくれれば当然なのだが、セッションに参加しているあるプレーヤー鈴木が毒薬を自ら飲んで自分のヘルスを-5し、それをマルチキャストしたところで鈴木のヘルスが-5されたという情報が同期されるだけである。全てのプレーヤーでヘルスが-5されるわけではない。
同様に、今回自分で書いた処理も、鈴木が「鈴木」と名前をplayer stateに保存しました、鈴木はplayer stateから自分の名前を確認して鈴木の頭上に表示します、というのがマルチキャストされているだけ。あらかじめ参加している佐藤や田中には、鈴木のクライアントでは「自分の名前を確認して頭上に表示します」という処理が走らないため、鈴木からは佐藤や田中の名前が見えない。一方で先に参加している佐藤や田中からは鈴木の名前は見える。
必要なのは、全プレーヤーが一斉に「自分の名前を自分のplayer stateから確認し、頭上に表示する」という処理。具体的には、Run on Serverで Get All Actors Of Class (CharacterBP) → For Each Loop で全てのプレーヤーのBP内にある「自分の名前を player state から確認し頭上に表示する」というマルチキャストのカスタムイベント を実行すればよい。
・オンラインでセッション作成や参加がうまくいかない時用のログの取り方
exeのショートカットを作り、プロパティ→リンク先を "場所” -log としてOK、ショートカットを起動するとログも表示される。
・Steam経由でセッション参加時のビルド不一致エラーについて
オンラインマルチ開発中は steam app id = 480 を使うと思うが、これが原因で問題を起こしていて悩んだ。
セッション検索機能を実装せず、セッションへの参加を自動にしている場合、これのせいで見知らぬ人の見知らぬゲームに参加しようとする場合がある。当然違うゲームなのでできない。セッション検索機能で知らない人のゲームが引っかかるのも煩わしいので、自分のゲームだと識別したい場合、自分でKEYを設定できる。Make Literal Session Property String で適当な文字列の組み合わせを鍵代わりに作って、Extra Settings に追加した状態でセッションを作ればよい。検索する側は、ForEachLoopで、その鍵と同じ文字列かどうか確認していく。画像を見た方が速いので画像を貼っておく。


・マルチプレイでP2P接続を拒否られるエラーについて
SteamセッションはみつかっているのにP2Pが確立できない場合、相手のWindowsDefenderが悪さをしている可能性がある。
Windows Defender ファイアウォール → 詳細設定 → 受信の規則 → 新しい規則
ポート → TCP → 特定のローカルポート:7777 → 接続を許可 → 全てチェック → ゲーム名とか適当に名前つけておいて完了
同様にUDPポートも開いておく
・一度セッションに参加してAlt+F4でゲームを終了すると、再度ゲームを起動した時に画面が真っ暗になる問題
DestroySessionしないとSessionが残る。
またどこかで引っかかったら追記していく。

















