ログ解析ロジック アーキテクチャドキュメント
概要
このドキュメントは、ゲームログを解析して試合情報(BAN/PICK、勝敗結果)を抽出する LogParser クラスのアーキテクチャを説明します。
ファイル構成
src/utils/logAnalyzer/ # フロント/バック共通のログ解析ライブラリ
├── LogParser.ts # 一括解析モード(バッチ)
├── CharacterService.ts # キャラクター名・ID変換サービス
├── StatisticsCalculator.ts # 統計計算クラス
├── core/ # 解析エンジン(2026-05 に 3 層分離)
│ ├── LogParserCore.ts # 集約オーケストレータ(薄いラッパ)
│ ├── StreamLogParserV2.ts # ストリーム解析(リアルタイム用、StreamFsm を内蔵)
│ ├── line/
│ │ └── LineParser.ts # 純粋な行パーサ(regex / 抽出関数 / MARKER)
│ ├── fsm/
│ │ └── StreamFsm.ts # phase 状態機械(IDLE→BP→LOADING→INGAME→RESULT)
│ └── aggregator/
│ └── Aggregator.ts # 重複排除 / ソート / Normal 戦キャラ抽出
├── types.ts # 型定義
└── index.ts # エントリーポイント
scripts/analyze-log/ # CLIログ解析スクリプト
├── parsers/
│ └── LogParser.ts # スクリプト用LogParser実装
├── services/
│ └── CharacterService.ts # キャラクター変換サービス
├── statistics/
│ └── StatisticsCalculator.ts # 統計計算
├── reports/
│ └── ReportGenerator.ts # レポート生成
└── index.ts # エントリーポイント3 層分離の役割
| Layer | ファイル | 責務 | テスト |
|---|---|---|---|
| Line | core/line/LineParser.ts | 1 行を受け取り構造化データを返す純粋関数(I/O・時間・Electron 依存なし) | LineParser.test.ts table-driven |
| FSM | core/fsm/StreamFsm.ts | phase の状態保持・遷移・onChange リスナー | StreamFsm.test.ts 全遷移 1 ケース以上 |
| Aggregator | core/aggregator/Aggregator.ts | 解析結果の重複排除・ソート・Normal 戦キャラ抽出 | Aggregator.test.ts fixture ベース |
LogParserCore.ts (114 行) は LineParser の関数を re-export し、Aggregator のメソッドを delegate するだけの薄いラッパ。互換のため既存 API シグネチャを維持する。
ログの構造
ゲームログには以下の重要なマーカーが含まれます:
1. BPフェーズ(BAN/PICK)関連
| マーカー | 説明 | Rank/Normal |
|---|---|---|
BP数据日志 | BAN/PICKの詳細情報(プレイヤー名、キャラID等) | Rankのみ |
匹配成功开始加载战斗 | マッチング成功・バトルロード開始(BPフェーズ終了) | 両方 |
PageBattleBanPick2V2.prefab | BP画面のUI表示ログ | Rankのみ |
2. 試合進行関連
| マーカー | 説明 |
|---|---|
ON GAME START | ゲーム開始 |
ON BATTLE END PUSH | バトル終了 |
upload sdk battle player | 試合結果(プレイヤー名、勝敗) |
3. マッチタイプ関連
| マーカー | 説明 |
|---|---|
TYPE:Rank_2v2 | ランクマッチ2v2 |
TYPE:Rank_1v1 | ランクマッチ1v1 |
TYPE:Normal_2v2 | ノーマル2v2 |
TYPE:Normal_1v1 | ノーマル1v1 |
TYPE:Custom | カスタムマッチ |
解析フロー
1. scanLogForMarkers()
└── ログ全体をスキャンして重要な行番号を収集
├── bpEndLines[] - BPフェーズ終了行
├── bpDataLines[] - BP数据日志の行(Rank判定用)
├── gameStartLines[] - ゲーム開始行
├── gameEndLines[] - ゲーム終了行
└── battleResultLines[] - 試合結果行
2. parseAllMatches()
└── 試合ごとに解析
├── groupBattleResults() - 連続した結果行をグループ化
├── findBpEndBeforeResult() - 対応するBPフェーズ終了を探す
├── findMatchTypeBeforeResult() - TYPE:ログを探す
├── hasBpDataBeforeResult() - BP数据日志の有無でRank判定
├── parseMatchBP() - BAN/PICK情報を解析
└── parseMatchResultDynamic() - 勝敗結果を解析Rank判定ロジック(2025-12-06修正済み)
マッチタイプ判定の優先順位
LogParserは以下の3段階でマッチタイプを判定します:
1. TYPE:ログによる明示的判定(最優先)
試合結果の前500行以内でTYPE:マーカーを検索:
typescript
const typeMatch = this.lines[i].match(/TYPE:(Rank_2v2|Rank_1v1|Normal_2v2|Normal_1v1|Custom|[\w_]+)/);2. BP数据日志によるRank判定(フォールバック)
TYPE:が見つからない場合、BP数据日志の有無でRank判定:
typescript
if (!matchType && this.hasBpDataBeforeResult(resultStartLine, bpEndLine)) {
matchType = playerCount === 2 ? 'Rank_1v1' : 'Rank_2v2';
}BP数据日志の特性:
- ランクマッチでのみ出力される
- BAN/PICK情報(プレイヤー名、キャラID、チーム)を含む
- ログ例:
[Info]:00:00:30:547 BP数据日志---玩家:もーり(1046101022) P1 Team:TeamA TeamSort:0
3. プレイヤー数による推定(最終手段)
上記2つで判定できない場合、プレイヤー数から推定:
typescript
const is1v1 = matchType?.includes('1v1') || playerCount === 2;hasBpDataBeforeResult()の実装
typescript
private hasBpDataBeforeResult(resultLine: number, bpEndLine: number | null): boolean {
if (bpEndLine === null) return false;
// 前のBPフェーズ終了行を探す(この試合のBPフェーズ開始点として使う)
const prevBpEndIdx = this.bpEndLines.indexOf(bpEndLine) - 1;
const bpStartLine = prevBpEndIdx >= 0 ? this.bpEndLines[prevBpEndIdx] + 1 : 0;
// bpStartLine から resultLine の間に BP数据日志 があるか確認
for (const bpDataLine of this.bpDataLines) {
if (bpDataLine >= bpStartLine && bpDataLine < resultLine) {
return true;
}
}
return false;
}ログの行番号関係(試合1の例)
行134〜 : BP数据日志(BAN/PICK情報)
行749 : 匹配成功开始加载战斗(BPフェーズ終了)
行953〜956: upload sdk battle player(試合結果)この例では:
- bpStartLine = 0(最初の試合)
- bpEndLine = 749
- resultLine = 953
- bpDataLines内に134が含まれる
- 134 >= 0 && 134 < 953 → true → Rank判定成功
テスト用コマンド
bash
# ログ解析実行
cd c:/Users/mouri/Documents/devkit/broadcast-Overlay
npx tsx scripts/analyze-log/index.ts "scripts/testData/mouri/Log_2025_12_06.txt"
# BP数据日志の存在確認
grep -n "BP数据日志" scripts/testData/mouri/Log_2025_12_06.txt | head -10
# TYPE:ログの確認
grep -n "TYPE:" scripts/testData/mouri/Log_2025_12_06.txt | head -30関連ファイル
ログ解析コア
- src/utils/logAnalyzer/LogParser.ts - フロント/バック共通のログ解析クラス
- src/utils/logAnalyzer/CharacterService.ts - キャラクター変換サービス
- src/utils/logAnalyzer/StatisticsCalculator.ts - 統計計算クラス
- src/utils/logAnalyzer/types.ts - 型定義
CLIスクリプト
- scripts/analyze-log/parsers/LogParser.ts - スクリプト用LogParser実装
- scripts/analyze-log/index.ts - CLIエントリーポイント
- scripts/analyze-log/reports/ReportGenerator.ts - レポート生成
テストデータ
- scripts/testData/mouri/Log_2025_12_04.txt - 36試合(Rank: 24, Normal: 12)
- scripts/testData/mouri/Log_2025_12_05.txt - 29試合(Rank: 28)
- scripts/testData/mouri/Log_2025_12_06.txt - 39試合(Rank: 39)
解析結果の出力内容
LogParserは以下の情報を抽出します:
1. 試合基本情報
- 試合番号
- タイムスタンプ
- マッチタイプ(Rank_2v2, Normal_2v2, etc.)
- ゲーム開始・終了時刻
- 試合時間
2. プレイヤー情報
- プレイヤー名
- プレイヤーID(UID)
- 勝敗結果
- チーム(TeamA/TeamB)
3. BAN/PICK情報(ランクマッチのみ)
- BANされたキャラクター
- BANしたプレイヤー
- ピックされたキャラクター
- ピックしたプレイヤー
4. 統計情報
- プレイヤー別勝敗数・勝率
- キャラクター別BAN回数
- キャラクター別ピック回数
- 総試合数・ランクマッチ数