# 通知設計書 3-チャート読み込みエラー通知

## 概要

本ドキュメントは、K-Shoot MANIAの譜面データ（KSHファイル）読み込み時に不正なデータを検出した場合に表示されるエラーダイアログ通知の設計を記述する。未定義フィルター・エフェクト・パラメータエラー等を検出した際のdialog関数によるエラーメッセージ表示について、トリガー条件、エラーメッセージ一覧、処理フローを網羅的に定義する。

### 本通知の処理概要

本通知は、譜面ファイル（.ksh形式）の解析中に不正または未対応のデータを検出した場合に、OS標準のダイアログボックスでエラーメッセージを表示する機能を提供する。主にplay_chart_load.hspでの譜面データ解析とplay_audio_effects.hspでのオーディオエフェクト初期化の2つのフェーズで検出・表示される。

**業務上の目的・背景**：K-Shoot MANIAはユーザー作成譜面（User-Created Charts）をサポートしているため、譜面ファイルに不正なデータが含まれる可能性がある。これらのエラーを早期に検出し、制作者にフィードバックすることで、譜面品質の向上と実行時クラッシュの回避を実現する。Warning（警告）とError（エラー）の2段階で通知することで、軽微な問題と致命的な問題を区別している。

**通知の送信タイミング**：プレイ画面遷移時の譜面ファイル読み込み・解析フェーズで発生する。具体的にはparseKSHChartParamLines関数（play_chart_load.hsp）およびinitCustomAudioEffects関数（play_audio_effects.hsp）の実行中に検出される。

**通知の受信者**：現在プレイを開始しようとしているプレイヤー。特に譜面制作者にとって有用なデバッグ情報となる。

**通知内容の概要**：未定義のフィルター名、未定義のエフェクト名、不正なパラメータ名、不正なフォーマット、SwitchAudioの値変更不可エラー、譜面データの構造エラー（小節線欠落）等。

**期待されるアクション**：譜面制作者がダイアログのエラーメッセージを確認し、KSHファイルを修正する。プレイヤーの場合はエラーを認識した上でプレイを継続するか、別の譜面を選択する。

## 通知種別

モーダルダイアログ通知（OS標準のdialog命令）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期（dialog関数はモーダルで、OKボタン押下まで処理を停止） |
| 優先度 | 中（Warning）/ 高（Error：致命的な構造エラー） |
| リトライ | なし（同一エラーは譜面データ修正まで再発する） |

### 送信先決定ロジック

ダイアログはアクティブウィンドウに対してモーダル表示される。送信先はプレイヤーのPC画面上のダイアログウィンドウ固定。

## 通知テンプレート

### メール通知の場合

本通知はOS標準ダイアログのため、メール関連項目は該当しない。

| 項目 | 内容 |
|-----|------|
| 送信元アドレス | N/A |
| 送信元名称 | N/A |
| 件名 | N/A |
| 形式 | OS標準ダイアログ（dialog命令） |

### 本文テンプレート

play_chart_load.hspのエラーメッセージ:
```
Error: Undefined filter ("{フィルター名}")
Error: Undefined fx ("{エフェクト名}")
Error: Cannot change "SwitchAudio" value
Error: "SwitchAudio" value cannot be changed
Error: Unknown paramater ("{パラメータ名}")
{lang.2.1} (譜面データの先頭には小節線(--)を入力する必要があります)
```

play_audio_effects.hspのエラーメッセージ:
```
Warning: Unknown format ("{フォーマット文字列}")
Warning: Unknown paramater ("{パラメータ名}")
Error: Unknown effect type ("{エフェクトタイプ}")
Error: Too many "Switch Audio" Effects
Error: Could not find SwitchAudio file ("{ファイル名}")
```

### 添付ファイル

