# Adding a Feature: Quick Start Guide

This guide shows the shortest reliable path for adding a feature to `TarkovAddonsRefactored`. It assumes the existing layered and ports-and-adapters architecture described in `ARCHITECTURE.md`.

## 1. Choose the Smallest Integration Level

Before creating files, decide what the feature actually needs.

| Feature type | Typical components |
|---|---|
| Configuration-only or render-only | Feature settings, config adapter, feature query snapshot, bootstrap module, overlay renderer |
| Game-state reader | Settings, gateway port, feature, EFT/Unity gateway adapter, bootstrap module |
| User-triggered game action | Settings, command contract, feature command queue/slot, gateway adapter, `UiActionDispatcher` binding |
| Custom menu page | Query/command contracts, `MenuPorts`, `MenuContext`, page renderer, `PageId`, navigation entry |

Prefer the first applicable row. A feature does not need a custom page when the generic configuration UI can render its controls.

## 2. Keep Dependencies Pointing Inward

Use this dependency direction:

```text
presentation ─┐
adapters ─────┼──> features ──> application ──> foundation
bootstrap ────┘
```

Rules:

- Put business decisions and feature state in `features/<name>`.
- Put EFT, IL2CPP, Unity, Windows, DirectX, file, and hook calls in `adapters`.
- Put object construction and registration in `bootstrap/modules`.
- Put ImGui drawing in `presentation`.
- Do not include adapter or presentation headers from a feature.
- Do not retain raw host objects across callbacks unless an existing adapter abstraction explicitly owns that lifetime.

The examples below use a fictional feature named `Example`.

## 3. Create the Feature Contracts

Create a directory:

```text
src/features/example/
```

### Settings value

Use a plain value type for the settings consumed by the feature:

```cpp
// features/example/ExampleSettings.h
#pragma once

namespace ta::features::example
{
    struct ExampleSettings final
    {
        bool enabled = false;
        float radius = 25.0f;

        friend bool operator==(const ExampleSettings&, const ExampleSettings&) = default;
    };
}
```

Equality allows `SettingsCache` to avoid publishing unchanged values.

### Settings port

```cpp
// features/example/IExampleSettings.h
#pragma once

#include "features/example/ExampleSettings.h"

namespace ta::features::example
{
    class IExampleSettings
    {
    public:
        virtual ~IExampleSettings() = default;
        [[nodiscard]] virtual ExampleSettings read() const = 0;
    };
}
```

### Gateway port

Define only the host operations required by the feature:

```cpp
// features/example/IExampleGateway.h
#pragma once

#include "features/example/ExampleSettings.h"

namespace ta::features::example
{
    class IExampleGateway
    {
    public:
        virtual ~IExampleGateway() = default;
        virtual void game_tick(const ExampleSettings& settings) = 0;
    };
}
```

Avoid exposing IL2CPP classes, Unity objects, Windows handles, or ImGui types through this interface.

### Optional commands and queries

Add a command contract when the UI triggers an operation:

```cpp
// features/example/IExampleCommands.h
#pragma once

#include <cstdint>

namespace ta::features::example
{
    struct ExampleCommand final
    {
        std::uint64_t trace_id = 0;
    };

    class IExampleCommands
    {
    public:
        virtual ~IExampleCommands() = default;
        virtual void submit(ExampleCommand command) = 0;
    };
}
```

Add a query contract when presentation needs a feature-owned snapshot. Return immutable values or `shared_ptr<const T>` rather than mutable references.

## 4. Implement the Feature

Implement only the callbacks the feature needs:

- `IApplicationTick`: configuration and application-owned state.
- `IGameTick`: access mediated through a game gateway.
- `initialize()`: first snapshot/cache initialization.
- `reset_session() noexcept`: clear raid- or session-scoped state.

