// FOR DEVELOPERS

API Guide

Eymistaken's HUD was engineered with extensibility at its core. Use the EymistakenHudPlugin API to inject custom modules seamlessly into the HUD rendering and ticking engines — no core modification required.

JUMP TO: Architecture Dependency Creating a Module HUD Editor Context Menu Registering

Modular Architecture

The entire HUD system is orchestrated by HudModuleManager. On initialization it registers the 7 built-in modules. Via the eymistaken_hud Fabric entrypoint, third-party addons can register additional modules that are loaded and managed alongside the core ones automatically.

Each module extends HudModule, which handles render position injection, rainbow color cycling, and the context menu settings contract. Every frame, HudModuleManager calls tickAll(Minecraft) and renderAll(GuiGraphicsExtractor, float). The render pipeline runs through the client-side HUD registry — modules receive a GuiGraphicsExtractor context and implement extractRenderState(GuiGraphicsExtractor, float) to draw their content. Automatic stacking layout per screen quadrant (TOP_LEFT, TOP_RIGHT, BOTTOM_LEFT, BOTTOM_RIGHT, CENTER) is handled entirely by the manager before calling each module.

Adding the Dependency

Use JitPack to compile your addon mod against Eymistaken's HUD 26.1. Add the following to your build.gradle:

repositories {
    maven { url 'https://jitpack.io' }
}

dependencies {
    modImplementation 'com.github.Eymistaken:Eymistaken-s-HUD:-SNAPSHOT'
}

After reloading your Gradle project, all 26.1 API classes — including HudModule, HudModuleSetting, and all six setting types — will be available in your development environment.

Creating a Custom Module

Every HUD element must extend HudModule and implement its abstract methods. Below is the minimum required implementation:

import com.eymistaken.simplecps.api.HudModule;
import com.eymistaken.simplecps.SimpleCPSConfig;
import net.minecraft.client.gui.GuiGraphicsExtractor;

public class MyCustomModule extends HudModule {

    @Override
    public String getName() {
        return "My Custom Tracker";
    }

    @Override
    public SimpleCPSConfig.Position getPositionType() {
        return SimpleCPSConfig.Position.TOP_LEFT; // Default corner alignment
    }

    @Override
    public int getXOffset() { return 0; }

    @Override
    public int getYOffset() { return 0; }

    @Override
    public boolean isEnabled() {
        return true; // Tie to your own config
    }

    @Override
    public int getWidth() {
        return 100; // Required for stacking layout
    }

    @Override
    public int getHeight() {
        return 20;
    }

    @Override
    public void extractRenderState(GuiGraphicsExtractor context, float tickDelta) {
        // this.x and this.y are injected by HudModuleManager before extractRenderState() is called.
        context.drawString(this.client.font, "Hello World", this.x, this.y, 0xFFFFFF, true);
    }

    @Override
    public void tick(net.minecraft.client.Minecraft client) {
        // Optional: runs every client tick (timers, click tracking, etc.)
        super.tick(client);
    }
}

Important: Always return accurate values from getWidth() and getHeight(). Returning 0 removes your module from the stacking layout and makes it invisible.

HUD Editor Integration (Drag & Drop)

Override the optional setter methods to allow players to move, scale, and reset your module in the HUD Editor. Important: save all values to your own mod's config — never to SimpleCPSConfig.

// Inside your MyCustomModule class:

@Override
public void setPositionType(SimpleCPSConfig.Position pos) {
    MyAddonConfig.anchor = pos; // Save to YOUR config
}

@Override
public void setXOffset(int x) { MyAddonConfig.xOffset = x; }

@Override
public void setYOffset(int y) { MyAddonConfig.yOffset = y; }

@Override
public void setScale(int scale) { MyAddonConfig.scale = scale; }

@Override
public int getScale() { return MyAddonConfig.scale; }

@Override
public void resetToDefaults() {
    // Called by "Reset Position" in the context menu
    MyAddonConfig.anchor  = SimpleCPSConfig.Position.TOP_LEFT;
    MyAddonConfig.xOffset = 0;
    MyAddonConfig.yOffset = 0;
    MyAddonConfig.scale   = 100;
}

