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 同期フロー

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 には metadata.json とは独立した enum定義が存在します。

# ability.py (行10-22) - metadata.json と独立
class TriggerType(IntEnum):
    NONE = 0
    ON_PLAY = 1
    ON_LIVE_START = 2
    # ...

これは 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.pyAbilityCostType200以上のエントリ を持ち、その多くが自動生成された「プレースホルダ」です:

# 行410-500: 自動生成されたエントリの例
PLACE_ENERGY_FROM_DECK_TO_DISCARD = 110
PLACE_ENERGY_FROM_DECK_TO_HAND = 111
# ... 90行以上の自動生成エントリ

これらは metadata.jsoncosts セクション (95エントリ) と比較して2倍以上の規模です。


3. ビットマスク処理の複雑さ分析

3.1 _pack_filter_attr のビットレイアウト

ability.py_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 FilterColor Filter で競合しています:

# 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 では、同じビットレイアウトを使用:

/// 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 コンパイルフロー

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 メソッドには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.pyability.py も生成するよう拡張
  2. ビット競合の解消

    • Color Filter を Bits 32-38 に移動 (Rust側に合わせる)
    • または、Cost Filter を Bits 8-14 に移動

5.2 中期的改善 (優先度: 中)

  1. フィルタ構造体の導入

    @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:
            """構造化されたフィルタをビット列に変換"""
    
  2. エフェクトコンパイラの分割

    • _compile_single_effect を各エフェクトタイプ別のハンドラに分割
    • Visitor パターンまたは Strategy パターンの採用

5.3 長期的改善 (優先度: 低)

  1. バイトコード設計の再検討

    • 現在: 4-int固定長 [op, v, a, s]
    • 提案: 可変長またはTLV (Type-Length-Value) 形式
  2. 宣言的エフェクト定義

    • 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 323 定数定義のマスター
engine/models/ability.py 1852 能力定義・コンパイル
tools/sync_metadata.py 349 定数同期スクリプト
engine_rust_src/src/core/generated_constants.rs 275 Rust定数 (自動生成)
engine_rust_src/src/core/logic/filter.rs 150+ Rustフィルタロジック
tools/verify/bytecode_decoder.py 307 バイトコードデコーダ