# 通知設計書 26-NOTIFICATION_PREDELETE

## 概要

本ドキュメントは、Godot EngineのObjectクラスにおける`NOTIFICATION_PREDELETE`通知の設計仕様を記載する。この通知はオブジェクトが削除される直前に発火し、オブジェクトのライフサイクルにおいて最後に発行される通知である。

### 本通知の処理概要

NOTIFICATION_PREDELETEは、Objectおよびそのすべての派生クラスのインスタンスが削除される前に発行されるシステム通知である。この通知はオブジェクト破棄のキャンセルを可能にする唯一のタイミングを提供する重要な通知である。

**業務上の目的・背景**：オブジェクトの削除前に、リソースの解放、シグナル接続の切断、参照の解除など、クリーンアップ処理を実行する必要がある。また、特定の条件下ではオブジェクトの削除をキャンセルする必要がある場合もある（例：RefCountedの参照カウントがまだ残っている場合）。NOTIFICATION_PREDELETEは、オブジェクトがまだ完全に有効な状態で最後のクリーンアップを行う機会を提供する。

**通知の送信タイミング**：Object::_predelete()が呼ばれた時。具体的にはmemdelete(obj)またはfree()が呼ばれ、predelete_handler()経由で_predelete()が実行される際に、notification(NOTIFICATION_PREDELETE, true)として送信される。p_reversed = trueのため、派生クラスから基底クラスの順で通知が処理される。

**通知の受信者**：削除されるすべてのObjectインスタンス（Node、Resource、その他すべての派生クラスを含む）。

**通知内容の概要**：通知IDは整数値1（NOTIFICATION_PREDELETE = 1）。追加のパラメータは含まないが、p_reversed = trueで送信される。

**期待されるアクション**：
- シグナル接続の切断
- 子ノードの削除（Nodeの場合）
- 保持しているリソースの解放
- cancel_free()による削除キャンセル（必要な場合）
- シーンツリーからの離脱処理

## 通知種別

エンジン内部通知（Engine Internal Notification）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期 |
| 優先度 | 最高（オブジェクト削除時に必ず発行） |
| リトライ | 無し |
| 逆順処理 | true（派生→基底の順） |

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

1. memdelete(obj)またはobj->free()が呼ばれる
2. predelete_handler(obj)が呼ばれる
3. Object::_predelete()が実行される
4. _predelete_ok = true を設定
5. notification(NOTIFICATION_PREDELETE, true)が送信される
6. _predelete_okがfalseに変更された場合、削除をキャンセル

## 通知テンプレート

### システム通知の場合

| 項目 | 内容 |
|-----|------|
| 通知ID | 1 |
| 通知名 | NOTIFICATION_PREDELETE |
| 定義箇所 | core/object/object.h |

### 通知ハンドリング例

```cpp
void MyObject::_notification(int p_notification) {
    switch (p_notification) {
        case NOTIFICATION_PREDELETE: {
            // 削除前のクリーンアップ処理
            if (_should_cancel_deletion()) {
                cancel_free();
                return;
            }
            _cleanup_resources();
        } break;
    }
}
```

```gdscript
func _notification(what):
    if what == NOTIFICATION_PREDELETE:
        # 削除前のクリーンアップ処理
        _cleanup_resources()
```

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| p_notification | 通知ID（1） | エンジン内部 | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| API呼び出し | memdelete(obj) | 常に | オブジェクト削除時 |
| API呼び出し | Object.free() | 常に | オブジェクト解放時 |
| 内部処理 | predelete_handler(obj) | 常に | ObjectDB管理のオブジェクト削除 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| なし | すべてのObjectインスタンスの削除時に常に送信される |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[memdelete/free呼び出し] --> B[predelete_handler\obj\]
    B --> C[Object::_predelete]
    C --> D[_predelete_ok = true]
    D --> E[notification\nNOTIFICATION_PREDELETE, true\]
    E --> F{_predelete_ok?}
    F -->|false| G[削除キャンセル\nreturn false]
    F -->|true| H[_gdtype_ptr = nullptr]
    H --> I[notification\nNOTIFICATION_PREDELETE_CLEANUP, true\]
    I --> J[script_instance削除]
    J --> K[_extension削除]
    K --> L[return true]
    L --> M[デストラクタ実行]
    G --> N[オブジェクト存続]
