rabukasim / docs /plans /metadata_bytecode_analysis.md
trioskosmos's picture
chore: remove large files for HF Space
9bd4ce5
# metadata.json とバイトコード生成の分析レポート
## 概要
このレポートでは、`data/metadata.json` がバイトコード生成にどのように影響するか、またパーサーとビットマスク処理が過度に複雑かどうかを分析します。
---
## 1. metadata.json の構造
### 1.1 セクション一覧
| セクション | 用途 | エントリ数 |
|-----------|------|-----------|
| `triggers` | 能力の発動タイミング | 11 |
| `targets` | 効果の対象 | 14 |
| `opcodes` | バイトコード命令 | 67 |
| `action_bases` | アクションIDのベース値 | 13 |
| `phases` | ゲームフェーズ | 15 |
| `conditions` | 条件チェック命令 | 54 |
| `costs` | コスト種別 | 95 |
| `extra_constants` | ビットマスク定数 | 26 |
| `unused` | 未使用マーク | 0 (空) |
### 1.2 同期フロー
```mermaid
flowchart TD
A[data/metadata.json] --> B[tools/sync_metadata.py]
B --> C[engine_rust_src/src/core/generated_constants.rs]
B --> D[engine_rust_src/src/core/enums.rs]
B --> E[frontend/web_ui/js/generated_constants.js]
B --> F[engine/models/generated_metadata.py]
B --> G[engine_rust_src/src/core/shader_constants.wgsl]
```
---
## 2. 問題点: 二重定義と不整合
### 2.1 Python側の二重定義問題
**重大な問題**: [`engine/models/ability.py`](engine/models/ability.py) には `metadata.json` とは**独立した** enum定義が存在します。
```python
# ability.py (行10-22) - metadata.json と独立
class TriggerType(IntEnum):
NONE = 0
ON_PLAY = 1
ON_LIVE_START = 2
# ...
```
これは [`engine/models/generated_metadata.py`](engine/models/generated_metadata.py) と**重複**しており、同期されていません。
### 2.2 具体的な不整合例
| 項目 | metadata.json | ability.py | 状態 |
|-----|---------------|------------|------|
| `SEARCH_DECK` | 22 | 22 | ✅ 一致 |
| `FORMATION_CHANGE` | 26 | 26 | ✅ 一致 |
| `SWAP_ZONE` | 38 | 38 | ✅ 一致 |
| `PREVENT_SET_TO_SUCCESS_PILE` | 80 | 80 | ✅ 一致 |
| `SET_HEART_COST` | 83 | 83 | ✅ 一致 |
**現在は値が一致していますが**`ability.py`のenumは手動管理であり、将来的な不整合のリスクがあります。
### 2.3 AbilityCostType の爆発的増加
[`ability.py`](engine/models/ability.py:303-500) の `AbilityCostType`**200以上のエントリ** を持ち、その多くが自動生成された「プレースホルダ」です:
```python
# 行410-500: 自動生成されたエントリの例
PLACE_ENERGY_FROM_DECK_TO_DISCARD = 110
PLACE_ENERGY_FROM_DECK_TO_HAND = 111
# ... 90行以上の自動生成エントリ
```
これらは `metadata.json``costs` セクション (95エントリ) と比較して**2倍以上の規模**です。
---
## 3. ビットマスク処理の複雑さ分析
### 3.1 _pack_filter_attr のビットレイアウト
[`ability.py`](engine/models/ability.py:1388-1595) の `_pack_filter_attr` メソッドは、64ビット整数に複数のフィルタ条件をパックします:
```
ビットレイアウト (64ビット):
┌─────────────────────────────────────────────────────────────────┐
│ Bits 2-3 : Type (0=Any, 1=Member, 2=Live) │
│ Bit 4 : Group Filter Enable │
│ Bits 5-11 : Group ID (7 bits) │
│ Bit 12 : Tapped Filter │
│ Bit 13 : Has Blade Heart │
│ Bit 14 : Not Has Blade Heart │
│ Bit 15 : Unique Names │
│ Bit 16 : Unit Filter Enable │
│ Bits 17-23 : Unit ID (7 bits) │
│ Bit 24 : Cost Filter Enable ←┐ │
│ Bits 25-29 : Cost Threshold (5b) │ 競合! │
│ Bit 30 : Cost Mode │ │
│ Bit 31 : Color Filter Enable ←┘ │
│ Bits 32-38 : Character ID 1 │
│ Bit 42 : Character Filter Enable │
│ Bits 43-49 : Character ID 2 │
│ Bits 50-56 : Character ID 3 │
│ Bits 57-59 : Special Filter ID │
└─────────────────────────────────────────────────────────────────┘
```
### 3.2 ビット競合の問題
**重大な設計欠陥**: Bits 24-30 が **Cost Filter****Color Filter** で競合しています:
```python
# Cost Filter (行1517-1536)
if c_min is not None:
attr |= 1 << 24 # Cost Enable
attr |= (val & 0x1F) << 25 # Cost Value
# Color Filter (行1538-1555) - 同じビット領域を使用!
if color_mask > 0:
attr |= (color_mask & 0x7F) << 24 # ← Cost と重複!
attr |= 1 << 31
```
これにより、Cost Filter と Color Filter は**同時に使用できません**
### 3.3 Rust側の実装との整合性
[`engine_rust_src/src/core/logic/filter.rs`](engine_rust_src/src/core/logic/filter.rs:20-33) では、同じビットレイアウトを使用:
```rust
/// Bit layout (see generated_constants.rs):
/// - Bits 2-3: Card type (Member=1, Live=2)
/// - Bit 4: Group filter enable
/// - Bits 5-11: Group ID
/// - Bit 16: Unit filter enable
/// - Bits 17-23: Unit ID
/// - Bits 32-38: Color mask ← 異なる! Pythonは24-30
/// - Bit 42: Character filter enable
```
**Rust側は Bits 32-38 を Color に使用**していますが、Python側は Bits 24-30 を使用しており、**不整合**があります。
---
## 4. バイトコードコンパイルの複雑さ
### 4.1 コンパイルフロー
```mermaid
flowchart TD
A[Ability.instructions] --> B{Instruction Type?}
B -->|Condition| C[_compile_single_condition]
B -->|Effect| D[_compile_effect_wrapper]
B -->|Cost| E[_compile_single_cost]
C --> F[Opcode + Value + Attr + Slot]
D --> G{Effect Type?}
G -->|ORDER_DECK| H[LOOK_DECK + ORDER_DECK]
G -->|SELECT_MODE| I[Jump Table生成]
G -->|Other| J[_compile_single_effect]
J --> K[特殊処理]
K --> L[_pack_filter_attr呼び出し]
L --> F
```
### 4.2 特殊処理の分岐数
[`_compile_single_effect`](engine/models/ability.py:949-1386) メソッドには**15以上の特殊ケース分岐**があります:
| Effect Type | 特殊処理内容 | 行番号 |
|-------------|-------------|-------|
| `ORDER_DECK` | LOOK_DECK命令を先行 emit | 859-872 |
| `SELECT_MODE` | ジャンプテーブル生成 | 877-925 |
| `RECOVER_MEMBER/LIVE` | ゾーン再配置ビット処理 | 965-977 |
| `TAP_OPPONENT/TAP_MEMBER` | フィルタ属性パック | 981-986 |
| `PLACE_UNDER` | ソース属性設定 | 989-993 |
| `ENERGY_CHARGE` | ウェイト状態フラグ | 996-998 |
| `SELECT_MEMBER` | フィルタ属性パック | 1001-1002 |
| `PLAY_MEMBER_*` | フィルタ属性パック | 1005-1010 |
| `LOOK_AND_CHOOSE` | キャラクターID + ゾーン処理 | 1013-1099 |
| `SELECT_CARDS/MEMBER/LIVE` | 複雑なビットパッキング | 1102-1130 |
| `SET_HEART_COST` | 6色コスト + ユニットフィルタ | 1133-1194 |
| `META_RULE` | 13種類のルールタイプ | 1275-1302 |
| `REVEAL_UNTIL` | 条件タイプ別エンコード | 1305-1345 |
### 4.3 コードの複雑さ指標
| 指標 | 値 | 評価 |
|-----|-----|------|
| `_compile_single_effect` の行数 | 437行 | 🔴 過大 |
| `_pack_filter_attr` の行数 | 208行 | 🟡 中程度 |
| 特殊処理分岐数 | 15+ | 🔴 過多 |
| ビットシフト演算数 | 50+ | 🔴 過多 |
| ネスト深度 | 最大5レベル | 🟡 中程度 |
---
## 5. 推奨される改善策
### 5.1 短期的改善 (優先度: 高)
1. **二重定義の排除**
- `ability.py` の enum を `generated_metadata.py` から import するよう変更
- または、`sync_metadata.py``ability.py` も生成するよう拡張
2. **ビット競合の解消**
- Color Filter を Bits 32-38 に移動 (Rust側に合わせる)
- または、Cost Filter を Bits 8-14 に移動
### 5.2 中期的改善 (優先度: 中)
3. **フィルタ構造体の導入**
```python
@dataclass
class CardFilter:
card_type: Optional[CardType]
group_id: Optional[int]
unit_id: Optional[int]
cost_filter: Optional[tuple[int, bool]] # (threshold, is_le)
color_mask: int
# ...
def pack(self) -> int:
"""構造化されたフィルタをビット列に変換"""
```
4. **エフェクトコンパイラの分割**
- `_compile_single_effect` を各エフェクトタイプ別のハンドラに分割
- Visitor パターンまたは Strategy パターンの採用
### 5.3 長期的改善 (優先度: 低)
5. **バイトコード設計の再検討**
- 現在: 4-int固定長 `[op, v, a, s]`
- 提案: 可変長またはTLV (Type-Length-Value) 形式
6. **宣言的エフェクト定義**
- YAML/JSON でエフェクトを定義し、コード生成
---
## 6. 結論
### 6.1 metadata.json のバイトコードへの影響
| 側面 | 評価 | 説明 |
|-----|------|------|
| Opcode値の定義 | ✅ 良好 | 自動同期されている |
| 条件/コスト値 | ✅ 良好 | 自動同期されている |
| Python enumとの整合性 | 🟡 リスクあり | 手動管理のため将来的に不整合の可能性 |
| ビットマスク定数 | 🔴 不整合あり | Python/Rustでビット位置が異なる |
### 6.2 複雑さの評価
| 側面 | 評価 | 理由 |
|-----|------|------|
| パーサー | 🟡 中程度 | 分岐は多いが構造は理解可能 |
| ビットマスク | 🔴 過度に複雑 | 競合あり、文書化不十分 |
| コンパイラ | 🔴 過度に複雑 | 400行の単一メソッド、15+分岐 |
| 保守性 | 🔴 低い | 二重定義、暗黙のビット操作 |
### 6.3 最優先すべき課題
1. **Color Filter のビット位置修正** (Rust側に合わせる)
2. **ability.py の enum を自動生成に切り替え**
3. **_compile_single_effect の分割リファクタリング**
---
## 付録: 関連ファイル一覧
| ファイル | 行数 | 役割 |
|---------|------|------|
| [`data/metadata.json`](data/metadata.json) | 323 | 定数定義のマスター |
| [`engine/models/ability.py`](engine/models/ability.py) | 1852 | 能力定義・コンパイル |
| [`tools/sync_metadata.py`](tools/sync_metadata.py) | 349 | 定数同期スクリプト |
| [`engine_rust_src/src/core/generated_constants.rs`](engine_rust_src/src/core/generated_constants.rs) | 275 | Rust定数 (自動生成) |
| [`engine_rust_src/src/core/logic/filter.rs`](engine_rust_src/src/core/logic/filter.rs) | 150+ | Rustフィルタロジック |
| [`tools/verify/bytecode_decoder.py`](tools/verify/bytecode_decoder.py) | 307 | バイトコードデコーダ |