nnnnnnn0090
← research

research — case study

ブループロトコル:スターレゾナンス

『ブループロトコル:スターレゾナンス』(中国語名:星痕共鳴)の通信・クライアント実装の調査メモ。Gateway / World の分離、Lua 層、キャラごとの Attr リスト。

Gateway と World は、別々に接続する 2 段構成

パーティ調整は Gateway、マップ入場・切替の実行は World。初回入場とフィールド内移動で経路が少し違う。

クライアント

① Gateway に接続

Gateway

パーティ — 作成・招待・投票

初回入場 — World の接続先を通知

IP・ポート・トークン

② World に接続

World

入場を確定

シーン切替(マップ移動・ダンジョン)

Attr + パーティ情報を同期

01/Servers

Gateway / World 分離

クライアントは Gateway と World の 2 つに別々に接続する。まず Gateway で World の接続先を受け取り、次に World でプレイする。

Gateway がやること

  • 最初につなぐサーバー
  • パーティ — 作成・招待・参加・マッチング・活動開始・入場投票
  • 初回マップ入場 — World の接続先(IP・ポート・トークン)を通知
  • キックなどの通知を受け取る

World がやること

  • 通知された先へ接続し、入場を確定する
  • マップ移動 — シーン切替の指示と読み込み完了のやり取り
  • 入場時に Attr リストをまとめて送る(パーティ情報も含む)
  • 移動・戦闘・周囲の状態配信などフィールドの処理

パーティとマップ入場の経路

  • パーティ操作は Gateway 側のキャラクター用サービス(Lua)で処理される
  • パーティ状態は CharSerialize の team_info として World から同期される
  • 初回入場 — Gateway が接続先を通知 → World で入場確定
  • フィールド内の移動 — World が NotifySwitchScene でシーン切替を指示
  • ダンジョン入場 — パーティ投票(活動開始・参加返答)のあと World でシーン切替

なぜ分けるか

  • ソーシャル調整とフィールド処理を別サーバーに分けられる
  • World の接続先を変えても、Gateway との関係は保てる
  • フィールド側はゲーム進行に集中できる

02/Client

クライアントの Lua 層

スタレゾのクライアントは Unity(C#)と Lua の二層構成。描画や物理は C#、UI やソーシャル操作の多くは Lua が担当する。

C# と Lua は、クライアント内で役割分担している

Lua が「何をするか」を決め、重い処理やサーバー通信の受け口は C# が担う。UI やソーシャルは差し替えやすく、エンジンは安定したまま更新できる。

Lua

UI・クエスト

パーティ操作

Gateway RPC(Req)

C#(Unity)

描画・物理・入力

World RPC(戦闘・移動)

LuaAsyncBridge

Lua → C# 呼び出し↔状態を Lua に返す

パーティ作成の例

UI(Lua)→ Gateway Char サービス(Lua 受け口)→ サーバー

→ World が team_info を同期 → UI 更新(Lua)+ Attr 更新(C#)

C#(Unity)がやること

  • 描画・物理・入力・エンティティ管理
  • World 向け RPC の受け口(移動・戦闘・Attr 同期)
  • Lua から呼べるエンジン機能(LuaAsyncBridge)

Lua がやること

  • UI フロー — 画面遷移、パーティ画面、ダイアログ
  • クエスト・ストーリー・インタラクションの進行
  • Gateway 向け RPC — パーティ作成・招待・投票など

Lua を使うメリット

  • ホットアップデート — UI やクエストのロジックをアプリ全体の再ビルドなしで差し替えやすい
  • 開発速度 — 画面遷移や条件分岐を C# より素早く書ける。コンテンツ量の多い MMO 向き
  • 役割分担 — C# はエンジン(描画・同期)、Lua はゲーム体験(UI・ソーシャル)に集中できる
  • 変更に強い — パーティやイベントなど頻繁に触る機能をスクリプト側に寄せられる
  • 業界でよくある構成 — 大規模オンラインゲームのクライアントで採用例が多い

RPC の振り分け(ForCs / ForLua)

  • 各 Proxy は method ID ごとに C# か Lua かを分ける
  • 移動・戦闘・シーン切替の多くは C#(WorldProxy)
  • パーティ・ログイン周りは Lua(Gateway の Char サービス)
  • Lua 側の受け口を ZLuaProxy と呼ぶ(調査上の呼び名)

パーティ作成の流れ(Lua 視点)

  • ① プレイヤーがパーティ画面で「作成」を押す(Lua UI)
  • ② Lua が Gateway の Char サービスへ ReqCreateTeam を送る
  • ③ サーバーが CharTeam を生成し、Return で成功/失敗を返す
  • ④ World から CharSerialize(team_info)が同期される
  • ⑤ ContainerDataChanged で Lua UI が更新、AttrTeamId でフィールド表示も変わる

03/What

Attr とは

World 側で扱う、ゲーム内の「属性」。各キャラが自分の Attr リストを持ち、名前・HP・装備などをそこに載せる。

キャラごとに、自分の Attr リストを持つ

リストの形はみんな同じ。中身はキャラごとに別。

自分のキャラ

名前値
HP値
攻撃力値
職業値
装備値

…

Attr リスト

他プレイヤー

名前値
HP値
攻撃力値
職業値
装備値

…

Attr リスト

敵

名前値
HP値
攻撃力値
職業値
装備値

…

Attr リスト

同じ行の並び×別々のリスト

イメージ

  • 自分・他プレイヤー・敵 — それぞれが別々の Attr リストを持つ
  • リストの形(行の種類)は共通。中身の値だけキャラごとに違う
  • 1 行が「何の情報か」と「値」のペアになっている

04/Unified

1 つの仕組みで全部表す

職業やクラスごとに別のデータ構造を用意していない。違いはリストの中身の値だけ。

載っているものの例

  • 職業・レベル・戦闘力
  • HP・攻撃力・防御力などのステータス
  • 装備・スキル・見た目
  • 今どこにいて、何をしているか

うれしいこと

  • 新しいステータスを足すとき、全体の形を変えなくてよい
  • プレイヤーと敵で同期のやり方が同じ
  • 調べるときも「Attr を読む」だけでだいたい追える

05/Stats

ステータスの考え方

攻撃力や HP などの数値は、同じルールで組み立てられている。

1 つのステータスも、リストの中の複数行で表す

例:攻撃力(同じ並びが HP などにも使われる)

もとの値100
足す+20
割合で増やす+10%
最終値132

ざっくり言うと

  • もとになる値(ベース)がある
  • 装備やバフで「足す」「割合で増やす」が別々に記録される
  • それらを合わせた最終値が画面に出る
  • HP も攻撃力も会心も、同じ考え方でそろえてある

06/Sync

サーバーとの同期

World に入ったあと、Attr はまとめて受け取り、以降は変わった分だけ届く。

サーバーは、キャラごとのリストを更新する

入場時はリストまるごと。プレイ中は変わった行だけ。

サーバー

自分

Attr リスト

まとめて → あと差分

他プレイヤー

Attr リスト

見える分だけ差分

敵

Attr リスト

見える分だけ差分

流れ

  • Gateway で接続先を受け取り、World に接続する
  • 入場確定後、Attr リストをまとめて受け取る
  • プレイ中 — 変わった行だけが届く

誰の値が正か

  • HP やステータスは World が送った値が正
  • クライアントはそれで表示を更新する
  • だから「表示」と「本当の値」がずれにくい