```

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

### 参照データ一覧

| データ | 用途 | 備考 |
|--------|------|------|
| Object::_predelete_ok | 削除キャンセル判定 | bool |
| Object::script_instance | スクリプトインスタンス参照 | 削除対象 |
| Object::_extension | GDExtension参照 | 削除対象 |

### 更新データ一覧

| データ | 操作 | 概要 |
|--------|------|------|
| Object::_predelete_ok | 設定/チェック | 削除可否フラグ |
| Object::_gdtype_ptr | nullptr設定 | 型ポインタのクリア |
| Object::script_instance | 削除 | memdeleteで解放 |
| Object::_extension | nullptr設定 | 拡張参照のクリア |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| 削除キャンセル | cancel_free()呼び出し | _predelete_okをfalseに設定、削除中止 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | 0（リトライなし） |
| リトライ間隔 | N/A |
| リトライ対象エラー | N/A |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | 制限なし |
| 1日あたり上限 | 制限なし |

### 配信時間帯

制限なし（オブジェクト削除時にいつでも発生）

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

- この通知はエンジン内部でのみ使用され、外部からの直接呼び出しは想定されていない
- cancel_free()を不適切に使用するとメモリリークの原因となる
- p_reversed = trueで送信されるため、処理順序に注意が必要

## 備考

- 通知ID = 1 であり、NOTIFICATION_POSTINITIALIZEの次に重要な基本通知
- p_reversed = trueで送信されるため、派生クラスの_notificationが先に呼ばれる
- cancel_free()でオブジェクト削除をキャンセル可能
- NOTIFICATION_PREDELETE_CLEANUP（3）は内部用でスクリプトには公開されない
- Nodeの場合、子ノードの削除やシーンツリーからの離脱がこの通知内で行われる

---

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

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

### 推奨読解順序

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

Object基底クラスの削除関連データを理解することが重要。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | object.h | `core/object/object.h` | NOTIFICATION_PREDELETE定数の定義（856行目） |
| 1-2 | object.h | `core/object/object.h` | _predelete()宣言（649行目） |
| 1-3 | object.h | `core/object/object.h` | _predelete_okメンバ変数（659行目） |

**読解のコツ**: NOTIFICATION_PREDELETE = 1であり、NOTIFICATION_POSTINITIALIZEの次の値であることを確認。

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

処理の起点となる関数を特定。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | object.cpp | `core/object/object.cpp` | _predelete関数（273-316行目） |
| 2-2 | object.cpp | `core/object/object.cpp` | cancel_free関数（318-320行目） |

**主要処理フロー**:
1. **274行目**: _predelete_ok = true を設定
2. **275行目**: notification(NOTIFICATION_PREDELETE, true)を送信
3. **276-278行目**: _predelete_okがfalseならfalseを返して削除キャンセル
4. **280行目**: _gdtype_ptr = nullptr を設定
5. **281行目**: NOTIFICATION_PREDELETE_CLEANUPを送信（内部用）
6. **285-288行目**: script_instanceを削除
7. **290-302行目**: _extensionを削除

#### Step 3: 通知ハンドラを理解する

派生クラスでの通知処理例を確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | node.cpp | `scene/main/node.cpp` | NodeでのPREDELETE処理（子ノード削除、ツリー離脱） |
| 3-2 | ref_counted.cpp | `core/object/ref_counted.cpp` | RefCountedでのPREDELETE処理 |

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

```
memdelete(obj) または obj->free()
    │
    └─ predelete_handler(obj)
           │
           └─ Object::_predelete()
                  │
                  ├─ _predelete_ok = true
                  │
                  ├─ notification(NOTIFICATION_PREDELETE, true) [逆順]
                  │      │
                  │      ├─ スクリプト::_notification() [最初]
                  │      ├─ MyObject::_notification()
                  │      ├─ Node::_notification() [子削除、ツリー離脱]
                  │      └─ Object::_notification() [最後]
                  │
                  ├─ [_predelete_ok チェック]
                  │      └─ false → return false（削除キャンセル）
                  │
                  ├─ _gdtype_ptr = nullptr
                  │
                  ├─ notification(NOTIFICATION_PREDELETE_CLEANUP, true)
                  │
                  ├─ memdelete(script_instance)
                  │
                  ├─ _extension->free_instance()
                  │
                  └─ return true
                         │
                         └─ デストラクタチェーン実行
```

### データフロー図

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

memdelete(obj) ─────────▶ predelete_handler ────────────▶ _predelete()
       │                       │                              │
       │                       ▼                              ▼
       │              _predelete_ok = true        NOTIFICATION_PREDELETE
       │                       │                              │
       │                       ▼                              ▼
       │              notification(PREDELETE)      cancel_free()可能
       │                       │                              │
       │                       ▼                              ▼
       │              _predelete_okチェック        削除継続 or キャンセル
       │                       │
       └───────────────────────┴───────────────────────▶ script_instance削除
                                                        _extension削除
                                                        デストラクタ実行
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| object.h | `core/object/object.h` | ヘッダー | Object基底クラス定義、通知定数 |
| object.cpp | `core/object/object.cpp` | ソース | _predelete、cancel_freeの実装 |
| object_db.h | `core/object/object_db.h` | ヘッダー | ObjectDB、predelete_handler宣言 |
| object_db.cpp | `core/object/object_db.cpp` | ソース | predelete_handlerの実装 |
| node.cpp | `scene/main/node.cpp` | ソース | NodeでのPREDELETE処理（子削除） |
| ref_counted.cpp | `core/object/ref_counted.cpp` | ソース | RefCountedでのPREDELETE処理 |
| memory.h | `core/os/memory.h` | ヘッダー | memdeleteマクロ定義 |