```cpp
// features/example/ExampleFeature.h
#pragma once

#include "application/contracts/IApplicationTick.h"
#include "application/contracts/IGameTick.h"
#include "features/common/SettingsCache.h"
#include "features/example/IExampleGateway.h"
#include "features/example/IExampleSettings.h"

namespace ta::features::example
{
    class ExampleFeature final : public ta::application::IApplicationTick,
                                 public ta::application::IGameTick
    {
    public:
        ExampleFeature(IExampleGateway& gateway, IExampleSettings& settings) noexcept
            : gateway_(gateway), settings_(settings)
        {
        }

        void initialize();
        void on_application_tick() override;
        void on_game_tick() override;
        void reset_session() noexcept;

    private:
        IExampleGateway& gateway_;
        IExampleSettings& settings_;
        ta::features::SettingsCache<ExampleSettings> settings_cache_;
    };
}
```

```cpp
// features/example/ExampleFeature.cpp
#include "features/example/ExampleFeature.h"

namespace ta::features::example
{
    void ExampleFeature::initialize()
    {
        settings_cache_.refresh(settings_);
    }

    void ExampleFeature::on_application_tick()
    {
        settings_cache_.publish_if_changed(settings_.read());
    }

    void ExampleFeature::on_game_tick()
    {
        const ExampleSettings settings = settings_cache_.current_or_default();
        if (!settings.enabled)
            return;

        gateway_.game_tick(settings);
    }

    void ExampleFeature::reset_session() noexcept
    {
        settings_cache_.clear();
    }
}
```

For commands submitted on the render thread, use an existing concurrency primitive:

- `CommandQueue<T>` when every command must execute.
- `CoalescingCommandSlot<T>` when a newer request replaces an older pending request.

Consume game-changing commands in `on_game_tick()`, not in presentation code.

## 5. Add the Configuration Adapter

Create an adapter that is both a `ConfigOwner` and the feature settings port:

```cpp
// adapters/config/ExampleConfigAdapter.h
#pragma once

#include "application/config/ConfigOwner.h"
#include "application/config/values/BasicValues.h"
#include "application/config/values/NumberValues.h"
#include "features/example/IExampleSettings.h"

namespace ta::adapters::config
{
    class ExampleConfigAdapter final :
        public ta::application::config::ConfigOwner,
        public ta::features::example::IExampleSettings
    {
    public:
        ExampleConfigAdapter();
        [[nodiscard]] ta::features::example::ExampleSettings read() const override;

    private:
        ta::application::config::RegisteredConfigValue<
            ta::application::config::CheckboxValue> enabled_{*this, "enabled", false, "Enabled"};

        ta::application::config::RegisteredConfigValue<
            ta::application::config::FloatSliderValue> radius_{*this, "radius", 25.0f, 1.0f, 100.0f, "Radius"};
    };
}
```

```cpp
// adapters/config/ExampleConfigAdapter.cpp
#include "adapters/config/ExampleConfigAdapter.h"

namespace ta::adapters::config
{
    ExampleConfigAdapter::ExampleConfigAdapter()
        : ta::application::config::ConfigOwner(
              "example", "Example", ta::application::config::ConfigCategory::Exploit)
    {
    }

    ta::features::example::ExampleSettings ExampleConfigAdapter::read() const
    {
        return {
            enabled_->get_value(),
            radius_->get_value()
        };
    }
}
```

Choose the appropriate `ConfigCategory` (`Visuals`, `Exploit`, `QuestList`, `ItemList`, `Config`, or conditional `Aimbot`). The generic config pages discover registered owners automatically, so a basic settings panel normally requires no custom ImGui code.

Add new display strings to every file in `src/locales/`. At minimum, ensure `en.json` contains the canonical labels. Keep locale JSON keys identical across languages.

## 6. Implement the Concrete Gateway

Place game-specific code under `adapters/eft`, `adapters/unity`, or another matching adapter area:

```cpp
// adapters/eft/example/EftExampleGateway.h
#pragma once

#include "adapters/eft/runtime/EftGameContext.h"
#include "features/example/IExampleGateway.h"

namespace ta::adapters::eft::example
{
    class EftExampleGateway final : public ta::features::example::IExampleGateway
    {
    public:
        explicit EftExampleGateway(ta::adapters::eft::runtime::EftGameContext& context) noexcept
            : context_(context)
        {
        }

        void game_tick(const ta::features::example::ExampleSettings& settings) override;

    private:
        ta::adapters::eft::runtime::EftGameContext& context_;
    };
}
```

