> For the complete documentation index, see [llms.txt](https://azuriohs-organization.gitbook.io/r-type/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://azuriohs-organization.gitbook.io/r-type/subsystems/our-subsystems/resource-manager.md).

# Resource manager

## Table of Contents

* [Introduction](#introduction)
* [Overview](#overview)
* [Architecture](#architecture)
* [Getting Started](#getting-started)
* [Core Components](#core-components)
  * [Resource Manager](#resource-manager)
  * [Caching System](#caching-system)
* [Resource Loading](#resource-loading)
* [Caching Mechanism](#caching-mechanism)
* [Error Handling](#error-handling)
* [Advanced Features](#advanced-features)
* [Examples](#examples)
* [Best Practices](#best-practices)
* [Troubleshooting](#troubleshooting)

***

## Introduction

The Resource Manager is a C++ resource management subsystem designed for the R-Type game engine. It provides efficient file loading with automatic caching and cache invalidation when files are modified.

This Resource Manager subsystem is designed as a modular library that can be dynamically loaded into the R-Type game engine, following the plugin architecture pattern. It implements the `IResourceManager` interface from the common engine subsystem, allowing for easy swapping between different resource management implementations.

***

## Overview

### Features

* **File Loading**: Load binary files from disk
* **Automatic Caching**: Resources are automatically cached in memory
* **Cache Invalidation**: Automatically reload resources when files are modified
* **Binary Support**: Full support for binary file formats
* **Exception Handling**: Throws exceptions for invalid files or errors
* **Memory Efficient**: Shared cache across resource loads

### Dependencies

* **C++20 Standard Library**: Required for `std::filesystem`, `std::vector`, `std::chrono`
* **Common Engine**: Depends on the common engine interfaces

### Build Requirements

* CMake 3.16.0 or higher
* C++20 compiler

***

## Architecture

### Module Structure

The Resource Manager subsystem follows a simple, focused architecture:

```
Resource Manager Module (Entry Point)
├── IResourceManager (Interface)
└── ResourceManager (Implementation)
    ├── Load Resource
    ├── Cache Management
    │   ├── Store in Cache
    │   ├── Get from Cache
    │   └── File Edit Detection
    └── Resource Cache (unordered_map)
        └── Resource Data + Timestamp
```

### Entry Point

The module exports an entry point function that returns a `ResourceManager` instance:

```cpp
extern "C" Subsystems::ResourceManager::ResourceManager *entryPoint(void);
```

This allows the engine to dynamically load the Resource Manager library at runtime.

***

## Getting Started

### Building the Module

1. **Configure CMake**:

```bash
cd lib/ResourceManager/V1
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
```

2. **Build**:

```bash
cmake --build build
```

The compiled library (`libresource-manager-v1.dylib` on macOS, `.so` on Linux, `.dll` on Windows) will be placed in the `lib/` directory.

### Basic Usage

```cpp
#include "Subsystems/ResourceManager/IResourceManager.hpp"
#include <vector>
#include <string>

// Create Resource Manager instance (usually loaded dynamically)
auto resourceManager = std::make_unique<Subsystems::ResourceManager::ResourceManager>();

// Load a resource
try {
    auto& imageData = resourceManager->LoadResource("assets/player.png");

    // Use the resource data
    // imageData is a std::vector<char>& containing the file contents
    std::cout << "Loaded " << imageData.size() << " bytes" << std::endl;

    // Resource is cached - subsequent calls return cached version
    auto& cachedImageData = resourceManager->LoadResource("assets/player.png");
    // cachedImageData points to the same cached data

} catch (const Exception::Subsystems::ResourceManager::InvalidFile& e) {
    std::cerr << "Error loading resource: " << e.what() << std::endl;
}
```

***

## Core Components

### Resource Manager

The `ResourceManager` class is the main interface for resource loading.

**Key Methods:**

* `LoadResource(filePath)`: Load a resource from a file path

**Example:**

```cpp
auto resourceManager = std::make_unique<Subsystems::ResourceManager::ResourceManager>();

// Load a texture
auto& textureData = resourceManager->LoadResource("assets/textures/ship.png");

// Load a sound file
auto& soundData = resourceManager->LoadResource("assets/sounds/shoot.wav");

// Load a data file
auto& dataFile = resourceManager->LoadResource("assets/data/config.json");
```

### Caching System

The Resource Manager automatically caches loaded resources. The cache system provides:

* **Automatic Caching**: All loaded resources are cached in memory
* **Cache Invalidation**: Resources are automatically reloaded if files are modified
* **Shared References**: Multiple loads of the same file return references to the same cached data

**How It Works:**

1. First load: File is read from disk and stored in cache
2. Subsequent loads: Returns reference to cached data (no disk I/O)
3. File modification: Cache is invalidated and file is reloaded on next access
4. Timestamp tracking: Uses file modification time to detect changes

***

## Resource Loading

### Loading Resources

Load resources using the `LoadResource()` method:

```cpp
auto resourceManager = std::make_unique<Subsystems::ResourceManager::ResourceManager>();

// Load a resource
auto& resourceData = resourceManager->LoadResource("path/to/file.ext");
```

**Return Value:**

The method returns a reference to a `std::vector<char>` containing the file's binary data. The data remains valid as long as the resource manager instance exists.

### Resource Data Format

Resources are loaded as binary data (`std::vector<char>`), making it suitable for:

* **Images**: PNG, JPEG, BMP, etc.
* **Audio**: WAV, OGG, MP3, etc.
* **Text Files**: JSON, XML, TXT, etc.
* **Binary Files**: Any binary format

**Example:**

```cpp
// Load an image
auto& imageData = resourceManager->LoadResource("assets/sprite.png");

// Load a configuration file
auto& configData = resourceManager->LoadResource("config/game.cfg");

// Load a model file
auto& modelData = resourceManager->LoadResource("models/player.obj");
```

### File Path Resolution

The Resource Manager uses the file path as provided. It does not resolve relative paths or search multiple directories. Use absolute paths or paths relative to the current working directory.

**Example:**

```cpp
// Absolute path
auto& data = resourceManager->LoadResource("/absolute/path/to/file.png");

// Relative path (relative to current working directory)
auto& data = resourceManager->LoadResource("assets/textures/ship.png");

// Relative path with subdirectory
auto& data = resourceManager->LoadResource("assets/sprites/enemies/monster.png");
```

***

## Caching Mechanism

### Automatic Caching

Resources are automatically cached when loaded:

```cpp
auto resourceManager = std::make_unique<Subsystems::ResourceManager::ResourceManager>();

// First load - reads from disk
auto& firstLoad = resourceManager->LoadResource("assets/sprite.png");

// Second load - returns cached data (no disk I/O)
auto& secondLoad = resourceManager->LoadResource("assets/sprite.png");

// Both references point to the same cached data
assert(&firstLoad == &secondLoad);
```

### Cache Invalidation

The cache is automatically invalidated when a file is modified:

```cpp
auto resourceManager = std::make_unique<Subsystems::ResourceManager::ResourceManager>();

// Load resource (cached)
auto& originalData = resourceManager->LoadResource("assets/config.txt");

// Modify the file externally (e.g., edit in text editor)

// Next load detects modification and reloads from disk
auto& updatedData = resourceManager->LoadResource("assets/config.txt");

// Updated data contains the new file contents
```

**Cache Invalidation Logic:**

1. When `LoadResource()` is called, it checks if the file exists in cache
2. If cached, it compares the file's modification timestamp with the cached timestamp
3. If timestamps differ, the file has been modified - cache is invalidated
4. File is reloaded from disk and new data is cached

### Timestamp Tracking

The Resource Manager tracks file modification timestamps to detect changes:

* **First Load**: Stores current file modification time
* **Subsequent Loads**: Compares current modification time with cached timestamp
* **Change Detection**: If timestamps differ, file is reloaded

**Note:** The timestamp comparison is done on each `LoadResource()` call, ensuring resources are always up-to-date.

***

## Error Handling

### Exception Types

The Resource Manager throws `InvalidFile` exceptions for various error conditions:

* **File does not exist**: Thrown when the specified file path doesn't exist
* **Cannot open file**: Thrown when file cannot be opened (permissions, etc.)
* **Other file system errors**: Thrown for other file-related errors

### Exception Handling

Handle exceptions when loading resources:

```cpp
#include "Exception/Subsystems/ResourceManager/InvalidFile.hpp"

try {
    auto& resourceData = resourceManager->LoadResource("assets/missing.png");
    // Use resource data
} catch (const Exception::Subsystems::ResourceManager::InvalidFile& e) {
    std::cerr << "Failed to load resource: " << e.what() << std::endl;
    // Handle error (e.g., use default resource, show error message)
}
```

### InvalidFile Exception

The `InvalidFile` exception is thrown for file-related errors:

```cpp
class InvalidFile : public GenericError {
    // Exception details available via what()
};
```

**Common Error Messages:**

* `"File does not exist: path/to/file"`
* `"Could not open file: path/to/file"`

### Error Prevention

To avoid exceptions, check if files exist before loading:

```cpp
#include <filesystem>

std::string filePath = "assets/sprite.png";

if (std::filesystem::exists(filePath)) {
    try {
        auto& resourceData = resourceManager->LoadResource(filePath);
        // Use resource data
    } catch (const Exception::Subsystems::ResourceManager::InvalidFile& e) {
        // Handle error
    }
} else {
    std::cerr << "File not found: " << filePath << std::endl;
}
```

***

## Advanced Features

### Memory Management

Resources are stored in memory as long as the Resource Manager instance exists:

```cpp
auto resourceManager = std::make_unique<Subsystems::ResourceManager::ResourceManager>();

// Load resource (cached in memory)
auto& data = resourceManager->LoadResource("large_file.bin");

// Resource remains in memory until Resource Manager is destroyed
// Multiple calls to LoadResource() return references to the same data
```

**Memory Considerations:**

* Resources stay in memory until Resource Manager is destroyed
* Large resources will consume significant memory
* Consider unloading or limiting cache size for very large files

### Thread Safety

The Resource Manager is not thread-safe. Use appropriate synchronization if accessing from multiple threads:

```cpp
#include <mutex>

std::mutex resourceMutex;

// Thread-safe resource loading
std::vector<char>* LoadResourceThreadSafe(const std::string& filePath) {
    std::lock_guard<std::mutex> lock(resourceMutex);
    return &resourceManager->LoadResource(filePath);
}
```

### Resource Types

The Resource Manager works with any binary file format:

**Supported Use Cases:**

* **Images**: PNG, JPEG, BMP, GIF, TGA, etc.
* **Audio**: WAV, OGG, MP3, FLAC, etc.
* **Text**: JSON, XML, TXT, CSV, etc.
* **Models**: OBJ, GLTF, FBX, etc.
* **Fonts**: TTF, OTF, etc.
* **Any Binary Format**: The manager is format-agnostic

***

## Examples

### Complete Resource Loading Example

```cpp
#include "Subsystems/ResourceManager/IResourceManager.hpp"
#include "Exception/Subsystems/ResourceManager/InvalidFile.hpp"
#include <iostream>
#include <vector>
#include <string>

class AssetLoader {
public:
    AssetLoader(Subsystems::ResourceManager::IResourceManager* resourceManager)
        : _resourceManager(resourceManager) {}

    std::vector<char>* LoadTexture(const std::string& path) {
        try {
            return &_resourceManager->LoadResource(path);
        } catch (const Exception::Subsystems::ResourceManager::InvalidFile& e) {
            std::cerr << "Failed to load texture: " << e.what() << std::endl;
            return nullptr;
        }
    }

    std::vector<char>* LoadSound(const std::string& path) {
        try {
            return &_resourceManager->LoadResource(path);
        } catch (const Exception::Subsystems::ResourceManager::InvalidFile& e) {
            std::cerr << "Failed to load sound: " << e.what() << std::endl;
            return nullptr;
        }
    }

    std::vector<char>* LoadConfig(const std::string& path) {
        try {
            return &_resourceManager->LoadResource(path);
        } catch (const Exception::Subsystems::ResourceManager::InvalidFile& e) {
            std::cerr << "Failed to load config: " << e.what() << std::endl;
            return nullptr;
        }
    }

private:
    Subsystems::ResourceManager::IResourceManager* _resourceManager;
};

// Usage
int main() {
    auto resourceManager = std::make_unique<Subsystems::ResourceManager::ResourceManager>();
    AssetLoader loader(resourceManager.get());

    // Load textures
    auto playerTexture = loader.LoadTexture("assets/textures/player.png");
    auto enemyTexture = loader.LoadTexture("assets/textures/enemy.png");

    // Load sounds
    auto shootSound = loader.LoadSound("assets/sounds/shoot.wav");
    auto explosionSound = loader.LoadSound("assets/sounds/explosion.wav");

    // Load configuration
    auto configData = loader.LoadConfig("config/game.json");

    // Use resources...
    if (playerTexture) {
        std::cout << "Player texture loaded: " << playerTexture->size() << " bytes" << std::endl;
    }

    return 0;
}
```

### Resource Loading with Error Recovery

```cpp
#include "Subsystems/ResourceManager/IResourceManager.hpp"
#include "Exception/Subsystems/ResourceManager/InvalidFile.hpp"
#include <filesystem>
#include <string>

class SafeResourceLoader {
public:
    SafeResourceLoader(Subsystems::ResourceManager::IResourceManager* resourceManager)
        : _resourceManager(resourceManager) {}

    std::vector<char>* LoadWithFallback(const std::string& preferredPath,
                                        const std::string& fallbackPath) {
        // Try preferred path first
        try {
            if (std::filesystem::exists(preferredPath)) {
                return &_resourceManager->LoadResource(preferredPath);
            }
        } catch (const Exception::Subsystems::ResourceManager::InvalidFile& e) {
            std::cerr << "Preferred resource failed: " << e.what() << std::endl;
        }

        // Try fallback path
        try {
            if (std::filesystem::exists(fallbackPath)) {
                std::cout << "Using fallback resource: " << fallbackPath << std::endl;
                return &_resourceManager->LoadResource(fallbackPath);
            }
        } catch (const Exception::Subsystems::ResourceManager::InvalidFile& e) {
            std::cerr << "Fallback resource failed: " << e.what() << std::endl;
        }

        std::cerr << "Both resources failed to load" << std::endl;
        return nullptr;
    }

private:
    Subsystems::ResourceManager::IResourceManager* _resourceManager;
};

// Usage
int main() {
    auto resourceManager = std::make_unique<Subsystems::ResourceManager::ResourceManager>();
    SafeResourceLoader loader(resourceManager.get());

    // Try to load high-res texture, fallback to low-res
    auto texture = loader.LoadWithFallback(
        "assets/textures/player_hd.png",
        "assets/textures/player.png"
    );

    if (texture) {
        // Use texture
    }

    return 0;
}
```

### Batch Resource Loading

```cpp
#include "Subsystems/ResourceManager/IResourceManager.hpp"
#include "Exception/Subsystems/ResourceManager/InvalidFile.hpp"
#include <vector>
#include <string>
#include <map>

class ResourcePreloader {
public:
    ResourcePreloader(Subsystems::ResourceManager::IResourceManager* resourceManager)
        : _resourceManager(resourceManager) {}

    void PreloadResources(const std::vector<std::string>& paths) {
        for (const auto& path : paths) {
            try {
                auto& data = _resourceManager->LoadResource(path);
                _loadedResources[path] = &data;
                std::cout << "Preloaded: " << path << " (" << data.size() << " bytes)" << std::endl;
            } catch (const Exception::Subsystems::ResourceManager::InvalidFile& e) {
                std::cerr << "Failed to preload " << path << ": " << e.what() << std::endl;
            }
        }
    }

    std::vector<char>* GetResource(const std::string& path) {
        auto it = _loadedResources.find(path);
        if (it != _loadedResources.end()) {
            return it->second;
        }
        return nullptr;
    }

private:
    Subsystems::ResourceManager::IResourceManager* _resourceManager;
    std::map<std::string, std::vector<char>*> _loadedResources;
};

// Usage
int main() {
    auto resourceManager = std::make_unique<Subsystems::ResourceManager::ResourceManager>();
    ResourcePreloader preloader(resourceManager.get());

    // Preload all game assets
    std::vector<std::string> assetPaths = {
        "assets/textures/player.png",
        "assets/textures/enemy.png",
        "assets/sounds/shoot.wav",
        "assets/sounds/explosion.wav",
        "assets/music/background.ogg",
    };

    preloader.PreloadResources(assetPaths);

    // Later, retrieve resources (already cached)
    auto playerTexture = preloader.GetResource("assets/textures/player.png");
    if (playerTexture) {
        // Use resource
    }

    return 0;
}
```

### Dynamic Resource Reloading

```cpp
#include "Subsystems/ResourceManager/IResourceManager.hpp"
#include <chrono>
#include <thread>

class HotReloadManager {
public:
    HotReloadManager(Subsystems::ResourceManager::IResourceManager* resourceManager)
        : _resourceManager(resourceManager) {}

    void MonitorResource(const std::string& path,
                         std::function<void(const std::vector<char>&)> onReload) {
        // Load initial resource
        auto& data = _resourceManager->LoadResource(path);
        onReload(data);

        // Poll for changes (simplified example)
        // In a real scenario, you might use file system watchers
        while (true) {
            std::this_thread::sleep_for(std::chrono::seconds(1));

            try {
                // Reload resource (will return cached version if unchanged,
                // or reload if file was modified)
                auto& updatedData = _resourceManager->LoadResource(path);

                // Check if data changed by comparing pointers
                static auto lastData = &data;
                if (&updatedData != lastData) {
                    onReload(updatedData);
                    lastData = &updatedData;
                }
            } catch (const Exception::Subsystems::ResourceManager::InvalidFile& e) {
                std::cerr << "Error reloading resource: " << e.what() << std::endl;
            }
        }
    }

private:
    Subsystems::ResourceManager::IResourceManager* _resourceManager;
};
```

***

## Best Practices

### Resource Paths

* **Use consistent paths**: Establish a convention for asset paths (e.g., `assets/type/name.ext`)
* **Avoid absolute paths**: Use relative paths for portability
* **Validate paths**: Check if files exist before loading if needed
* **Document asset structure**: Document where assets should be placed

### Error Handling

* **Always handle exceptions**: Wrap `LoadResource()` calls in try-catch blocks
* **Provide fallbacks**: Have default resources for critical assets
* **Log errors**: Log file loading errors for debugging
* **Handle missing files gracefully**: Don't crash the application on missing assets

### Memory Management

* **Be aware of cache size**: Large resources consume significant memory
* **Load on demand**: Don't preload all resources if memory is limited
* **Unload unused resources**: Consider cache management strategies for very large projects
* **Monitor memory usage**: Track memory consumption in debug builds

### Performance

* **Leverage caching**: The cache system prevents redundant disk I/O
* **Preload critical resources**: Load essential resources at startup
* **Batch loading**: Load related resources together
* **Use absolute paths**: Reduces path resolution overhead

### File Organization

* **Organize by type**: Group resources by type (textures/, sounds/, data/)
* **Use consistent naming**: Follow a naming convention for files
* **Document structure**: Document the asset directory structure
* **Version control**: Keep assets in version control when appropriate

***

## Troubleshooting

### Common Issues

**File not found errors:**

* Verify file paths: Check that paths are correct (case-sensitive on Linux/macOS)
* Check working directory: Ensure paths are relative to the correct working directory
* Verify file exists: Use `std::filesystem::exists()` to check before loading
* Check permissions: Ensure read permissions on files and directories

**Memory issues:**

* Monitor cache size: Large resources consume memory
* Limit preloading: Don't preload all resources at once
* Consider unloading: Implement cache management for very large projects

**Cache not updating:**

* Check file modification: Ensure files are actually being modified
* Verify timestamp comparison: Cache invalidation relies on file modification times
* Check file system: Some file systems have delayed timestamp updates

**Performance problems:**

* First load is slow: First load reads from disk, subsequent loads use cache
* Too many loads: Reduce redundant `LoadResource()` calls
* Large files: Consider streaming for very large resources

**Thread safety issues:**

* Not thread-safe: Use synchronization primitives for multi-threaded access
* Shared state: Be careful when accessing from multiple threads
* Race conditions: Protect Resource Manager access with mutexes

**Path resolution issues:**

* Use absolute paths: If relative paths fail, try absolute paths
* Check working directory: Verify current working directory
* Path separators: Use platform-appropriate path separators

***

## API Reference

For detailed API documentation, refer to the header files:

* `IResourceManager.hpp`: Main Resource Manager interface
* `ResourceManager.hpp`: Resource Manager implementation
* `InvalidFile.hpp`: Exception class for file errors

***

## Version Information

* **Version**: 1.0.0
* **Build System**: CMake 3.16.0+
* **C++ Standard**: C++20
* **Platform Support**: macOS, Linux, Windows

***

## License

This Resource Manager subsystem is part of the R-Type project (EPITECH, 2025).

***

## Contributing

When contributing to the Resource Manager subsystem:

1. Follow the existing code style
2. Add documentation for new features
3. Update this documentation file
4. Test with various file types and sizes
5. Ensure backward compatibility with the `IResourceManager` interface
6. Add unit tests for file loading and caching

***

*Last Updated: 2025*
