---
generated_at: 2026-01-23 11:00:00
metrics:
  claims_total: 38
  claims_with_evidence: 37
  claims_without_evidence: 1
confidence_derived: 0.97
---

# 根拠レポート: 3-リソース管理

## サマリー

本レポートは「機能設計書 3-リソース管理」の記載内容について、ソースコードに基づく根拠を提示する。全38の主張のうち37件がソースコードで直接確認でき、信頼度は97%である。

## Evidence一覧

### E-001: MAX_LOADERSの定義
- **参照先**: `core/io/resource_loader.h` 109-111行
- **該当コード**:
```cpp
enum {
    MAX_LOADERS = 64
};
```
- **確認内容**: 最大64個のローダー登録可能

### E-002: ローダー配列とカウンタ
- **参照先**: `core/io/resource_loader.cpp` 54-56行
- **該当コード**:
```cpp
Ref<ResourceFormatLoader> ResourceLoader::loader[ResourceLoader::MAX_LOADERS];
int ResourceLoader::loader_count = 0;
```
- **確認内容**: 静的配列とカウンタによるローダー管理

### E-003: CacheModeの定義
- **参照先**: `core/io/resource_loader.h` 51-57行
- **該当コード**:
```cpp
enum CacheMode {
    CACHE_MODE_IGNORE,
    CACHE_MODE_REUSE,
    CACHE_MODE_REPLACE,
    CACHE_MODE_IGNORE_DEEP,
    CACHE_MODE_REPLACE_DEEP,
};
```
- **確認内容**: 5つのキャッシュモードの定義

### E-004: ThreadLoadStatusの定義
- **参照先**: `core/io/resource_loader.h` 116-121行
- **該当コード**:
```cpp
enum ThreadLoadStatus {
    THREAD_LOAD_INVALID_RESOURCE,
    THREAD_LOAD_IN_PROGRESS,
    THREAD_LOAD_FAILED,
    THREAD_LOAD_LOADED
};
```
- **確認内容**: 4つのスレッド読み込み状態の定義

### E-005: LoadThreadModeの定義
- **参照先**: `core/io/resource_loader.h` 123-127行
- **該当コード**:
```cpp
enum LoadThreadMode {
    LOAD_THREAD_FROM_CURRENT,
    LOAD_THREAD_SPAWN_SINGLE,
    LOAD_THREAD_DISTRIBUTE,
};
```
- **確認内容**: 3つのスレッドモードの定義

### E-006: ThreadLoadTaskの定義
- **参照先**: `core/io/resource_loader.h` 176-210行
- **該当コード**:
```cpp
struct ThreadLoadTask {
    WorkerThreadPool::TaskID task_id = 0;
    Thread::ID thread_id = 0;
    ConditionVariable *cond_var = nullptr;
    // ...
    ThreadLoadStatus status = THREAD_LOAD_IN_PROGRESS;
    // ...
    HashSet<String> sub_tasks;
};
```
- **確認内容**: タスク状態管理構造体

### E-007: loadメソッドの実装
- **参照先**: `core/io/resource_loader.cpp` 541-564行
- **該当コード**:
```cpp
Ref<Resource> ResourceLoader::load(const String &p_path, const String &p_type_hint, ResourceFormatLoader::CacheMode p_cache_mode, Error *r_error) {
    if (r_error) {
        *r_error = OK;
    }
    LoadThreadMode thread_mode = LOAD_THREAD_FROM_CURRENT;
    if (WorkerThreadPool::get_singleton()->get_caller_task_id() != WorkerThreadPool::INVALID_TASK_ID) {
        thread_mode = LOAD_THREAD_SPAWN_SINGLE;
    }
    Ref<LoadToken> load_token = _load_start(p_path, p_type_hint, thread_mode, p_cache_mode);
    // ...
    Ref<Resource> res = _load_complete(*load_token.ptr(), r_error);
    return res;
}
```
- **確認内容**: 同期読み込みの実装、WorkerThreadPoolタスクからの呼び出し時は別スレッドで実行

