# 機能設計書 2-ノードシステム

## 概要

本ドキュメントは、Godot Engineにおけるノードシステムの詳細設計を記述する。ノード（Node）は、シーンツリーを構成する基本単位であり、すべてのゲームオブジェクトの基底クラスとして機能する。

### 本機能の処理概要

ノードシステムは、Godot Engineにおけるすべてのゲームオブジェクトの基盤となるクラス階層を提供する。親子関係の管理、ライフサイクル通知、プロセス処理、入力処理、グループ管理などの機能を統合的に提供する。

**業務上の目的・背景**：ゲーム開発では、キャラクター、背景オブジェクト、UI要素、カメラなど多様なゲームオブジェクトを扱う必要がある。ノードシステムは、これらすべてのオブジェクトに共通する基本機能（親子関係、更新処理、入力処理など）を提供することで、開発者が個々のゲームロジックに集中できるようにする。また、継承による拡張性を提供し、Node2D、Node3D、Control等の特化したノードタイプの基盤となる。

**機能の利用シーン**：
- シーン内でのオブジェクト階層構造の構築（親子関係の設定）
- 毎フレームの更新処理（_process、_physics_process）の実装
- キーボード・マウス・タッチ入力の受け取り
- ノードのライフサイクル管理（ツリーへの追加・削除・準備完了）
- グループを使った複数ノードの一括管理
- ノードパスによるノードの検索・取得
- ノードの複製・置換

**主要な処理内容**：
1. 親子関係の管理（add_child、remove_child、get_parent、get_children）
2. ノード名の管理と検証（set_name、_validate_child_name）
3. ライフサイクル通知の伝播（NOTIFICATION_ENTER_TREE、NOTIFICATION_EXIT_TREE、NOTIFICATION_READY）
4. プロセス処理の制御（set_process、set_physics_process）
5. 入力処理の制御（set_process_input、set_process_unhandled_input）
6. グループ管理（add_to_group、remove_from_group、is_in_group）
7. ノードパスによるノード取得（get_node、get_node_or_null）
8. プロセスモード・物理補間の継承制御
9. マルチプレイヤー権限管理
10. ノードの複製（duplicate）と置換（replace_by）

**関連システム・外部連携**：
- SceneTree: ツリー全体の管理、プロセスループ
- Viewport: 描画領域の管理
- MultiplayerAPI: ネットワーク同期（RPC）
- MessageQueue: 遅延呼び出し

**権限による制御**：マルチプレイヤーシステムにおいて、multiplayer_authorityによりノードの制御権限を管理できる。デフォルトはサーバー（peer_id = 1）が権限を持つ。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | エディタシーンビュー | 主画面 | ノードの追加・削除・編集 |
| - | エディタインスペクタ | 参照画面 | ノードプロパティの編集 |
| - | エディタノードドック | 参照画面 | シグナル・グループの管理 |

## 機能種別

エンジンコア機能 / オブジェクト基盤 / ライフサイクル管理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| p_child | Node | Yes | 追加する子ノード | null不可、親を持たないこと |
| p_name | StringName | Yes | ノード名 | 空でないこと、有効な文字のみ |
| p_path | NodePath | Yes | ノードパス | 空でないこと |
| p_index | int | Yes | 子ノードのインデックス | 有効範囲内 |
| p_group | StringName | Yes | グループ名 | 空でないこと |
| p_process | bool | Yes | 処理有効フラグ | - |
| p_mode | ProcessMode | Yes | プロセスモード | 有効な列挙値 |
| p_internal | InternalMode | No | 内部ノードモード | 有効な列挙値 |

### 入力データソース

- SceneTreeからのライフサイクル通知
- ユーザースクリプトからのAPI呼び出し
- エディタからのノード操作

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| name | StringName | ノード名 |
| parent | Node* | 親ノード |
| children | HashMap<StringName, Node*> | 子ノードマップ |
| path | NodePath | ノードのフルパス |
| index | int | 親内でのインデックス |
| tree | SceneTree* | 所属するシーンツリー |
| viewport | Viewport* | 所属するビューポート |
| groups | List<GroupInfo> | 所属グループ一覧 |