```cpp
// adapters/eft/example/EftExampleGateway.cpp
#include "adapters/eft/example/EftExampleGateway.h"

namespace ta::adapters::eft::example
{
    void EftExampleGateway::game_tick(const ta::features::example::ExampleSettings& settings)
    {
        const auto snapshot = context_.snapshot();
        if (!snapshot.has_player())
            return;

        // Resolve and mutate EFT/IL2CPP/Unity state here.
        // Keep host-specific failure handling inside the adapter.
    }
}
```

Follow existing wrappers and services before adding raw offset or reflection logic. Gateway methods should fail safely when the game context is unavailable or the raid is changing state.

## 7. Add a Bootstrap Module

The module is the assembly boundary for settings, gateway, feature, lifecycle ports, and UI action bindings.

```cpp
// bootstrap/modules/ExampleModule.h
#pragma once

#include "adapters/config/ExampleConfigAdapter.h"
#include "adapters/eft/example/EftExampleGateway.h"
#include "bootstrap/modules/ModulePorts.h"
#include "features/example/ExampleFeature.h"

namespace ta::bootstrap::modules
{
    class ExampleModule final
    {
    public:
        explicit ExampleModule(ta::adapters::eft::runtime::EftGameContext& context);

        [[nodiscard]] const ModulePorts& ports() const noexcept { return ports_; }

    private:
        ta::adapters::config::ExampleConfigAdapter settings_;
        ta::adapters::eft::example::EftExampleGateway gateway_;
        ta::features::example::ExampleFeature feature_;
        ModulePorts ports_;
    };
}
```

```cpp
// bootstrap/modules/ExampleModule.cpp
#include "bootstrap/modules/ExampleModule.h"

namespace ta::bootstrap::modules
{
    ExampleModule::ExampleModule(ta::adapters::eft::runtime::EftGameContext& context)
        : gateway_(context),
          feature_(gateway_, settings_),
          ports_(ModulePorts::bind(
              feature_,
              &settings_,
              "runtime.application.tick.example",
              "runtime.game.tick.example",
              "runtime.raid.reset.example"))
    {
    }
}
```

Member declaration order matters because C++ constructs members in declaration order. Declare dependencies before the objects that reference them.

`ModulePorts::bind` automatically detects the implemented lifecycle capabilities. Pass `nullptr` instead of `&settings_` when the module has no configuration owner.

Use `ModuleResetScope::Session` only for state that must survive raid transitions. The default raid scope is appropriate for most game features.

## 8. Register the Module in `ApplicationRuntime`

Update `bootstrap/ApplicationRuntime.h`:

```cpp
#include "bootstrap/modules/ExampleModule.h"
```

Declare the module after the shared services it consumes:

```cpp
ta::bootstrap::modules::ExampleModule example_module_;
```

Update the constructor initializer list in `ApplicationRuntime.cpp`:

```cpp
example_module_(game_context_),
```

Register its ports:

```cpp
register_module(example_module_.ports());
```

Registration provides:

- Initialization.
- Application tick scheduling.
- Game tick scheduling.
- Configuration ownership.
- Raid/session reset participation.

Do not call the feature directly from `ApplicationRuntime` unless it exposes an explicit query or diagnostics surface that the runtime must aggregate.

## 9. Bind UI Actions When Needed

For a one-shot operation, bind an action key in the module constructor using `UiActionDispatcher`, as existing player, world, and item modules do:

```cpp
actions.bind("example.execute", [this](const ta::application::CommandContext& command)
{
    feature_.submit({command.trace_id});
});
```

The config UI can emit the same action key through an action/button config value. Keep action keys stable because they are the contract between configuration presentation and the module.

Record command execution with `foundation/diagnostics/ExecutionPath.h` when the operation crosses queues or callbacks. Mark replaced or abandoned commands as failed so diagnostics do not leave traces permanently pending.

## 10. Expose Queries to Presentation Only When Required

