Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/iFamishedX/HungerBridge/llms.txt

Use this file to discover all available pages before exploring further.

HungerBridge for Fabric is a server-side-only mod that launches a lightweight HTTP server alongside your Minecraft server. It gives HungerLib (and any other HTTP client) a stable, authenticated interface to execute console commands, write server logs, and query real-time performance metrics — all without RCON. This guide covers installation, configuration, and the internals you need to understand to get the most out of the integration.

Prerequisites

Before installing HungerBridge, make sure your environment meets these requirements:

Fabric Loader

Version ≥ 0.18.4 — declared as a hard dependency in fabric.mod.json

Minecraft

1.21.11 (the mod depends on minecraft: >=1.21.10)

Java

Java 21 or later — required by Minecraft 1.21.x itself

Dedicated Server

HungerBridge declares "environment": "server" and will not initialize on a client instance
HungerBridge is a server-side only mod. It does not need to be installed on any player client.

Installation

1

Download the JAR

Grab the latest HungerBridge-fabric-<version>.jar from the GitHub Releases page. Choose the file with the fabric classifier.
2

Place the JAR in your mods folder

Copy the downloaded JAR into the mods/ directory of your Fabric dedicated server:
cp HungerBridge-fabric-2.5.2-alpha.jar /path/to/server/mods/
3

Start the server

Launch the server normally. On the first run, HungerBridge creates its configuration directory and writes a default config.yaml with a randomly generated auth key:
[HungerBridge] Config file not found, generating default config at config/HungerBridge/config.yaml
[HungerBridge] HungerBridge started on port 30007
4

Review the config file

Open config/HungerBridge/config.yaml (relative to your server root) and adjust the settings for your environment. The most important value is auth.key — copy it to your HungerLib configuration.
config/HungerBridge/config.yaml
port: 30007

auth:
  key: "auto-generated-uuid-here"

v2-endpoints:
  run: true
  log: true
  ping: true
  info: true
  status: true
  tps: true
  players: true

v1-endpoints:
  run: false
  log: false
  status: false
  version: false

legacy-endpoints:
  run: false
  log: false

players:
  max-list: 50
5

Restart the server

Stop and restart the server to apply any configuration changes. HungerBridge reads config.yaml once at startup via Config.load().

Configuration Reference

KeyDefaultDescription
port30007TCP port the HTTP server binds to
auth.key(random UUID)Shared secret; sent as X-Auth-Key header
v2-endpoints.*all trueEnable/disable individual v2 API routes
v1-endpoints.*all falseEnable/disable legacy v1 routes
legacy-endpoints.*all falseEnable/disable plaintext legacy routes
players.max-list50Maximum number of player names returned by /v2/players
Leave v1-endpoints and legacy-endpoints disabled unless you are running an older HungerLib version that requires them. The v2 routes are the preferred interface.

Mod Internals

Understanding how HungerBridge works under the hood helps when debugging unexpected behaviour or integrating with custom tooling.

Lifecycle and Mixins

HungerBridge registers a single Mixin — MinecraftServerMixin — that hooks into two points of the MinecraftServer lifecycle:
  • Server started: on the first tick of tickChildren, calls HungerBridgeFabric.onServerStarted(server), which loads config, constructs a FabricCommandExecutor, and starts the BridgeServer HTTP listener.
  • Server stopping: calls HungerBridgeFabric.onServerStopping() from the stopServer injection, which calls BridgeServer.stop() to shut down the HTTP listener and its thread pool cleanly.
The DedicatedServerModInitializer entry point (onInitializeServer) only logs an initialization message — the actual startup is deferred to the first tick via the mixin.

Command Dispatch

Fabric commands are dispatched on the server main thread using server.execute():
server.execute(() ->
    server.getCommands().performPrefixedCommand(console(), command)
);
performPrefixedCommand uses a CommandSourceStack built from server.createCommandSourceStack(), giving the command full console-level permissions. When output capture is not needed (fire-and-forget execute()), the call is non-blocking. When output is required (executeWithOutput()), a CompletableFuture is used to block the HTTP handler thread until the main thread finishes executing the command.

Output Capture via Log4j

Command output is intercepted by temporarily installing a custom AbstractAppender on the Log4j root logger. The behaviour differs based on the show_console field in the request body:
All existing appenders (console, file, etc.) are removed from the root logger before the command runs, so output is captured silently without printing to the server console. After the command finishes, the original appenders are restored.
// Remove all existing appenders
for (Appender a : original.values()) {
    root.removeAppender(a);
}
root.addAppender(capture); // only capture appender active
try {
    server.getCommands().performPrefixedCommand(console(), command);
} finally {
    root.removeAppender(capture);
    // Restore original appenders
    for (Appender a : original.values()) {
        root.addAppender(a);
    }
}
Appender manipulation happens on the server main thread and is not safe to run concurrently. Avoid sending overlapping command-with-output requests; HungerBridge does not serialize them internally.

TPS Tracking

Fabric does not expose a built-in TPS API, so HungerBridge implements its own using an exponential moving average (EMA) updated on every server tick via the MinecraftServerMixin. Each tick duration (in nanoseconds) is recorded into a fixed-size ring buffer of 18,000 samples (equivalent to 15 minutes at 20 TPS). Three EMA windows are maintained in parallel:
FieldSmoothing Factor (α)Approximate Window
ema201/20~20 ticks (1 second)
ema12001/1200~1 minute
ema60001/6000~5 minutes
TPS is derived from the EMA tick time:
double raw = 1000.0 / ema20; // convert ms/tick → ticks/second
return Math.min(20.0, raw);  // clamp to 20.0 maximum
The /v2/tps endpoint exposes four fields: tps (20-tick EMA), tps_1m, tps_5m, and tps_15m. Because the EMA only has three windows, tps_15m reuses the 5-minute value (getTps5m()) to keep the response schema consistent with the Paper implementation. tick_time_ms is computed separately as the average of the last 100 raw tick durations from the ring buffer, giving a short-window view of current tick health.
TPS values are clamped to a maximum of 20.0. A reading of 20.0 means the server is keeping up with the target tick rate; values below indicate lag. Before the ring buffer fills (18,000 ticks, about 15 minutes of uptime), EMA values start from an assumed ideal tick time of 50 ms.

Build docs developers (and LLMs) love