### 出力先

- ライフサイクル通知（_notification）
- シグナル発行（ready、renamed、tree_entered、tree_exited等）
- 仮想関数コールバック（_enter_tree、_exit_tree、_ready、_process等）

## 処理フロー

### 処理シーケンス

```
1. ノード作成
   └─ コンストラクタでデータ初期化

2. ツリーへの追加 (add_child)
   ├─ 名前の検証 (_validate_child_name)
   ├─ 子ノードマップへの追加
   ├─ NOTIFICATION_PARENTED 発行
   ├─ _set_tree() でツリー設定
   │      ├─ _propagate_enter_tree()
   │      │      ├─ ツリー/深度/ビューポート設定
   │      │      ├─ グループへの登録
   │      │      ├─ NOTIFICATION_ENTER_TREE
   │      │      ├─ _enter_tree() 仮想関数呼び出し
   │      │      ├─ tree_entered シグナル発行
   │      │      └─ 子ノードへ再帰伝播
   │      └─ _propagate_ready()
   │             ├─ NOTIFICATION_POST_ENTER_TREE
   │             ├─ NOTIFICATION_READY（初回のみ）
   │             └─ ready シグナル発行
   └─ add_child_notify()
       └─ NOTIFICATION_CHILD_ORDER_CHANGED

3. フレーム処理
   └─ SceneTreeから通知を受信
       ├─ NOTIFICATION_PROCESS → _process() 呼び出し
       └─ NOTIFICATION_PHYSICS_PROCESS → _physics_process() 呼び出し

4. ツリーからの削除 (remove_child)
   ├─ _set_tree(nullptr)
   │      └─ _propagate_exit_tree()
   │             ├─ _exit_tree() 仮想関数呼び出し
   │             ├─ tree_exiting シグナル発行
   │             ├─ NOTIFICATION_EXIT_TREE
   │             ├─ グループからの削除
   │             └─ 子ノードへ再帰伝播（逆順）
   ├─ remove_child_notify()
   ├─ NOTIFICATION_UNPARENTED
   └─ _propagate_after_exit_tree()
```

### フローチャート

```mermaid
flowchart TD
    A[ノード作成] --> B{ツリーに追加?}
    B -->|Yes| C[add_child]
    B -->|No| D[スタンドアロン状態]

    C --> E[名前検証]
    E --> F[子ノードマップ追加]
    F --> G[NOTIFICATION_PARENTED]
    G --> H[_propagate_enter_tree]

    H --> I[NOTIFICATION_ENTER_TREE]
    I --> J[_enter_tree 呼び出し]
    J --> K[tree_entered シグナル]
    K --> L{子ノードあり?}
    L -->|Yes| H
    L -->|No| M[_propagate_ready]

    M --> N{初回?}
    N -->|Yes| O[NOTIFICATION_READY]
    N -->|No| P[処理続行]
    O --> Q[_ready 呼び出し]
    Q --> P

    P --> R{削除要求?}
    R -->|No| S[フレーム処理]
    S --> T[NOTIFICATION_PROCESS]
    T --> R

    R -->|Yes| U[remove_child]
    U --> V[_propagate_exit_tree]
    V --> W[NOTIFICATION_EXIT_TREE]
    W --> X[グループ削除]
    X --> Y[終了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-001 | メインスレッド制限 | ツリー内ノードの追加・削除・移動はメインスレッドからのみ | ツリー内の場合 |
| BR-002 | 単一親制限 | ノードは同時に1つの親しか持てない | 常時 |
| BR-003 | 循環参照禁止 | 自分の祖先を子として追加できない | add_child時 |
| BR-004 | ブロック中操作禁止 | blocked > 0の間は子ノードの操作不可 | ツリー走査中 |
| BR-005 | 名前の一意性 | 同一親内で子ノード名は一意 | 常時 |
| BR-006 | ルートノード制限 | ルートノードはINHERITモードに設定不可 | ルートノードの場合 |
| BR-007 | ready通知は初回のみ | NOTIFICATION_READYは初回ツリー追加時のみ | 初回enter時 |

### 計算ロジック

**ノードインデックスの計算**:
```
InternalMode別のインデックス計算:
- INTERNAL_MODE_FRONT: index = そのまま
- INTERNAL_MODE_DISABLED: index = internal_front_count + index
- INTERNAL_MODE_BACK: index = internal_front_count + external_count + index
```

**can_process判定**:
```
if tree is suspended:
    return false
