# Maintaining the Plugin API

This document is for developers who need to update, extend, or maintain the `dragonfly-plugin` API. This is **not** for plugin _users_; that documentation is in the main `README.md`.

## The Golden Rule: Do Not Edit Generated Files

This entire API is code-generated from a "Single Source of Truth." **You must not edit the generated Rust files by hand.** Any manual changes will be overwritten.

The _only_ files you will ever edit manually are:

1.  The `.proto` files (Phase 1).
2.  The `xtask` generator code (Phase 3's _generator_).
3.  The `dragonfly-plugin-macros` crate code.
4.  The `src/*` code in case of BC changes or etc.

## The 3-Phase Generation Pipeline

Our architecture is a 3-phase pipeline. Understanding this flow is critical to maintaining the API.

---

### Phase 1: The Protocol (Source of Truth)

- **What it is:** The `.proto` files that define all our gRPC services, messages, and events.
- **Location:** `../proto` directory.
- **How to change:** This is the **only place** you should start a change. To add a new event (e.g., `PlayerSleepEvent`), you add it to the `EventEnvelope` message in the `.proto` file.

---

### Phase 2: The Raw Bindings (Intermediate)

- **What it is:** The "raw" Rust code (structs, enums, and gRPC clients) generated directly from the `.proto` files. This code is often ugly, un-idiomatic, and not user-friendly.
- **How it's made:** This code is generated by `buf` which uses `prost` (via the makefile).
- **How to update:** When you have made changes to the proto buf files run the buf tool via `make proto`
- **Warning:** **NEVER EDIT THESE FILES BY HAND.**

---

### Phase 3: The Friendly API (The `xtask` Generator)

- **What it is:** This is the **public-facing, idiomatic Rust API** that our users love. It includes:
  - The `PluginEventHandler` trait.
  - The `Server` struct with its friendly helper methods (e.g., `server.send_chat(...)`).
  - The `EventContext` struct and its helpers (`.cancel()`, `.set_message()`).
  - The `types::EventType` enum.
- **How it's made:** The `xtask` crate is a custom Rust program that **parses the output of Phase 2** and generates this beautiful API.
- **How to update:** You run the `xtask` crate from the terminal.
- **Warning:** **NEVER EDIT THESE FILES BY HAND.**

---

## How to Add a New Event

This is the most common maintenance task. Here is the complete workflow.

**Goal:** Add a new `PlayerSleepEvent`.

1.  **Phase 1: Edit the Protocol**
    - Open the relevant `.proto` file (e.g., `events.proto`).
    - Add the `PlayerSleepEvent` message.
    - Add `PlayerSleepEvent player_sleep = 15;` (or the next available ID) to your main `EventEnvelope`'s `payload` oneof.

2.  **Phase 2: Generate the Raw Bindings**
    - Run `make proto` to use the buf tool to generate all the needed `generated/*` files.

3.  **Phase 3: Generate the Friendly API**
    - Now that the raw types exist, we can generate the friendly API for them.
    - `cd` into the `xtask` directory.
    - Run `cargo run`.
    - The `xtask` generator will see the new `PlayerSleep` variant and automatically:
      - Add `async fn on_player_sleep(...)` to the `PluginEventHandler` trait.
      - Add the `case PlayerSleep` arm to the `dispatch_event` function.

4.  **Review and Commit**
    - You are done. Review the changes in `git`.
    - You should see changes in:
      1.  The `.proto` file you edited.
      2.  The Phase 2 raw bindings file.
      3.  The Phase 3 friendly API files (e.g., `event_handler.rs`, `types.rs`).
    - Commit all of them.

## The `Handler` Proc-Macro

- **Crate:** `dragonfly-plugin-macros`
- **Purpose:** Provides `#[derive(Handler)]` and its helper attribute `#[subscriptions(...)]`.
- **How it works:** This macro generates the `impl PluginSubscriptions` block for the user, turning their `#[subscriptions(Chat, PlayerSleep)]` list into a `Vec<types::EventType>`.
- **Maintenance:** You do not need to touch this crate during the normal "add an event" workflow. The macro doesn't need to know _what_ events exist; it just converts the identifiers the user provides (e.g., `PlayerSleep`) into the corresponding enum variant (`types::EventType::PlayerSleep`). If the user makes a typo, the Rust compiler throws the error for us, which is the intended design.