| ファイル名 | 形式 | 条件 | 説明 |
|----------|------|------|------|
| N/A | N/A | N/A | ダイアログ通知のため添付ファイルなし |

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| d.cnt | 現在解析中のKSHファイル行 | KSHファイルの各行 | Yes |
| fxsplitstat.0 | エフェクト名（fx-l=/fx-r=行から抽出） | d.cnt行のセミコロン分割後の先頭要素 | Yes |
| fxdefstat2.0 | エフェクトタイプ定義（type=...形式） | #define_fx/#define_filter行のパラメータ | Yes |
| fxdefstat3.0 | パラメータ名（key=value形式のkey部分） | エフェクト定義行のパラメータ | Yes |
| userfx_name.cnt | ユーザー定義エフェクト名 | #define_fx行で定義されたエフェクト名 | No |
| userfilter_name.cnt | ユーザー定義フィルター名 | #define_filter行で定義されたフィルター名 | No |
| swaudio.cnt | SwitchAudioファイル名 | エフェクト定義のfilename型パラメータ | No |
| lang.2.1 | 小節線エラーメッセージ（多言語対応） | 言語リソース | Yes |
| lang.0.2 | ダイアログタイトル | 言語リソース | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| データ解析 | 未定義フィルター検出 | filtertype行で既知のフィルター名と一致しない | play_chart_load.hsp:1028 |
| データ解析 | 未定義エフェクト検出 | fx-l=/fx-r=行で既知のFX名およびユーザー定義FX名と一致しない | play_chart_load.hsp:1193 |
| データ解析 | 未定義ユーザーFX検出 | fx:{name}:{param}=形式でnameがuserfx_name配列に存在しない | play_chart_load.hsp:1269 |
| データ解析 | SwitchAudio値変更不可 | fx:{name}:{param}=形式でFXタイプがSwitchAudioの場合 | play_chart_load.hsp:1271 |
| データ解析 | 未知パラメータ検出 | fx:{name}:{param}=形式でparamがFX定義のパラメータ名と一致しない | play_chart_load.hsp:1292 |
| データ解析 | 未定義フィルター検出（filter:行） | filter:{name}:{param}=形式でnameがuserfilter_name配列に存在しない | play_chart_load.hsp:1319 |
| データ解析 | 未知パラメータ検出（filter:行） | filter:{name}:{param}=形式でparamがフィルター定義のパラメータ名と一致しない | play_chart_load.hsp:1356 |
| データ解析 | 小節線欠落エラー | 譜面データ本体の前に小節線(--)が見つからない | play_chart_load.hsp:1365 |
| エフェクト初期化 | 不正フォーマット検出 | #define_fx行のパラメータがkey=value形式でない | play_audio_effects.hsp:41 |
| エフェクト初期化 | 未知パラメータ検出 | #define_fx行で既知のパラメータ名と一致しない | play_audio_effects.hsp:67 |
| エフェクト初期化 | 未知エフェクトタイプ | #define_fx行のtype=値が既知のエフェクトタイプと一致しない | play_audio_effects.hsp:75 |
| エフェクト初期化 | SwitchAudio上限超過 | SwitchAudioエフェクト数が31を超過 | play_audio_effects.hsp:49 |
| エフェクト初期化 | SwitchAudioファイル未発見 | 指定されたオーディオファイルが存在しない | play_audio_effects.hsp:195 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| 正常な譜面データ | エラーが検出されない場合はダイアログを表示しない |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[譜面ファイル読み込み開始] --> B[loadKSHChartFile]
    B --> C[parseKSHChartParamLines]
    C --> D{各行を解析}
    D --> E{filtertype行?}
    E -->|Yes| F{既知フィルター?}
    F -->|No| G[dialog: Undefined filter]
    F -->|Yes| H[正常処理]
    E -->|No| I{fx-l=/fx-r=行?}
    I -->|Yes| J{既知FX?}
    J -->|No| K[dialog: Undefined fx]
    J -->|Yes| H
    I -->|No| L{fx:行?}
    L -->|Yes| M{ユーザーFX名存在?}
    M -->|No| N[dialog: Undefined fx]
    M -->|Yes| O{パラメータ名存在?}
    O -->|No| P[dialog: Unknown paramater]
    O -->|Yes| H
    L -->|No| Q{小節線チェック}
    Q -->|エラー| R[dialog: 小節線エラー endfl=1]
    Q -->|OK| D
    H --> D
    G --> D
    K --> D
    N --> D
    P --> D
    R --> S[終了]
    D -->|解析完了| T[initCustomAudioEffects]
    T --> U[loadAudioFilesForSwitchAudio]
    U --> V[終了]