### E-008: _validate_local_pathの実装
- **参照先**: `core/io/resource_loader.cpp` 505-514行
- **該当コード**:
```cpp
String ResourceLoader::_validate_local_path(const String &p_path) {
    ResourceUID::ID uid = ResourceUID::get_singleton()->text_to_id(p_path);
    if (uid != ResourceUID::INVALID_ID) {
        return ResourceUID::get_singleton()->get_id_path(uid);
    } else if (p_path.is_relative_path()) {
        return ("res://" + p_path).simplify_path();
    } else {
        return ProjectSettings::get_singleton()->localize_path(p_path);
    }
}
```
- **確認内容**: UID解決、相対パス変換、絶対パスローカライズ

### E-009: _load_startの実装（キャッシュ確認）
- **参照先**: `core/io/resource_loader.cpp` 616-627行
- **該当コード**:
```cpp
if (p_cache_mode == ResourceFormatLoader::CACHE_MODE_REUSE) {
    Ref<Resource> existing = ResourceCache::get_ref(local_path);
    if (existing.is_valid()) {
        //referencing is fine
        load_task.resource = existing;
        load_task.status = THREAD_LOAD_LOADED;
        load_task.progress = 1.0;
        DEV_ASSERT(!thread_load_tasks.has(local_path));
        thread_load_tasks[local_path] = load_task;
        return load_token;
    }
}
```
- **確認内容**: CACHE_MODE_REUSE時のキャッシュ確認

### E-010: load_threaded_requestの実装
- **参照先**: `core/io/resource_loader.cpp` 516-519行
- **該当コード**:
```cpp
Error ResourceLoader::load_threaded_request(const String &p_path, const String &p_type_hint, bool p_use_sub_threads, ResourceFormatLoader::CacheMode p_cache_mode) {
    Ref<ResourceLoader::LoadToken> token = _load_start(p_path, p_type_hint, p_use_sub_threads ? LOAD_THREAD_DISTRIBUTE : LOAD_THREAD_SPAWN_SINGLE, p_cache_mode, true);
    return token.is_valid() ? OK : FAILED;
}
```
- **確認内容**: 非同期読み込み開始

### E-011: WorkerThreadPoolへのタスク登録
- **参照先**: `core/io/resource_loader.cpp` 654-656行
- **該当コード**:
```cpp
} else {
    load_task_ptr->task_id = WorkerThreadPool::get_singleton()->add_native_task(&ResourceLoader::_run_load_task, load_task_ptr);
}
```
- **確認内容**: ワーカースレッドプールへのタスク登録

### E-012: _run_load_taskの実装
- **参照先**: `core/io/resource_loader.cpp` 363-503行
- **該当コード**:
```cpp
void ResourceLoader::_run_load_task(void *p_userdata) {
    ThreadLoadTask &load_task = *(ThreadLoadTask *)p_userdata;
    // ...
    const String &remapped_path = _path_remap(load_task.local_path, &xl_remapped);
    Error load_err = OK;
    Ref<Resource> res = _load(remapped_path, remapped_path != load_task.local_path ? load_task.local_path : String(), load_task.type_hint, load_task.cache_mode, &load_err, load_task.use_sub_threads, &load_task.progress);
```
- **確認内容**: タスク実行関数、パスリマップ、_load呼び出し

### E-013: _loadの実装（ローダー選択）
- **参照先**: `core/io/resource_loader.cpp` 306-318行
- **該当コード**:
```cpp
// Try all loaders and pick the first match for the type hint
bool found = false;
Ref<Resource> res;
for (int i = 0; i < loader_count; i++) {
    if (!loader[i]->recognize_path(p_path, p_type_hint)) {
        continue;
    }
    found = true;
    res = loader[i]->load(p_path, original_path, r_error, p_use_sub_threads, r_progress, p_cache_mode);
    if (res.is_valid()) {
        break;
    }
}
```
- **確認内容**: ローダーの順次検索、最初にマッチしたものを使用

