> ## 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.

# Manual Text

> Push text to entities directly for event-driven or external data.

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

Most segments should use [resolvers](/modding/resolvers). This page covers the alternative: pushing text to entities yourself using `setText()` and `clearText()`.

## When Do You Need This?

You need manual text when your segment's value **doesn't come from an ECS component on the entity**. Some examples:

* An admin runs `/setbounty goblin 500` - the bounty is stored in your mod's config, not as a component on the entity
* A player earns a title from an achievement system - the title lives in a database, not on the entity
* A buff is applied through a chat command - there's no `BuffComponent` to read from
* You need to seed initial nameplate data on NPCs when they first spawn

If the data **does** live on the entity as a component (health, stats, faction, etc.), use a [resolver](/modding/resolvers) instead - it's simpler and you don't need to write any tick systems.

## The Two Methods

### `setText()` - Set or Update

```java theme={null}
NameplateAPI.setText(store, entityRef, "bounty", "$500");
```

This sets the text for your segment on a specific entity. If the entity doesn't have a `NameplateData` component yet, one is created automatically. If the segment already has text on this entity, it's overwritten.

You can call this from anywhere you have access to the `Store` and a `Ref` - event handlers, command handlers, systems, etc.

### `clearText()` - Remove

```java theme={null}
NameplateAPI.clearText(store, entityRef, "bounty");
```

This removes your segment's text from the entity. If the entity has no other segments left, the entire `NameplateData` component is removed automatically.

## Example: Admin Command Sets a Bounty

Here's a concrete scenario. Your mod has a `/setbounty` command. When an admin uses it, you want to show the bounty above the targeted entity:

```java theme={null}
// In your command handler:
public void onSetBounty(Store<EntityStore> store, Ref<EntityStore> targetEntity,
                        int amount) {
    // Tell NameplateBuilder to show this text on the entity
    NameplateAPI.setText(store, targetEntity, "bounty", "$" + amount);
}

public void onClearBounty(Store<EntityStore> store, Ref<EntityStore> targetEntity) {
    // Remove the bounty text from the entity
    NameplateAPI.clearText(store, targetEntity, "bounty");
}
```

You still need to call `define()` in `setup()` so the segment appears in the player UI:

```java theme={null}
@Override
protected void setup() {
    // Register the segment for the UI - no resolver needed
    NameplateAPI.define(this, "bounty", "Bounty",
            SegmentTarget.NPCS, "$500");
}
```

## The Tick System Restriction

There's one important restriction: **`setText()` cannot be called inside an `EntityTickingSystem`** if the entity doesn't already have a `NameplateData` component. This is because `setText()` needs to add the component to the entity, and Hytale locks the store for structural changes during tick processing.

If you try, you'll get:

```
IllegalStateException: Store is currently processing
```

This only matters when you need to **initialize** nameplate data on entities that don't have it yet (like newly spawned NPCs). Once an entity has the component, updating it from a tick system is fine.

## Tick System Pattern: NPC Spawn Initialization

If you need to give NPCs nameplate data when they first appear in the world, you need a tick system that uses `CommandBuffer` instead of `setText()`:

```java theme={null}
final class MyNpcNameplateSystem extends EntityTickingSystem<EntityStore> {

    private final ComponentType<EntityStore, NPCEntity> npcType;
    private final ComponentType<EntityStore, NameplateData> nameplateDataType;

    MyNpcNameplateSystem(ComponentType<EntityStore, NameplateData> nameplateDataType) {
        this.npcType = NPCEntity.getComponentType();
        this.nameplateDataType = nameplateDataType;
    }

    @Override
    public Archetype<EntityStore> getQuery() {
        // Only tick on entities that have an NPCEntity component
        return Archetype.of(npcType);
    }

    @Override
    public SystemGroup<EntityStore> getGroup() {
        return EntityTrackerSystems.QUEUE_UPDATE_GROUP;
    }

    @Override
    public void tick(float deltaTime, int index, ArchetypeChunk<EntityStore> chunk,
                     Store<EntityStore> store, CommandBuffer<EntityStore> commandBuffer) {

        // Check if this is the right type of NPC
        NPCEntity npc = chunk.getComponent(index, npcType);
        if (npc == null || !"Kweebec".equals(npc.getRoleName())) {
            return;
        }

        Ref<EntityStore> entityRef = chunk.getReferenceTo(index);

        // Skip if this entity already has nameplate data (already initialized)
        if (store.getComponent(entityRef, nameplateDataType) != null) {
            return;
        }

        // First time seeing this entity - create the component manually
        NameplateData data = new NameplateData();
        data.setText("faction", "<Forest>");
        data.setText("level", "Lv. 10");

        // Use commandBuffer.putComponent() instead of store.addComponent()
        // The CommandBuffer queues the change and applies it after the tick finishes
        commandBuffer.putComponent(entityRef, nameplateDataType, data);
    }
}
```

**Why `CommandBuffer`?** Inside a tick system, the entity store is locked. You can't add or remove components directly. `CommandBuffer` queues the change and applies it safely after the system finishes processing.

**Why `putComponent()` instead of `addComponent()`?** `addComponent()` throws an error if the component already exists. `putComponent()` adds it if missing or replaces it if it exists - safer when multiple systems or mods might initialize the same entity.

Register the system in your plugin's `setup()`:

```java theme={null}
@Override
protected void setup() {
    NameplateAPI.define(this, "faction", "Faction",
            SegmentTarget.NPCS, "<Forest>");
    NameplateAPI.define(this, "level", "Level",
            SegmentTarget.ALL, "Lv. 10");

    ComponentType<EntityStore, NameplateData> nameplateDataType =
        NameplateAPI.getComponentType();

    getEntityStoreRegistry().registerSystem(new MyNpcNameplateSystem(nameplateDataType));
}
```

## Updating Text Every Tick

Once an entity already has a `NameplateData` component (from initialization or any other source), you can safely update it from a tick system. No `CommandBuffer` needed - you're modifying existing data, not adding a new component:

```java theme={null}
@Override
public void tick(float deltaTime, int index, ArchetypeChunk<EntityStore> chunk,
                 Store<EntityStore> store, CommandBuffer<EntityStore> commandBuffer) {

    NameplateData data = chunk.getComponent(index, nameplateDataType);
    if (data == null) return; // entity doesn't have nameplate data yet

    // This is safe - it's just a HashMap.put() internally
    data.setText("timer", formatTimer(computeTimeLeft()));
}
```

## Working with `NameplateData` Directly

If you need lower-level access to the nameplate component, you can read and write it directly:

```java theme={null}
ComponentType<EntityStore, NameplateData> type = NameplateAPI.getComponentType();
NameplateData data = store.getComponent(entityRef, type);

if (data != null) {
    data.setText("health", "42/67");        // set or update a value
    String current = data.getText("health"); // read the current value
    data.removeText("health");              // remove a single key
    boolean empty = data.isEmpty();         // check if any segments remain

    for (var entry : data.getEntries()) {
        String key = entry.getKey();        // segment ID
        String value = entry.getValue();    // current text
    }
}
```

## Manual Text + Resolver Priority

If an entity has **both** manual text and a resolver for the same segment, the manual text wins. This is useful when you want a resolver to handle the normal case but override specific entities:

```java theme={null}
// In setup() - resolver computes health normally
NameplateAPI.define(this, "health", "Health", SegmentTarget.ALL, "67/69")
    .requires(statMapType)
    .resolver((store, entityRef, variantIndex) -> {
        // ... compute health from stats ...
    });

// At runtime - override one specific boss entity
NameplateAPI.setText(store, bossEntityRef, "health", "INVULNERABLE");
```

## Next Steps

* **[Format Variants](/modding/format-variants)** - Let players pick between display formats
* **[Advanced](/modding/advanced)** - Hidden metadata keys, cleanup, and edge cases
