final fantasy record keeperのマスターデータを支える技術
TRANSCRIPT
Copyright (C) DeNA Co.,Ltd. All Rights Reserved.
第 6 回 DeNA ゲーム開発勉強会
DeNA 史上最大級!FINAL FANTASY Record Keeper の
マスターデータを支える技術
2015/08/24GDI 渋川よしき
Copyright (C) DeNA Co.,Ltd. All Rights Reserved.
お前だれよ? 前職
⁃ 自動車会社の社内 SE 現職
⁃ 社内ゲームエンジン用のフレームワーク( クライアント用もサーバ用も ) 作ったり、開発支援ツール作ったりいわゆる社内 SE
⁃ たまにゲーム開発を手伝ったりもします。
渋川 よしき
プログラミング C++ とか Python とか Golang とか JavaScript とか
本 つまみぐい勉強法、アート・オブ・コミュニティ ( 翻訳 ) 、
Mobage を支える技術、オブジェクト指向 JavaScript( 翻訳 ) 、ポモドーロ・テクニック入門 ( 翻訳 ) 、 etc
Copyright (C) DeNA Co.,Ltd. All Rights Reserved.
新書出ました!
JavaScript の、最速クライアント用 MVC フレームワークの本です!⁃ 速いのが好きな人や、変化が多いブラウザ周辺技術に疲れた人に
オススメ 電子書籍のみです 表紙は黒ムツの仲間
⁃ 南オセアニアの深海魚⁃ 最大 75cm⁃ 確認された最高齢は
100 歳を超えるとか
Copyright (C) DeNA Co.,Ltd. All Rights Reserved.
マスタデータとは?
ゲームを支える要素⁃ プログラム⁃ アセット• 画像とか 2D アニメーションとか 3D モデルとか音楽とか
⁃ マスタデータ• プログラム・アセット以外
• シナリオ、テキスト、敵の強さなどのパラメータ
• レベルデザイン (3D アクションのマップ ) 的なものはあまりマスターデータとは言わないかも・・・
Copyright (C) DeNA Co.,Ltd. All Rights Reserved.
マスタデータとは?
ゲームを支える要素⁃ プログラム →プログラマ⁃ アセット →アーティスト• 画像とか 2D アニメーションとか 3D モデルとか音楽とか
⁃ マスタデータ→ゲームデザイナ• プログラム・アセット以外
• シナリオ、テキスト、敵の強さなどのパラメータ
• レベルデザイン (3D アクションのマップ ) 的なものはあまりマスターデータとは言わないかも・・・
Copyright (C) DeNA Co.,Ltd. All Rights Reserved.
マスターデータの役割
ユーザのプレイサイクルをデザインする⁃ ユーザ体験のうち、 UI とか画像とか音楽のような目や耳で感じる
以外のところ全般• ステージクリアや、レベルアップのテンポだったり
• アイテムや必殺技、魔法などの種類とか性能だったり
• 敵の強さの調整だったり
• 会話やチュートリアルなどの説明だったり
モバイルのオンラインゲームでは特に大事⁃ 新しいイベントやステージを ( アプリ本体の更新なしに ) 追加し
たり⁃ ユーザが挫折しやすいポイントがあれば、それを修正したり
Copyright (C) DeNA Co.,Ltd. All Rights Reserved.
マスターデータの役割
ユーザのプレイサイクルをデザインする⁃ ユーザ体験のうち、 UI とか画像とか音楽のような目や耳で感じる
以外のところ全般• ステージクリアや、レベルアップのテンポだったり
• アイテムや必殺技、魔法などの種類とか性能だったり
• 敵の強さの調整だったり
• 会話やチュートリアルなどの説明だったり
モバイルのオンラインゲームでは特に大事⁃ 新しいイベントやステージを ( アプリ本体の更新なしに ) 追加し
たり⁃ ユーザが挫折しやすいポイントがあれば、それを修正したり
今日は、比較的スポットのあたりにくいマスターデータの運用改善の紹介をします
Copyright (C) DeNA Co.,Ltd. All Rights Reserved.
Final Fantasy Record Keeper
DeNA 社内でもっとも複雑※なマスターデータを持つゲーム⁃ すでに確立された世界観を持つ• 炎耐性とか、弱点属性とか、前後列、カウンター専用技、ボスの状態の変
化など、かなり複雑な要素が満載だが、ユーザはすでに FF の世界を熟知しているので、ほぼフルスペックの FF のメカニズムが実装されている
⁃ しかも、各シリーズの最小公倍数
• 元ネタがあるので、コンテンツ追加の速度は速い!
• スクウェアエニックス社様の大事な IP であるため、文言やアニメーションの監修もきちんと行う体制になっている
⁃ 開発が並列• イベントが常に数本走っている
• イベントの開発も常に数本並行で走っている
• 機能追加も並列で!
※ 何人かのチームメンバーにインタビューした結果
Copyright (C) DeNA Co.,Ltd. All Rights Reserved.
マスターデータ運用で悲鳴があがり始める前 (2014/11ごろ )
Google Spreadsheet を使っている⁃ 外部キー・主キーのような仕組みを Google Apps Script で実現⁃ 社内でも実績のある仕組み• かつては Excel をリポジトリに入れてたりもしてたが、共同編集のしやす
さから、今は Google Spreadsheet が主流
Jenkins を使った運用の仕組みは整備されていた⁃ マスタデータの csv を所定の場所に置いてスクリプトを起動する
と、整合性チェックを行ってテストサーバに投入したり、問題なさそうなら github:e にプルリクエストを送ったりできた
⁃ 将来必要だけど今はいらないデータを行ごとにフィルタする機能
Copyright (C) DeNA Co.,Ltd. All Rights Reserved.
外部キー・主キーのような仕組みの例
※ なお、このシートはツールのテスト用に大分昔にコピーしたものなので実際のゲーム内のデータとは異なります
わかりやすい名前で入力して、 CSV生成時に主キーに置き換える仕組み
Copyright (C) DeNA Co.,Ltd. All Rights Reserved.
実際のマスターデータ
※ シート間の関係を分析してみた結果⁃ ゲームプレイに関わる部分のみ⁃ 関連を複雑にする要素は一部抜いてます 10
Copyright (C) DeNA Co.,Ltd. All Rights Reserved.
FINAL FANTASY Record Keeper の開発の複雑さ
そもそもデータが複雑で量が多い⁃ データだけで多くの調整ができるようになっている• 味方や敵の強さの調整
• 演出の調整
• イベントの追加
• ダンジョンに出現する敵のセットの定義とか配置とか
同時にたくさんのチームが走る⁃ 開発チームごとにスキーマを変更して追加のデータを増やした
い!ということがよくおきる
Copyright (C) DeNA Co.,Ltd. All Rights Reserved.
少しずつ複雑化・・・
クエスト機能 (選択式チュートリアル ) 入れるよね レベルキャップ (50 まで ) を外す限界突破機能を入れよう
⁃ 限界突破したらレコードマテリアが使えるようにしよう⁃ レコードマテリア装備したらいろいろな効果が
必殺技付き武器を提供しよう⁃ 熟練度を上げると、必殺技をマスターするよ⁃ 超必殺技つけたらステータスアップあるよ⁃ ☆5 装備の鍛錬あるよ!☆ 5武器合成で武器のステータス上がる
よ 敵に HP ゲージ付けよう BRABRA コラボイベントで音楽室を追加しよう ブレイク技が強いからボスに耐性つけよう
Copyright (C) DeNA Co.,Ltd. All Rights Reserved.
さまざまな問題が発生・・・
GoogleSpreadsheet
GoogleSpreadsheet
GoogleSpreadsheet
GoogleApps Script
Jenkinsnormalize& check
デプロイスクリプトCSV 1
/db/data/src
開発用MySQL
CSV 2/db/data/master
github:eCSV 3 (dump)
/db/data/dump
本番MySQL
ひとつのマスターデータを各開発ブランチで利用している● 他のチームの変更 ( 不具合 ) の影響で作業が止まる● 気軽に変更できない
ここに来ないと分からないエラーも多い
•必要なスプレッドシートを手でひとつずつ出力
•CSV の依存関係を手で解決
•時間がかかる (1時間程度 )
•タイムアウトで仕事ができない ( とくに夕方 )
コンフリクト発生時に修正が難しい
Copyright (C) DeNA Co.,Ltd. All Rights Reserved.
発生した課題
複数人でもスプレッドシートのファイルは 1 つ⁃ 変なデータを入れてしまうとデータ不整合のエラーで、
全チームの作業が止まってしまう エクスポートに時間がかかった
⁃ まっさらな状態からやろうとすると 1時間近くかかる⁃ 変更中に誰かが作業すると結果が変わってしまう⁃ 調整が大変なので、シート構造変更をやろうとするとエンジニア
の MP がゼロになる カラム数が極端に多いシートも出てきた
⁃ 行数が 5桁のシートを開くとブラウザが重い・落ちる Google Apps Script がタイムアウト
⁃ データ数が多くなってきたら、すねて処理してくれない• 夕方の成功率が 50% を切る (巨大なシートだと 80% 以上失敗 )
⁃ Google Apps Script は自力でマルチスレッド化できないので遅い
Copyright (C) DeNA Co.,Ltd. All Rights Reserved.
マスターデータが問題を起こすと・・・
データのエクスポートができない⁃ データチェックは厳格に行われているがエラーがわかりにくかっ
た⁃ ログが大量に出力されていて、何が問題かを探すのも大変だった
⁃ 結果として、データ構造に詳しいエンジニアへの問い合わせが増えて、昼ごはんをお昼に食べれないほど忙しい日々が・・・たすけて
たすけて ひー
Copyright (C) DeNA Co.,Ltd. All Rights Reserved.
マスターデータが問題を起こすと・・・
データのエクスポートができない⁃ データチェックは厳格に行われているがエラーがわかりにくかっ
た⁃ ログが大量に出力されていて、何が問題かを探すのも大変だった
⁃ 結果として、データ構造に詳しいエンジニアへの問い合わせが増えて、昼ごはんをお昼に食べれないほど忙しい日々が・・・たすけて
たすけて ひー
「高橋慧さんがお昼を昼に食べれる」というのを目標に設定
20
Copyright (C) DeNA Co.,Ltd. All Rights Reserved.
開発規模に見合うスケール可能にする仕組みの導入を検討
1. 縦に長いシートをイベントや定常などのリリース時期ごとに分割
2. スプレッドシートのファイル群をグループ ( フォルダ ) に分ける
3. エクスポートするときにどのグループを出すか、ゲームデザイナーが選択できるようにする
4. 扱うファイル数が増えるので、一括出力の仕組みが必要そう
Copyright (C) DeNA Co.,Ltd. All Rights Reserved.
改良 1: バッチコマンドラインツール化
ファイル一覧のシート取得
ファイル一覧で指定された名前のファイ
ルのキーのリストを作
成
フォルダの全子要素のキーと名前を取得
ファイルをダウンロード
ファイルをロードし、JSONSheet /
JSONFormat を分析
•RefListTemplate を元に値の置き換え•CSV 出力
入力ファイルは変更なし
⁃ 運用しながらランニングチェンジ
Golang を使いスレッドプールでとことん並列化した
⁃ コマンド一発で最新データを一括取得
⁃ 処理自体もずいぶん早い
⁃ ついでに、バイナリなのでアクセストークンとか秘匿できて良い
Copyright (C) DeNA Co.,Ltd. All Rights Reserved.
バッチコマンドラインツール化の結果
読み込むシート一覧のシートを作成⁃ 誰がやっても (企画でもエンジニアでも ) 、ほぼ同じ結果が即座
に得られるようになった• 問題の追跡が楽になった
• 「データを通すため」の作業が減り、「良いゲームを作るため」の時間が増えた。
• Jenkins から呼んだり、コマンドラインから使ったり
⁃ テストサーバに投入するまでの時間が 100 倍ぐらい早くなった エラーメッセージや警告を日本語で出せるだけ出すようにした
⁃ 問題追跡をゲームデザイナーだけでできるように⁃ 初めて実行した時は警告が 4000件ぐらい出た
Copyright (C) DeNA Co.,Ltd. All Rights Reserved.
改良 2: 並行開発のサポート
ダンジョン名 リリース
カオス神殿 定常
西の城 定常
[初級 ] ナルシェ エドガー・マッシュ
[初級 ]西の炭鉱 エドガー・マッシュ
[初級 ] マルディアス エンサガ
[中級 ] マルディアス エンサガ
同名シートでもリリース時期によってファイルを分割できるようにした
⁃ 「このイベントではどのファイルを組み合わせるか?」というのは柔軟に設定できるようになった
⁃ 開発始まったばかりの不安定なシートの参照がスキップされるので、他の人の影響で仕事が止まることが減った
⁃ ブラウザの負担も減った ダンジョン名 リリース
カオス神殿 定常
西の城 定常ダンジョン名 リリース
[初級 ] マルディアス エンサガ
[中級 ] マルディアス エンサガダンジョン名 リリース
[初級 ] ナルシェ エドガー・マッシュ
[初級 ]西の炭鉱 エドガー・マッシュ
Copyright (C) DeNA Co.,Ltd. All Rights Reserved.
並行開発のサポートの実装 (1)
ファイル一覧のシート取得
ファイル一覧で指定された名前のファイ
ルのキーのリストを作
成
フォルダの全子要素のキーと名前を取得
ファイルをダウンロード
ファイルをロードし、JSONSheet /
JSONFormat を分析
•RefListTemplate を元に値の置き換え•CSV 出力
バッチ化で土台ができていたので、少し改造して「シートを後からマージ」できるようにした
⁃ 全イベント・定常が単一ファイルで管理していたときと、まったく同じ CSVを出せるようにしたので、後工程はそのまま変更なし
⁃ 2月末リリースのライトニングイベントから順次シート切り分け
⁃ ついでに ID が同じなら同名シート内で新しい情報で上書きできるように
同名のシートでグループ化
Copyright (C) DeNA Co.,Ltd. All Rights Reserved.
並行開発のサポートの実装 (2): Rel 更新プログラムの改善
今までは Google Apps Script で、
スプレッドシートの「データの検証」機能を設定していた
⁃ 並列処理できないので遅い
⁃ よくタイムアウトで止まる
⁃ 1 ファイルずつやらないといけない
データの検証更新プログラム
Copyright (C) DeNA Co.,Ltd. All Rights Reserved.
ここもバッチプログラムを作った
⁃ シートに設定するところは GAS の方がやりやすかったので最終段はほぼそのまま
⁃ 情報取得してプルダウンメニューの項目リスト作成する部分はバッチ化と同じライブラリを使って並列ダウンロード
⁃ GAS は自前でスレッドは起こせないが、ウェブサービス化して並列してリクエストを投げれば並列処理できる (x10 まで )
並行開発のサポートの実装 (2): Rel 更新プログラムの改善
データの検証更新プログラム
30
Copyright (C) DeNA Co.,Ltd. All Rights Reserved.
並行開発のサポートの結果
新しいカラムの追加などは、イベントごとに行えるようにした⁃ グループには親子関係があり、親の機能追加は子にも反映
イベントリリースにあわせて途中からパラメータの変更をできるように⁃ 例 ) イベントのキャラ配布にあわせて装備できる武器の
種類を増やしたい⁃ → リリースタイミングで設定を上書きできるようにした。
リリース後は?⁃ カラム追加や上書きは大本のシートに移動する運用ルール⁃ リリースされている現在の状態は大本のマスターにある、という
のが事故を防ぐのに大事
Copyright (C) DeNA Co.,Ltd. All Rights Reserved.
結果
リリースしてから 1ヶ月で 1000 回以上実行された⁃ 900時間以上節約⁃ といってもチームの人数が減ったわけではなく、負担が減ってそ
の分多くの調整が回せるようになった
Copyright (C) DeNA Co.,Ltd. All Rights Reserved.
目標も達成!
Copyright (C) DeNA Co.,Ltd. All Rights Reserved.
補助機能 (1): ブラウザでプレビュー機能
問題の追跡に使う⁃ どのシートから出力されたか?ソースはどこファイルのどの行?⁃ Rel で設定した日本語の名前は何?⁃ 出力設定はどのファイルから来たの?
Copyright (C) DeNA Co.,Ltd. All Rights Reserved.
補助機能 (2): セル・文字単位の diff 表示機能
カラム数が多いシートもあるし、カラム追加などでは全行差分になってしまうので、プルリクエストのページだと差分を確認しにくい
色は github に合わせた
Copyright (C) DeNA Co.,Ltd. All Rights Reserved.
補助機能 (3): Google Spreadsheet 用の blame コマンド
シートの行ごとに、最終編集者と変更日時を表示
Copyright (C) DeNA Co.,Ltd. All Rights Reserved.
さらなる機能追加とか高速化とか
リリース時期のフィルタ機能を内部に取り込んだ⁃ それまでは Perl スクリプトでエクスポート後にフィルタしていた⁃ ツール内部にこの仕組みを取り込むことで、有効なデータかどう
かを判断して、より厳しいチェックが可能になった• 警告・エラーと二種類メッセージを用意していたが、最終的に「別シート
で同一 ID のものを上書きした」以外はすべてエラーになった
• エラーは日本語で出すようにしています
Golang の xlsx パースは遅いしメモリ食う⁃ zlib+XML のパースで、ファイル変更がなくても 40秒近くかか
る• Jenkins サーバ上で、たまに OOM キラーに・・・
⁃ JSON+LZ4( 高速な圧縮アルゴリズム ) でキャッシュして 15秒に⁃ MessagePack+LZ4 でキャッシュすると 6秒ぐらいに
Copyright (C) DeNA Co.,Ltd. All Rights Reserved.
ぶっちゃけ Golang どうよ?
スクリプト言語並に書きやすい C/C++⁃ 速度は十分 (xml, json のパース以外は ) だし並列化しやすい• 同じことを C/C++ でやろうとすると結構ツライ
• 「 C++ と違ってその日のやる気が生産性に影響しない良い言語」 (同僚談 )⁃ IntelliJ IDEA + golang プラグインで開発はしやすかった⁃ ライブラリも多い⁃ クロスコンパイルがしやすいのが良い• Jenkins 用 (Linux) やデザイナー用 (Windows) 、エンジニア用 (Mac) を
簡単に作ってリリース
⁃ コンパイル時チェックが厳密なのでいじりやすい• ロジック以外のテストはそんなに書かなくても困らない
• 社内ツールは要望や報告が来て 1ヶ月ぶりにコード触るとかが多いので楽
とはいえ、 Jenkins 上や開発環境上のツールとしてしか運用していないので、サービス運用のノウハウはまだなし⁃ DeNA で「バリバリ使ってます」とはまだ言えない・・・⁃ US は使ってます
Copyright (C) DeNA Co.,Ltd. All Rights Reserved.
まとめ
チーム規模に負けない仕組みを整備した⁃ 運用を止めずに大幅なワークフローの変更を行った⁃ 開発期間におけるデータ入力の手間を大分減らすことができた• きちんとお昼にお昼ごはんを食べられるようになった
⁃ 効率アップは 10% じゃなくて 10 〜 100 倍だと仕事の流れが変わる
運用しつづけていくタイトルにおいて、企画とシステム開発は両輪⁃ プログラマの人は、エディタとかの話好きだよね?⁃ 企画側も仕組みをがっつり整備していくことで運用がしやすくな
る 他の運用中・新規タイトルにも絶賛水平展開中
40