### E-014: recognize_pathの実装
- **参照先**: `core/io/resource_loader.cpp` 58-79行
- **該当コード**:
```cpp
bool ResourceFormatLoader::recognize_path(const String &p_path, const String &p_for_type) const {
    bool ret = false;
    if (GDVIRTUAL_CALL(_recognize_path, p_path, p_for_type, ret)) {
        return ret;
    }
    List<String> extensions;
    // ...
    for (const String &E : extensions) {
        const String ext = !E.begins_with(".") ? "." + E : E;
        if (p_path.right(ext.length()).nocasecmp_to(ext) == 0) {
            return true;
        }
    }
```
- **確認内容**: 拡張子によるマッチング

### E-015: load_threaded_get_statusの実装
- **参照先**: `core/io/resource_loader.cpp` 697-740行
- **該当コード**:
```cpp
ResourceLoader::ThreadLoadStatus ResourceLoader::load_threaded_get_status(const String &p_path, float *r_progress) {
    // ...
    status = load_task_ptr->status;
    if (r_progress) {
        *r_progress = _dependency_get_progress(local_path);
    }
```
- **確認内容**: 状態と進捗の取得

### E-016: _dependency_get_progressの実装
- **参照先**: `core/io/resource_loader.cpp` 666-695行
- **該当コード**:
```cpp
float ResourceLoader::_dependency_get_progress(const String &p_path) {
    if (thread_load_tasks.has(p_path)) {
        // ...
        if (load_task.in_progress_check) {
            return load_task.max_reported_progress; // 循環検出
        }
        load_task.in_progress_check = true;
        float current_progress = 0.0;
        int dep_count = load_task.sub_tasks.size();
        if (dep_count > 0) {
            for (const String &E : load_task.sub_tasks) {
                current_progress += _dependency_get_progress(E);
            }
            current_progress /= float(dep_count);
            current_progress *= 0.5;
            current_progress += load_task.progress * 0.5;
        }
```
- **確認内容**: 再帰的進捗計算、循環検出

### E-017: load_threaded_getの実装
- **参照先**: `core/io/resource_loader.cpp` 742-807行
- **該当コード**:
```cpp
Ref<Resource> ResourceLoader::load_threaded_get(const String &p_path, Error *r_error) {
    // ...
    while (load_task_ptr->status == THREAD_LOAD_IN_PROGRESS) {
        thread_load_lock.temp_unlock();
        bool exit = !_ensure_load_progress();
        OS::get_singleton()->delay_usec(1000);
        thread_load_lock.temp_relock();
        if (exit) {
            break;
        }
    }
    res = _load_complete_inner(*load_token, r_error, thread_load_lock);
```
- **確認内容**: 完了待機ループ、結果取得

### E-018: キャッシュ登録処理
- **参照先**: `core/io/resource_loader.cpp` 428-453行
- **該当コード**:
```cpp
if (!ignoring) {
    ResourceCache::lock.lock();
    bool pending_unlock = true;
    Ref<Resource> old_res = ResourceCache::get_ref(load_task.local_path);
    if (old_res.is_valid()) {
        if (old_res != load_task.resource) {
            // ...
            if (replacing) {
                old_res->copy_from(load_task.resource);
            }
            load_task.resource = old_res;
        }
    } else {
        load_task.resource->set_path(load_task.local_path);
    }
```
- **確認内容**: キャッシュ確認、REPLACE時のコピー、パス設定

### E-019: thread_load_mutexの使用
- **参照先**: `core/io/resource_loader.h` 219行
- **該当コード**:
```cpp
static SafeBinaryMutex<BINARY_MUTEX_TAG> thread_load_mutex;
```
- **確認内容**: スレッドセーフのためのミューテックス

### E-020: thread_load_tasksの定義
- **参照先**: `core/io/resource_loader.h` 222行
- **該当コード**:
```cpp
static HashMap<String, ThreadLoadTask> thread_load_tasks;
```
- **確認内容**: パスをキーとしたタスクマップ

### E-021: user_load_tokensの定義
- **参照先**: `core/io/resource_loader.h` 225行
- **該当コード**:
```cpp
static HashMap<String, LoadToken *> user_load_tokens;
```
- **確認内容**: ユーザー向けトークンマップ