A normal configuration panel needs no `MenuPorts` change. Add a presentation port only for feature-specific data or controls.

When required:

1. Add the query/command interfaces to `presentation/MenuPorts.h`.
2. Return the concrete feature interfaces from the bootstrap module.
3. Add them to `ApplicationRuntime::menu_ports()`.
4. Transform feature snapshots into render-ready data in `MenuContext.cpp` or a dedicated builder.
5. Draw them in a page or overlay under `presentation`.

Do not pass mutable feature implementations to ImGui code. Presentation should receive interfaces that expose snapshots and command submission only.

### Custom page checklist

For a new top-level page, update:

- `presentation/pages/PageId.h`.
- The navigation array in `presentation/MenuRenderer.cpp`.
- The page dispatch switch in `MenuRenderer.cpp`.
- `MenuContext` and `UiState` only when the page needs persistent UI state.
- `ta_presentation.vcxproj` with the new source and header files.
- Locale files with the page title and description.

### Overlay checklist

For an overlay:

- Publish an immutable feature snapshot.
- Convert it into draw data outside the low-level renderer.
- Keep ImGui types inside `presentation`.
- Draw from the Present callback without accessing game objects directly.

## 11. Add Diagnostics

Small features can initially rely on execution-path and loop diagnostics. Add feature counters when operators need to distinguish requested, consumed, succeeded, failed, or dropped work.

Typical flow:

1. Define a thread-safe diagnostics collector in `features/<name>`.
2. Expose a snapshot through the bootstrap module.
3. Register an aggregator in `ApplicationRuntime::register_diagnostics()`.
4. Extend `ta::ui::DiagnosticsSnapshot` and the diagnostics page when the metric should be visible.

Diagnostics reads must be cheap and must not mutate feature state.

## 12. Update Visual Studio Project Files

This repository explicitly lists source files in `.vcxproj` files. Add each file to the project that owns its layer:

| File location | Project |
|---|---|
| `features/example/*` | `src/ta_features.vcxproj` |
| `adapters/config/*`, `adapters/eft/example/*` | `src/ta_adapters.vcxproj` |
| `presentation/*` | `src/ta_presentation.vcxproj` |
| `bootstrap/modules/*` | `src/TarkovAddonsRefactored.vcxproj` |

Use `<ClCompile Include="..." />` for `.cpp` files and `<ClInclude Include="..." />` for headers. Conditional features must use the same flavor condition in all affected projects and in the composition root.

## 13. Build and Validate

Build both supported flavors unless the feature is deliberately flavor-specific:

```powershell
.\build.ps1 -Configuration Release -Flavor NoAimbot
.\build.ps1 -Configuration Release -Flavor WithAimbot
```

Run this validation checklist:

- The feature project does not include adapter, presentation, Windows, Unity, EFT, IL2CPP, DirectX, or ImGui headers.
- The gateway handles missing context and invalid host objects safely.
- Game mutations execute on `IGameTick` or another established host callback.
- Render code consumes snapshots and never mutates game state directly.
- `reset_session() noexcept` clears pending commands and raid-owned snapshots.
- All submitted commands are eventually consumed, superseded, or marked failed.
- Configuration identifiers and action keys are unique and stable.
- New source files are listed in the correct `.vcxproj`.
- New UI strings exist in all locale JSON files.
- Startup and shutdown still work when the feature is disabled.
- Both build flavors compile and package successfully.

## 14. Recommended Reference Modules

Use an existing feature as the nearest template:

| Requirement | Reference |
|---|---|
| Settings and application snapshot only | `WatermarkFeature` / `WatermarkModule` |
| Read-only game data and overlay | `EspFeature` / `EspModule` |
| Coalesced user actions | `WorldFeature` / `WorldModule` |
| Rich query and command surface | `ItemFeature` / `ItemModule` |
| Custom page workflow | Quests or Items presentation pages |
| Conditional build feature | Aimbot module and `build/Flavor.props` |

Copy the structure, then rename and remove capabilities the new feature does not need. Avoid copying host-specific implementation details without confirming their lifetime and callback assumptions.
