> ## Documentation Index
> Fetch the complete documentation index at: https://docs.nameplatebuilder.frotty27.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Migration Guide

> Upgrade your mod to the latest NameplateBuilder API version.

<Info>This documentation is written for **NameplateBuilder >= v4.260326.7** with **API >= v2.2.0**.</Info>

Select your current API version below to see what needs to change.

<Tabs>
  <Tab title="From API 1.0.0 to 2.1.0">
    ## What Changed

    API 2.0.0 has two changes:

    1. **All method names were renamed** for clarity (required - your code won't compile until you rename them)
    2. **Resolvers were added** as a new way to provide segment text (optional but recommended - your existing tick systems still work)

    ## Step 1: Update Dependencies

    Replace the API jar in your `libs/` folder and update both files:

    **`build.gradle`:**

    ```groovy theme={null}
    dependencies {
        compileOnly files('libs/NameplateBuilder-API-2.2.0.jar')
    }
    ```

    **`manifest.json`:**

    ```json theme={null}
    {
      "Dependencies": {
        "Frotty27:NameplateBuilder": ">=4.260326.7"
      }
    }
    ```

    ## Step 2: Rename Methods

    Find and replace these five method names across your code. The behavior is identical - only the names changed.

    | Find                             | Replace with                   |
    | :------------------------------- | :----------------------------- |
    | `NameplateAPI.describe(`         | `NameplateAPI.define(`         |
    | `NameplateAPI.describeVariants(` | `NameplateAPI.defineVariants(` |
    | `NameplateAPI.undescribe(`       | `NameplateAPI.undefine(`       |
    | `NameplateAPI.register(`         | `NameplateAPI.setText(`        |
    | `NameplateAPI.remove(`           | `NameplateAPI.clearText(`      |

    After this step, your code compiles and works exactly as before. You're done with the required migration.

    **`NameplateData` methods are unchanged.** If you use `data.setText()`, `data.getText()`, etc. directly on the component, nothing needs to change.

    ## Step 3: Switch to Resolvers (Recommended)

    This step is optional. Your renamed `setText()` / `clearText()` code works fine. But if your segment's value comes from an **ECS component on the entity** (health, stats, faction, etc.), resolvers are simpler and more efficient.

    **The idea:** Instead of writing a tick system that reads a component and calls `setText()` every tick, you give NameplateBuilder a function that does the reading. NameplateBuilder calls it automatically - no tick system needed.

    ### Before (1.0.0 pattern)

    You had to write a tick system class, register it, handle spawn initialization with `CommandBuffer`, and update every tick:

    ```java theme={null}
    // In setup():
    NameplateAPI.define(this, "health", "Health",
            SegmentTarget.ALL, "67/69");

    getEntityStoreRegistry().registerSystem(
        new HealthNameplateSystem(NameplateAPI.getComponentType()));
    ```

    ```java theme={null}
    // Separate tick system class:
    final class HealthNameplateSystem extends EntityTickingSystem<EntityStore> {
        // ... constructor, getQuery(), getGroup() ...

        @Override
        public void tick(float deltaTime, int index, ArchetypeChunk<EntityStore> chunk,
                         Store<EntityStore> store, CommandBuffer<EntityStore> commandBuffer) {
            // Check if entity has stats
            EntityStatMap stats = chunk.getComponent(index, statMapType);
            if (stats == null) return;

            Ref<EntityStore> entityRef = chunk.getReferenceTo(index);

            // Initialize if needed (can't use setText here - store is locked)
            if (store.getComponent(entityRef, nameplateDataType) == null) {
                NameplateData data = new NameplateData();
                data.setText("health", computeHealth(stats));
                commandBuffer.putComponent(entityRef, nameplateDataType, data);
                return;
            }

            // Update every tick
            NameplateData data = chunk.getComponent(index, nameplateDataType);
            if (data != null) {
                data.setText("health", computeHealth(stats));
            }
        }
    }
    ```

    ### After (2.0.0 with resolver)

    Everything is in `setup()`. No tick system class needed:

    ```java theme={null}
    @Override
    protected void setup() {
        NameplateAPI.define(this, "health", "Health",
                SegmentTarget.ALL, "67/69")
            .requires(EntityStatMap.getComponentType())
            .resolver((store, entityRef, variantIndex) -> {
                EntityStatMap stats = store.getComponent(entityRef, statMapType);
                if (stats == null) return null;
                int current = Math.round(stats.get(health).get());
                int max = Math.round(stats.get(health).getMax());
                return current + "/" + max;
            });
    }
    ```

    **What you can delete:** The entire tick system class (`HealthNameplateSystem`), its registration in `setup()`, and the `CommandBuffer` initialization logic. The resolver replaces all of it.

    You can also add `.cacheTicks(100)` for data that rarely changes (faction, level, tier) to avoid recomputing every tick. See [Resolvers](/modding/resolvers) for the full guide.

    ### When to Keep Using `setText()`

    Keep your existing `setText()` / `clearText()` code if your segment's value **doesn't come from an ECS component**. For example:

    * A bounty stored in your mod's config file or database
    * A title assigned by an admin via a chat command
    * A buff applied through an event, not stored as a component

    In these cases there's no component for a resolver to read, so `setText()` is the right approach.

    **Rule of thumb:** If you're reading a component inside a tick system and calling `setText()` with the result, that's a resolver. If you're reacting to an event or command, keep `setText()`.

    ## Summary

    | What                               | Required?   | Action                                                                         |
    | :--------------------------------- | :---------- | :----------------------------------------------------------------------------- |
    | API jar                            | Yes         | Replace with `NameplateBuilder-API-2.2.0.jar`                                  |
    | Manifest version                   | Yes         | Change to `">=4.260326.7"`                                                     |
    | Rename 5 methods                   | Yes         | `describe` -> `define`, `register` -> `setText`, `remove` -> `clearText`, etc. |
    | Switch tick systems to resolvers   | Recommended | Replace component-reading tick systems with `.resolver()`                      |
    | Keep `setText()` for external data | Keep as-is  | No change needed for event/command/database-driven segments                    |
    | `NameplateData` methods            | No change   | `data.setText()`, `data.getText()`, etc. are identical                         |
  </Tab>

  <Tab title="From API 2.0.0 to 2.1.0">
    ## What Changed

    API 2.1.0 is a backward-compatible addition. Existing 2.0.0 code compiles and runs without changes. Two new methods were added to `SegmentBuilder`:

    1. **`enabledByDefault()`** - marks a segment as enabled by default on both chains for new players
    2. **`enabledByDefault(SegmentTarget target)`** - marks a segment as enabled by default on specific chain(s) for new players

    Each mod can mark at most 3 segments as `enabledByDefault`.

    ## Step 1: Update Dependencies

    Replace the API jar in your `libs/` folder and update both files:

    **`build.gradle`:**

    ```groovy theme={null}
    dependencies {
        compileOnly files('libs/NameplateBuilder-API-2.2.0.jar')
    }
    ```

    **`manifest.json`:**

    ```json theme={null}
    {
      "Dependencies": {
        "Frotty27:NameplateBuilder": ">=4.260326.7"
      }
    }
    ```

    ## Step 2: Use `enabledByDefault()` (Optional)

    If you want your segment to appear in new players' chains automatically, chain `enabledByDefault()` onto your `define()` call:

    ```java theme={null}
    NameplateAPI.define(this, "health", "Health",
            SegmentTarget.ALL, "67/69")
        .enabledByDefault()
        .resolver((store, entityRef, variantIndex) -> {
            // ...
        });
    ```

    You can also target a specific chain:

    ```java theme={null}
    NameplateAPI.define(this, "faction", "Faction",
            SegmentTarget.NPCS, "<Undead>")
        .enabledByDefault(SegmentTarget.NPCS)
        .resolver((store, entityRef, variantIndex) -> {
            // ...
        });
    ```

    See [Advanced - Default Segments](/modding/advanced#default-segments) for full details.

    ## Summary

    | What                 | Required? | Action                                             |
    | :------------------- | :-------- | :------------------------------------------------- |
    | API jar              | Yes       | Replace with `NameplateBuilder-API-2.2.0.jar`      |
    | Manifest version     | Yes       | Change to `">=4.260326.7"`                         |
    | `enabledByDefault()` | Optional  | Chain onto `define()` for up to 3 segments per mod |
  </Tab>

  <Tab title="From API 2.1.0 to 2.2.0">
    ## What Changed

    API 2.2.0 is a backward-compatible addition. Existing 2.1.0 code compiles and runs without changes. One new method was added to `SegmentBuilder`:

    1. **`replaces(String segmentId)`** - when your segment has a value for an entity, the target built-in segment is hidden for that entity

    This only targets NameplateBuilder's built-in segments: `entity-name`, `player-name`, `health`, `stamina`, `mana`.

    ## Step 1: Update Dependencies

    Replace the API jar in your `libs/` folder and update both files:

    **`build.gradle`:**

    ```groovy theme={null}
    dependencies {
        compileOnly files('libs/NameplateBuilder-API-2.2.0.jar')
    }
    ```

    **`manifest.json`:**

    ```json theme={null}
    {
      "Dependencies": {
        "Frotty27:NameplateBuilder": ">=4.260326.7"
      }
    }
    ```

    ## Step 2: Use `replaces()` (Optional)

    If your segment provides a context-specific version of a built-in segment (like a pet name replacing the entity name), chain `replaces()` onto your `define()` call:

    ```java theme={null}
    NameplateAPI.define(this, "pet-name", "Pet Name",
            SegmentTarget.NPCS, "Fluffy")
        .replaces("entity-name")
        .enabledByDefault(SegmentTarget.NPCS)
        .resolver((store, entityRef, variantIndex) -> {
            var name = store.getComponent(entityRef, petNameType);
            return name != null ? name.getName() : null;
        });
    ```

    When the resolver returns a value, `entity-name` is hidden for that entity. When it returns `null`, `entity-name` shows normally. Players don't need to change anything in their chain.

    See [Advanced - Replacing Built-in Segments](/modding/advanced#replacing-built-in-segments) for full details.

    ## Summary

    | What             | Required? | Action                                                         |
    | :--------------- | :-------- | :------------------------------------------------------------- |
    | API jar          | Yes       | Replace with `NameplateBuilder-API-2.2.0.jar`                  |
    | Manifest version | Yes       | Change to `">=4.260326.7"`                                     |
    | `replaces()`     | Optional  | Chain onto `define()` to replace a built-in segment per-entity |
  </Tab>

  <Tab title="Already on 2.2.0">
    ## You're up to date

    You're on the latest API version. No migration needed.

    * **[Quick Start](/modding/quick-start)** - Setting up a new integration
    * **[API Reference](/reference/api)** - Full method tables
  </Tab>
</Tabs>