```

## データベース参照・更新仕様

### 参照テーブル一覧

本通知はデータベースを使用しない。KSHファイル（譜面データ）の解析結果に基づく。

| テーブル名 | 用途 | 備考 |
|-----------|------|------|
| N/A | N/A | ファイルベースの譜面データ解析 |

### テーブル別参照項目詳細

該当なし。

### 更新テーブル一覧

| テーブル名 | 操作 | 概要 |
|-----------|------|------|
| N/A | N/A | 更新処理なし |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| Warning: Unknown format | #define_fx行のパラメータ書式不正 | ダイアログ表示後、処理続行 |
| Warning: Unknown paramater | #define_fx/#define_filter行の未知パラメータ | ダイアログ表示後、処理続行 |
| Error: Undefined filter | filtertype行の未定義フィルター名 | ダイアログ表示後、デフォルト値(0)を使用して続行 |
| Error: Undefined fx | fx-l=/fx-r=行の未定義エフェクト名 | ダイアログ表示後、エフェクトなし(0)として続行 |
| Error: Unknown effect type | #define_fx/#define_filter行の未知エフェクトタイプ | ダイアログ表示後、そのエフェクト定義をスキップ |
| Error: Too many Switch Audio | SwitchAudioエフェクトが31個を超過 | ダイアログ表示後、超過分のエフェクトをスキップ |
| Error: SwitchAudio file not found | オーディオファイルが存在しない | ダイアログ表示後、該当エフェクトを無効化 |
| Error: 小節線欠落 | 譜面データ先頭に小節線(--)がない | ダイアログ表示後、endfl=1で読み込み中止 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | なし（KSHファイルの修正が必要） |
| リトライ間隔 | N/A |
| リトライ対象エラー | N/A |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | 制限なし（検出されたエラーごとに1回表示） |
| 1日あたり上限 | 制限なし |

### 配信時間帯

制限なし。プレイ開始時の譜面読み込みフェーズでのみ発生。

## セキュリティ考慮事項

- エラーメッセージに譜面ファイル内の文字列をそのまま表示するため、悪意ある文字列が含まれる可能性がある
- dialog命令はOS標準ダイアログを使用するため、スクリプトインジェクションのリスクは低い
- ファイルパスの表示を含む場合がある（SwitchAudioファイル名）

## 備考

- Warningは軽微な問題（パラメータ不正等）で、処理は続行される
- Errorは重大な問題（未定義エフェクト等）だが、多くの場合はデフォルト値にフォールバックして処理が続行される
- 小節線欠落エラー（lang.2.1）のみが致命的エラーで、endfl=1により譜面読み込みが中止される
- dialog命令の第2引数が1の場合は「!」アイコン付きの警告ダイアログ、省略時は情報ダイアログが表示される
- "paramater"のスペルは原文ママ（"parameter"の誤記と思われるが、コード上でそのまま使用されている）

---

## コードリーディングガイド

本通知を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

KSHファイルの構造とエフェクト定義データを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | fxdef.hsp | `src/audio/fxdef.hsp` | エフェクトタイプ定数（FXDEF_FXTYPE_*）、パラメータ型定数（FXDEF_LENGTH, FXDEF_FILENAME等）の定義 |
| 1-2 | play_chart_load.hsp | `src/scene/play/play_chart_load.hsp` | 1-252行目: initChartVariables関数でuserfx_name, userfilter_name等の配列変数を初期化 |

**読解のコツ**: HSP3のswitch-case文は`switch`〜`swend`で記述され、`swbreak`でcase終了。`StartsWith`はカスタム関数で文字列の先頭一致を判定する。

#### Step 2: エントリーポイントを理解する

譜面読み込みの起点を特定する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | play_chart_load.hsp | `src/scene/play/play_chart_load.hsp` | 254-305行目: loadKSHChartFile関数 - KSHファイルの読み込みとBOM処理 |
| 2-2 | play_chart_load.hsp | `src/scene/play/play_chart_load.hsp` | 307行目以降: parseKSHChartParamLines関数 - パラメータ行の解析開始 |

**主要処理フロー**:
1. **254-256行目**: KSHファイルのロード
2. **262-266行目**: UTF-8 BOM検出・除去
3. **268-273行目**: ファイル内容を行配列(d配列)に格納
4. **307行目以降**: 各行の解析ループ

#### Step 3: エフェクト定義エラー検出を理解する（play_audio_effects.hsp）

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | play_audio_effects.hsp | `src/scene/play/play_audio_effects.hsp` | 1-177行目: initCustomAudioEffects関数 - #define_fxと#define_filterの解析、エフェクトタイプ照合 |
| 3-2 | play_audio_effects.hsp | `src/scene/play/play_audio_effects.hsp` | 185-213行目: loadAudioFilesForSwitchAudio関数 - SwitchAudioファイル存在チェック |

**主要処理フロー**:
- **25-27行目**: FXDEF_FXTYPEMAXまでのエフェクトタイプ名照合
- **41行目**: key=value形式でないパラメータの検出 → Warning
- **67行目**: 未知パラメータ名の検出 → Warning
- **75行目**: 未知エフェクトタイプの検出 → Error
- **49行目**: SwitchAudio上限(31個)超過 → Error
- **195行目**: SwitchAudioファイル未発見 → Error

#### Step 4: 譜面データ本体のエラー検出を理解する（play_chart_load.hsp）

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | play_chart_load.hsp | `src/scene/play/play_chart_load.hsp` | 1020-1030行目: filtertype行の未定義フィルター検出 |
| 4-2 | play_chart_load.hsp | `src/scene/play/play_chart_load.hsp` | 1191-1194行目: fx-l=/fx-r=行の未定義FX検出 |
| 4-3 | play_chart_load.hsp | `src/scene/play/play_chart_load.hsp` | 1246-1295行目: fx:{name}:{param}=行の解析とエラー検出 |
| 4-4 | play_chart_load.hsp | `src/scene/play/play_chart_load.hsp` | 1297-1360行目: filter:{name}:{param}=行の解析とエラー検出 |
| 4-5 | play_chart_load.hsp | `src/scene/play/play_chart_load.hsp` | 1364-1367行目: 小節線欠落の致命的エラー検出 |

### プログラム呼び出し階層図

```
play (play.hsp)
    |
    +-- initChartVariables (play_chart_load.hsp:4)
    +-- loadKSHChartFile (play_chart_load.hsp:254)
    |       +-- noteload : KSHファイル読み込み
    |       +-- varmd5 : ファイルハッシュ計算
    |
    +-- parseKSHChartParamLines (play_chart_load.hsp:307)
    |       +-- [filtertype行解析]
    |       |       +-- dialog : Undefined filter (1028行)
    |       +-- [fx-l=/fx-r=行解析]
    |       |       +-- dialog : Undefined fx (1193行)
    |       +-- [fx:{name}:{param}=行解析]
    |       |       +-- dialog : Undefined fx (1269行)
    |       |       +-- dialog : Cannot change SwitchAudio (1271行)
    |       |       +-- dialog : Unknown paramater (1292行)
    |       +-- [filter:{name}:{param}=行解析]
    |       |       +-- dialog : Undefined filter (1319行)
    |       |       +-- dialog : SwitchAudio cannot be changed (1321行)
    |       |       +-- dialog : Unknown paramater (1356行)
    |       +-- [小節線チェック]
    |               +-- dialog : 小節線エラー (1365行)
    |
    +-- initCustomAudioEffects (play_audio_effects.hsp:1)
    |       +-- [#define_fx解析]
    |       |       +-- dialog : Unknown format (41行)
    |       |       +-- dialog : Unknown paramater (67行)
    |       |       +-- dialog : Unknown effect type (75行)
    |       |       +-- dialog : Too many Switch Audio (49行)
    |       +-- [#define_filter解析]
    |               +-- dialog : Unknown format (117行)
    |               +-- dialog : Unknown paramater (165行)
    |               +-- dialog : Unknown effect type (174行)
    |
    +-- loadAudioFilesForSwitchAudio (play_audio_effects.hsp:185)
            +-- dialog : Could not find SwitchAudio file (195行)
```

### データフロー図

```
[入力]                          [処理]                              [出力]

KSHファイル ──────────▶ loadKSHChartFile ────────▶ d配列(行データ)
                           (chart_load:254)              |
                                                         v
                        parseKSHChartParamLines ◀────────┘
                           (chart_load:307)
                              |
                              +── filtertype行照合 ──▶ dialog (Undefined filter)
                              +── fx行照合 ─────────▶ dialog (Undefined fx)
                              +── fx:行照合 ────────▶ dialog (Undefined fx/Unknown param)
                              +── filter:行照合 ───▶ dialog (Undefined filter/Unknown param)
                              +── 小節線チェック ──▶ dialog (構造エラー) + endfl=1

#define_fx/
#define_filter ──────▶ initCustomAudioEffects ──▶ dialog (Unknown type/format/param)
                           (audio_effects:1)
                              |
SwitchAudioファイル ─▶ loadAudioFilesForSwitchAudio ──▶ dialog (File not found)
                           (audio_effects:185)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| play_chart_load.hsp | `src/scene/play/play_chart_load.hsp` | ソース | KSHファイルの読み込みと解析。filtertype/fx/fx:/filter:行のエラー検出 |
| play_audio_effects.hsp | `src/scene/play/play_audio_effects.hsp` | ソース | カスタムオーディオエフェクトの初期化。#define_fx/#define_filterの解析とエラー検出 |
| fxdef.hsp | `src/audio/fxdef.hsp` | ソース | エフェクトタイプ定義。FXDEF_FXTYPE_*定数、パラメータ名配列等 |
| play.hsp | `src/scene/play.hsp` | ソース | プレイ画面エントリーポイント。chart_load/audio_effectsの呼び出し元 |
| play_init.hsp | `src/scene/play/play_init.hsp` | ソース | プレイ初期化処理 |