if process_mode == INHERIT:
    process_mode = process_owner.process_mode
if process_mode == DISABLED:
    return false
if process_mode == ALWAYS:
    return true
if paused:
    return process_mode == WHEN_PAUSED
else:
    return process_mode == PAUSABLE
```

## データベース操作仕様

本機能はデータベースを使用しない。メモリ内のデータ構造のみで動作する。

### 操作別データベース影響一覧

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| - | - | - | データベース操作なし |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| ERR_INVALID_PARAMETER | パラメータエラー | メインスレッド以外からのツリー操作 | メインスレッドまたはcall_deferredで呼び出す |
| ERR_FAIL_COND | 前提条件エラー | 子ノードが既に親を持つ | 先にremove_childする |
| ERR_FAIL_COND | 前提条件エラー | 自分自身を子として追加 | 別のノードを使用 |
| ERR_FAIL_COND | 前提条件エラー | 祖先を子として追加（循環） | 階層構造を見直す |
| ERR_FAIL_COND | 前提条件エラー | blocked中の子操作 | call_deferredで呼び出す |
| ERR_FAIL_INDEX | インデックスエラー | 無効な子インデックス | 有効範囲内のインデックスを使用 |

### リトライ仕様

エラー時のリトライ機構は提供されない。call_deferredを使用して遅延実行することで、多くのタイミング関連エラーを回避できる。

## トランザクション仕様

本機能はデータベーストランザクションを使用しない。ただし、以下の操作は一貫性が保証される:

- blockedカウンタによるツリー走査中の変更禁止
- ERR_THREAD_GUARDマクロによるスレッドガード

## パフォーマンス要件

- 子ノードはHashMapで管理し、名前による高速検索を実現
- 子ノードキャッシュ（children_cache）はdirty flagで遅延更新
- プロセス処理は_is_any_processing()による早期チェック
- ノード名の自動生成は高速バージョン（@ClassName@番号）を使用

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

- ERR_THREAD_GUARDによるスレッドセーフティ確保
- multiplayer_authorityによるネットワーク権限管理
- queue_freeによる安全なノード削除

## 備考

- Node::current_process_thread_groupはthread_localで、並列処理時のスレッドグループ追跡に使用
- ready_firstフラグにより、NOTIFICATION_READYは最初のツリー追加時のみ発行
- internal_modeにより、エディタ用の内部ノードを通常の子ノードと分離可能

---

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

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

### 推奨読解順序

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

Nodeクラスの内部データ構造を把握することが、全体理解の基盤となる。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | node.h | `scene/main/node.h` | Data構造体、列挙型、メンバ変数の理解 |

**読解のコツ**:
- `Data`構造体（195-295行）がノードの全状態を保持
- ビットフィールドによるメモリ効率化（242-284行）
- `ProcessMode`、`ProcessThreadGroup`、`PhysicsInterpolationMode`等の列挙型を先に理解

**主要データ構造**:
- **200行**: `Node *parent` - 親ノードへの参照
- **202行**: `HashMap<StringName, Node *> children` - 子ノードマップ
- **204行**: `LocalVector<Node *> children_cache` - ソート済み子ノードキャッシュ
- **215行**: `SceneTree *tree` - 所属するシーンツリー
- **219行**: `Viewport *viewport` - 所属するビューポート
- **223行**: `HashMap<StringName, GroupData> grouped` - グループ所属情報
- **227-232行**: プロセス関連（process_owner、process_thread_group_owner等）

#### Step 2: ライフサイクル通知を理解する

ノードのライフサイクル（作成→ツリー追加→更新→ツリー削除→破棄）を追う。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | node.cpp | `scene/main/node.cpp` | _notification、_propagate_enter_tree、_propagate_exit_tree |

**主要処理フロー**:
1. **60-315行**: `_notification()` - 各種通知の処理
2. **335-383行**: `_propagate_enter_tree()` - ツリー追加時の伝播処理
3. **404-451行**: `_propagate_exit_tree()` - ツリー削除時の伝播処理
4. **317-333行**: `_propagate_ready()` - ready通知の伝播
5. **385-402行**: `_propagate_after_exit_tree()` - 終了後処理の伝播

**重要な通知定数** (node.h 449-505行):
- `NOTIFICATION_ENTER_TREE = 10`
- `NOTIFICATION_EXIT_TREE = 11`
- `NOTIFICATION_READY = 13`
- `NOTIFICATION_PROCESS = 17`
- `NOTIFICATION_PHYSICS_PROCESS = 16`

#### Step 3: 子ノード管理を理解する

親子関係の追加・削除・移動処理を追う。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | node.cpp | `scene/main/node.cpp` | add_child、remove_child、_add_child_nocheck |

**主要処理フロー**:
- **1699-1721行**: `add_child()` - 子ノード追加のメインエントリポイント
- **1652-1697行**: `_add_child_nocheck()` - 実際の追加処理
- **1735-1772行**: `remove_child()` - 子ノード削除
- **497-523行**: `move_child()` - 子ノードの順序変更
- **525-580行**: `_move_child()` - 実際の移動処理

#### Step 4: プロセス処理を理解する

フレーム毎の更新処理の仕組みを把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | node.cpp | `scene/main/node.cpp` | set_process、_add_to_process_thread_group |

**主要処理フロー**:
- **611-631行**: `set_physics_process()` - 物理処理の有効化
- **1016-1036行**: `set_process()` - 通常処理の有効化
- **1064-1070行**: `_add_process_group()` / `_remove_process_group()`
- **1072-1117行**: `_add_to_process_thread_group()` / `_remove_from_process_thread_group()`
- **901-933行**: `can_process()` / `_can_process()` - 処理可能判定

#### Step 5: ノード検索を理解する

ノードパスによるノード取得の仕組みを追う。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | node.cpp | `scene/main/node.cpp` | get_node、get_node_or_null |

**主要処理フロー**:
- **1892-1952行**: `get_node_or_null()` - パスによるノード取得の実装
- **1954-1969行**: `get_node()` - エラー付きバージョン
- **1977-1999行**: `find_child()` - パターンマッチによる子ノード検索

#### Step 6: 名前管理を理解する

ノード名の設定と一意性確保の仕組みを追う。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 6-1 | node.cpp | `scene/main/node.cpp` | set_name、_validate_child_name |

**主要処理フロー**:
- **1430-1466行**: `set_name()` - ノード名の設定
- **1515-1566行**: `_validate_child_name()` - 名前の検証と一意化
- **1593-1646行**: `_generate_serial_child_name()` - 連番付き名前の生成

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

```
Node (Object継承)
    │
    ├─ add_child(p_child)
    │      ├─ バリデーション（親チェック、循環チェック、blocked チェック）
    │      ├─ _validate_child_name(p_child)
    │      │      └─ _generate_serial_child_name() [必要な場合]
    │      └─ _add_child_nocheck(p_child, name, internal_mode)
    │             ├─ data.children.insert()
    │             ├─ p_child->notification(NOTIFICATION_PARENTED)
    │             ├─ p_child->_set_tree(data.tree)
    │             │      ├─ _propagate_enter_tree()
    │             │      │      ├─ グループ登録
    │             │      │      ├─ notification(NOTIFICATION_ENTER_TREE)
    │             │      │      ├─ GDVIRTUAL_CALL(_enter_tree)
    │             │      │      ├─ emit_signal("tree_entered")
    │             │      │      ├─ tree->node_added(this)
    │             │      │      └─ 子ノードへ再帰
    │             │      └─ _propagate_ready()
    │             │             ├─ notification(NOTIFICATION_POST_ENTER_TREE)
    │             │             ├─ notification(NOTIFICATION_READY) [初回のみ]
    │             │             └─ emit_signal("ready")
    │             ├─ add_child_notify(p_child)
    │             └─ notification(NOTIFICATION_CHILD_ORDER_CHANGED)
    │
    ├─ remove_child(p_child)
    │      ├─ p_child->_set_tree(nullptr)
    │      │      └─ _propagate_exit_tree()
    │      │             ├─ GDVIRTUAL_CALL(_exit_tree)
    │      │             ├─ emit_signal("tree_exiting")
    │      │             ├─ notification(NOTIFICATION_EXIT_TREE)
    │      │             ├─ tree->node_removed(this)
    │      │             ├─ グループ削除
    │      │             └─ 子ノードへ再帰（逆順）
    │      ├─ remove_child_notify(p_child)
    │      ├─ p_child->notification(NOTIFICATION_UNPARENTED)
    │      ├─ data.children.erase()
    │      └─ p_child->_propagate_after_exit_tree()
    │
    ├─ get_node_or_null(p_path)
    │      ├─ パス解析
    │      └─ ノード走査
    │             ├─ "." → 自分自身
    │             ├─ ".." → 親
    │             ├─ "%Name" → オーナーのユニークノード
    │             └─ "Name" → data.children.getptr(name)
    │
    └─ _notification(p_notification)
           ├─ NOTIFICATION_ENTER_TREE
           │      ├─ process_mode継承設定
           │      ├─ process_thread_group継承設定
           │      ├─ physics_interpolation_mode継承設定
           │      └─ 入力グループ登録
           ├─ NOTIFICATION_EXIT_TREE
           │      ├─ 入力グループ削除
           │      └─ プロセスグループ削除
           ├─ NOTIFICATION_READY
           │      ├─ 仮想関数オーバーライド検出
           │      ├─ set_process(true) [_process定義時]
           │      └─ GDVIRTUAL_CALL(_ready)
           ├─ NOTIFICATION_PROCESS
           │      └─ GDVIRTUAL_CALL(_process, delta)
           └─ NOTIFICATION_PHYSICS_PROCESS
                  └─ GDVIRTUAL_CALL(_physics_process, delta)