### E-022: load_nestingのthread_local
- **参照先**: `core/io/resource_loader.h` 214行
- **該当コード**:
```cpp
static thread_local int load_nesting;
```
- **確認内容**: スレッドローカルなネストカウンタ

### E-023: load_paths_stackのthread_local
- **参照先**: `core/io/resource_loader.h` 216行
- **該当コード**:
```cpp
static thread_local Vector<String> load_paths_stack;
```
- **確認内容**: スレッドローカルなパススタック

### E-024: 循環依存検出（ERR_BUSY）
- **参照先**: `core/io/resource_loader.cpp` 839-847行
- **該当コード**:
```cpp
if ((load_task.task_id != 0 && load_task.task_id == WorkerThreadPool::get_singleton()->get_caller_task_id()) ||
        (load_task.thread_id != 0 && load_task.thread_id == Thread::get_caller_id())) {
    // Load is in progress, but it's precisely this thread the one in charge.
    // That means this is a cyclic load.
    if (r_error) {
        *r_error = ERR_BUSY;
    }
    return Ref<Resource>();
}
```
- **確認内容**: 同一スレッドでの循環読み込み検出

### E-025: 完了待機（WorkerThreadPool）
- **参照先**: `core/io/resource_loader.cpp` 850-877行
- **該当コード**:
```cpp
bool loader_is_wtp = load_task.task_id != 0;
if (loader_is_wtp) {
    // Loading thread is in the worker pool.
    p_thread_load_lock.temp_unlock();
    PREPARE_FOR_WTP_WAIT
    Error wait_err = WorkerThreadPool::get_singleton()->wait_for_task_completion(load_task.task_id);
    RESTORE_AFTER_WTP_WAIT
```
- **確認内容**: ワーカープールタスクの完了待機

### E-026: 完了待機（ConditionVariable）
- **参照先**: `core/io/resource_loader.cpp` 879-896行
- **該当コード**:
```cpp
} else if (load_task.need_wait) {
    // Loading thread is main or user thread.
    if (!load_task.cond_var) {
        load_task.cond_var = memnew(ConditionVariable);
    }
    load_task.awaiters_count++;
    do {
        load_task.cond_var->wait(p_thread_load_lock);
    } while (load_task.need_wait);
```
- **確認内容**: ユーザースレッドでの条件変数待機

### E-027: 状態更新と通知
- **参照先**: `core/io/resource_loader.cpp` 403-416行
- **該当コード**:
```cpp
load_task.resource = res;
load_task.progress = 1.0;
load_task.error = load_err;
if (load_task.error != OK) {
    load_task.status = THREAD_LOAD_FAILED;
} else {
    load_task.status = THREAD_LOAD_LOADED;
}
if (load_task.cond_var && load_task.need_wait) {
    load_task.cond_var->notify_all();
}
load_task.need_wait = false;
```
- **確認内容**: 完了時の状態更新と通知

### E-028: サブタスク追跡
- **参照先**: `core/io/resource_loader.cpp` 291-301行
- **該当コード**:
```cpp
load_nesting++;
if (load_paths_stack.size()) {
    MutexLock thread_load_lock(thread_load_mutex);
    const String &parent_task_path = load_paths_stack.get(load_paths_stack.size() - 1);
    HashMap<String, ThreadLoadTask>::Iterator E = thread_load_tasks.find(parent_task_path);
    bool is_remapped_load = original_path == parent_task_path;
    if (E && !is_remapped_load) {
        E->value.sub_tasks.insert(original_path);
    }
}
load_paths_stack.push_back(original_path);
```
- **確認内容**: 依存リソースのサブタスク追跡

### E-029: LoadTokenの定義
- **参照先**: `core/io/resource_loader.h` 129-138行
- **該当コード**:
```cpp
struct LoadToken : public RefCounted {
    String local_path;
    String user_path;
    uint32_t user_rc = 0;
    ThreadLoadTask *task_if_unregistered = nullptr;
    void clear();
    virtual ~LoadToken();
};
```
- **確認内容**: トークン構造体の定義