If you skip these overrides, your module will still render correctly — but players will not be able to move or scale it via the HUD Editor.

Context Menu Settings

When a player right-clicks your module in the HUD Editor, a context menu appears. By default it contains Reset Position and Reset Settings. Extend it by overriding getContextMenuSettings().

Six setting types are available under com.eymistaken.simplecps.api:

import com.eymistaken.simplecps.api.*;
import java.util.Arrays;
import java.util.List;

// Inside your MyCustomModule class:

@Override
public List<HudModuleSetting> getContextMenuSettings() {
    List<HudModuleSetting> settings = new java.util.ArrayList<>(super.getContextMenuSettings());

    // Toggle — shown as [ON] / [OFF]
    settings.add(new BooleanSetting("Enable My Module",
        () -> MyAddonConfig.enabled,
        val -> { MyAddonConfig.enabled = val; MyAddonConfig.save(); }
    ));

    // Color — opens Color Picker on click
    settings.add(new ColorSetting("Text Color",
        () -> MyAddonConfig.textColor,
        color -> { MyAddonConfig.textColor = color; MyAddonConfig.save(); }
    ));

    // Text — opens inline input on click
    settings.add(new TextSetting("Suffix Text",
        () -> MyAddonConfig.suffix,
        val -> { MyAddonConfig.suffix = val; MyAddonConfig.save(); }
    ));

    // Cycle — click through options
    settings.add(new CycleSetting("Display Mode",
        Arrays.asList("Compact", "Full", "Minimal"),
        () -> MyAddonConfig.displayModeIndex,
        idx -> { MyAddonConfig.displayModeIndex = idx; MyAddonConfig.save(); }
    ));

    // Action — plain button, no value
    settings.add(new ActionSetting("Reset My Settings", () -> {
        MyAddonConfig.resetVisuals();
        MyAddonConfig.save();
    }));

    // Slider — integer range with Reset button
    settings.add(new SliderSetting("Scale %",
        50, 300, 100,
        () -> MyAddonConfig.scale,
        val -> { MyAddonConfig.scale = val; MyAddonConfig.save(); }
    ));

    return settings;
}

Tip: Always call super.getContextMenuSettings() and wrap it in a new ArrayList to preserve the default Reset Settings action at the top of the menu. Skip the super call only if you intentionally want to replace it entirely. Note: Reset Position is always present regardless — it is added directly by the HUD Editor, not by getContextMenuSettings().

Override resetVisualDefaults() to define what Reset Settings does for your module. Reset all visual and behavioral fields — but never the enabled state, position, offsets, or scale:

@Override
public void resetVisualDefaults() {
    MyAddonConfig.textColor        = 0xFFFFFF;
    MyAddonConfig.suffix           = "";
    MyAddonConfig.displayModeIndex = 0;
    MyAddonConfig.save();
}

Rule: Never reset enabled, position, offsets, or scale inside resetVisualDefaults(). Position is handled separately by Reset Position, and whether the module is on or off is always the player's choice.

Registering the Plugin

Declare an entrypoint implementing EymistakenHudPlugin in your fabric.mod.json. Your modules will be passed to HudModuleManager#registerModule() and managed alongside the built-in ones from that point forward — no core modification required.

Implementation class:

import com.eymistaken.simplecps.api.EymistakenHudPlugin;
import com.eymistaken.simplecps.HudModuleManager;

public class MyPluginInit implements EymistakenHudPlugin {
    @Override
    public void registerHudModules(HudModuleManager manager) {
        manager.registerModule(new MyCustomModule());
    }
}

fabric.mod.json:

"entrypoints": {
  "eymistaken_hud": [
    "com.myname.myaddon.MyPluginInit"
  ]
}

The eymistaken_hud entrypoint key is processed by SimpleCPSClient during initialization. Every registered module is automatically included in the tickAll() and renderAll() cycles of HudModuleManager, and becomes fully editable in the in-game HUD Editor.