```

### データフロー図

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

スクリプト/エディタ ─────▶ add_child() ──────────────────▶ 子ノードマップ更新
                               │                              │
                               ▼                              ▼
                          _set_tree() ────────────────────▶ tree/viewport設定
                               │
                               ▼
                          _propagate_enter_tree() ────────▶ NOTIFICATION_ENTER_TREE
                               │                              │
                               ▼                              ▼
                          グループ登録 ───────────────────▶ SceneTree.group_map
                               │
                               ▼
                          _propagate_ready() ─────────────▶ NOTIFICATION_READY
                                                             │
                                                             ▼
                                                          ready シグナル

SceneTree ──────────────▶ notification() ────────────────▶ _process() 呼び出し
(process/physics_process)     │
                              ▼
                         GDVIRTUAL_CALL ─────────────────▶ GDScript._process()

NodePath ───────────────▶ get_node_or_null() ────────────▶ Node* または nullptr
                               │
                               ▼
                          パス解析 → ノード走査
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| node.cpp | `scene/main/node.cpp` | ソース | Nodeクラスの実装 |
| node.h | `scene/main/node.h` | ヘッダ | Nodeクラスの定義 |
| node.compat.inc | `scene/main/node.compat.inc` | ソース | 互換性メソッド |
| scene_tree.cpp | `scene/main/scene_tree.cpp` | ソース | シーンツリー（Nodeと密接に連携） |
| scene_tree.h | `scene/main/scene_tree.h` | ヘッダ | シーンツリー定義 |
| viewport.cpp | `scene/main/viewport.cpp` | ソース | ビューポート |
| window.cpp | `scene/main/window.cpp` | ソース | ウィンドウ |
| scene_string_names.h | `scene/scene_string_names.h` | ヘッダ | シーン用文字列定数 |
| packed_scene.cpp | `scene/resources/packed_scene.cpp` | ソース | シーンのシリアライズ |
| multiplayer_api.cpp | `scene/main/multiplayer_api.cpp` | ソース | マルチプレイヤーRPC |
| tween.cpp | `scene/animation/tween.cpp` | ソース | Tweenアニメーション |