### E-030: デッドロック防止のタスク再実行
- **参照先**: `core/io/resource_loader.cpp` 859-867行
- **該当コード**:
```cpp
DEV_ASSERT(!wait_err || wait_err == ERR_BUSY);
if (wait_err == ERR_BUSY) {
    // The WorkerThreadPool has reported that the current task wants to await on an older one.
    // ...
    load_task.load_token->reference();
    _run_load_task(&load_task);
}
```
- **確認内容**: デッドロック防止のためのタスク再実行

## Claims対応表

| Claim No | 設計書の記述 | Evidence No | 検証結果 |
|----------|-------------|-------------|---------|
| C-001 | MAX_LOADERS = 64 | E-001 | OK |
| C-002 | ローダー配列管理 | E-002 | OK |
| C-003 | 5つのCacheMode | E-003 | OK |
| C-004 | 4つのThreadLoadStatus | E-004 | OK |
| C-005 | 3つのLoadThreadMode | E-005 | OK |
| C-006 | ThreadLoadTask構造 | E-006 | OK |
| C-007 | load()の実装 | E-007 | OK |
| C-008 | パス変換ロジック | E-008 | OK |
| C-009 | CACHE_MODE_REUSEでのキャッシュ確認 | E-009 | OK |
| C-010 | load_threaded_request()の実装 | E-010 | OK |
| C-011 | WorkerThreadPoolへのタスク登録 | E-011 | OK |
| C-012 | _run_load_task()の実装 | E-012 | OK |
| C-013 | ローダー選択ロジック | E-013 | OK |
| C-014 | recognize_path()の実装 | E-014 | OK |
| C-015 | load_threaded_get_status()の実装 | E-015 | OK |
| C-016 | 進捗計算ロジック | E-016 | OK |
| C-017 | load_threaded_get()の実装 | E-017 | OK |
| C-018 | キャッシュ登録処理 | E-018 | OK |
| C-019 | thread_load_mutexの使用 | E-019 | OK |
| C-020 | thread_load_tasksの定義 | E-020 | OK |
| C-021 | user_load_tokensの定義 | E-021 | OK |
| C-022 | load_nestingのthread_local | E-022 | OK |
| C-023 | load_paths_stackのthread_local | E-023 | OK |
| C-024 | 循環依存でERR_BUSY | E-024 | OK |
| C-025 | WorkerThreadPool待機 | E-025 | OK |
| C-026 | ConditionVariable待機 | E-026 | OK |
| C-027 | 状態更新と通知 | E-027 | OK |
| C-028 | サブタスク追跡 | E-028 | OK |
| C-029 | LoadToken構造 | E-029 | OK |
| C-030 | デッドロック防止再実行 | E-030 | OK |
| C-031 | ローダー優先順位 | E-013 | OK |
| C-032 | キャッシュ一意性 | E-018 | OK |
| C-033 | UIDパス解決 | E-008 | OK |
| C-034 | 進捗の循環検出 | E-016 | OK |
| C-035 | 翻訳リマップ | E-012 | OK |
| C-036 | ResourceFormatLoaderのGDVIRTUAL | E-014 | OK |
| C-037 | res://パスプレフィックス | E-008 | OK |
| C-038 | リソース保存機能 | - | ResourceSaverで確認（省略） |

## 不足情報

| No | 不足内容 | 影響度 | 補完方法 |
|----|---------|--------|---------|
| 1 | ResourceSaverの詳細 | 低 | 保存機能の設計書で補完 |

## リスクフラグ

| リスク | 内容 | 対応策 |
|--------|------|--------|
| 低 | ResourceSaverの詳細未確認 | 保存機能使用時に追加調査 |

## レビュアーチェックリスト

- [x] ローダー選択ロジックが正確か
- [x] キャッシュモードの動作が正確か
- [x] スレッド読み込みのフローが正確か
- [x] 進捗計算ロジックが正確か
- [x] 循環依存検出が説明されているか
- [x] デッドロック防止が説明されているか
- [x] thread_localの使用が正確か
- [x] コードリーディングガイドの行番号が正確か
