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 Paper is a standard Bukkit plugin that starts a lightweight HTTP server when your Paper or Purpur server enables it. The HTTP API lets HungerLib (and any compatible HTTP client) execute console commands, write server logs, and query live TPS and player data — without the complexity of RCON. This guide walks you through installation, configuration, and the internals that power command dispatch and output capture.

Prerequisites

Confirm your server environment before installing:

Server Software

Paper or Purpur — any build targeting Minecraft 1.21.11

Paper API

API version 1.21, as declared in plugin.yml

Minecraft

1.21.11 — the same version required by HungerBridge Fabric if you run a mixed setup

Java

Java 21 or later — required by Paper 1.21.x

Installation

1

Download the JAR

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

Place the JAR in your plugins folder

Copy the downloaded JAR into the plugins/ directory of your Paper or Purpur server:
cp HungerBridge-paper-2.5.2-alpha.jar /path/to/server/plugins/
3

Start the server

Launch the server. On the first run, HungerBridge generates a default config.yaml with a randomly generated auth key and logs the following:
[HungerBridge] Config file not found, generating default config at plugins/HungerBridge/config.yaml
[HungerBridge] HungerBridge enabled.
4

Review the config file

Open plugins/HungerBridge/config.yaml and adjust settings for your environment. The auth.key value must be copied into your HungerLib configuration:
plugins/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 during onEnable().

Configuration Reference

KeyDefaultDescription
port30007TCP port the HTTP server listens on
auth.key(random UUID)Shared secret sent as the X-Auth-Key header
v2-endpoints.*all trueToggle individual v2 API routes on or off
v1-endpoints.*all falseToggle legacy v1 routes
legacy-endpoints.*all falseToggle plaintext legacy routes
players.max-list50Maximum player names returned by /v2/players
Keep v1-endpoints and legacy-endpoints disabled unless you are using an older HungerLib version that targets those routes. The v2 routes are the recommended interface.

Plugin Internals

Lifecycle

HungerBridge is a standard JavaPlugin. Its HTTP server starts and stops entirely inside the two Bukkit lifecycle methods:
@Override
public void onEnable() {
    // Load config, create executor, start BridgeServer
    bridgeServer = new BridgeServer(config, logger, executor);
    bridgeServer.start();
}

@Override
public void onDisable() {
    if (bridgeServer != null) {
        bridgeServer.stop();  // stops HTTP listener and thread pool
        bridgeServer = null;
    }
}
BridgeServer.start() binds the configured TCP port and registers all enabled endpoint handlers. BridgeServer.stop() calls HttpServer.stop(0) and shuts down the cached thread pool immediately.
PaperServerInfoProvider is instantiated in onEnable() but is not passed into BridgeServer. TPS and tick-time data are read directly inside PaperCommandExecutor using the Bukkit API — PaperServerInfoProvider is unused in the current release.

Command Dispatch

Paper commands are dispatched on the server main thread using the Bukkit scheduler:
plugin.getServer().getScheduler().runTask(plugin, () ->
    plugin.getServer().dispatchCommand(
        plugin.getServer().getConsoleSender(),
        command
    )
);
dispatchCommand runs with getConsoleSender() as the source, which grants the command full console-level permissions. For fire-and-forget calls (no output capture), this task is submitted and the HTTP handler returns immediately. When output is required, a CompletableFuture blocks the HTTP handler thread until the main-thread task completes.

Output Capture via Log4j

Command output is captured by temporarily installing a custom AbstractAppender named HungerBridgeCapture on the Log4j root logger. The root logger is used because it is the single reliable capture point for all output on both Paper and Purpur. The behaviour depends on the show_console field in the request body:
All existing appenders (console writer, file appender, etc.) are removed before the command runs, so output is silently captured without appearing in the server console or log files. After the command finishes, every original appender is restored.
// Snapshot and remove all existing appenders
Map<String, Appender> originalAppenders = root.getAppenders();
for (Appender app : originalAppenders.values()) {
    root.removeAppender(app);
}
root.addAppender(capture);

try {
    plugin.getServer().dispatchCommand(
        plugin.getServer().getConsoleSender(), command
    );
} finally {
    root.removeAppender(capture);
    capture.stop();
    // Restore all original appenders
    for (Appender app : originalAppenders.values()) {
        root.addAppender(app);
    }
}
Log4j root logger manipulation runs on the server main thread. Concurrent requests that both capture output may interfere with each other. Avoid sending simultaneous command-with-output requests to the same HungerBridge instance.

TPS Reporting

Paper exposes TPS data through Bukkit.getServer().getTPS(), which returns a double[] of three values. HungerBridge maps these directly to the /v2/tps response fields:
Array IndexResponse FieldMeaning
tps[0]tpsRecent TPS (short window)
tps[1]tps_1m1-minute average TPS
tps[2]tps_5m5-minute average TPS
tps[2]tps_15mReuses the 5-minute value — Paper exposes only 3 values
@Override
public double getTps() {
    double[] tps = Bukkit.getServer().getTPS();
    if (tps.length == 0) return -1.0;
    return tps[0];
}

@Override
public double getTps15m() {
    // Paper exposes only 3 values; reuse 5m for 15m to keep schema stable.
    double[] tps = Bukkit.getServer().getTPS();
    if (tps.length < 3) return -1.0;
    return tps[2];
}
tick_time_ms is computed from Bukkit.getServer().getTickTimes(), which returns a long[] of recent tick durations in nanoseconds. HungerBridge averages the full array and converts to milliseconds by dividing by 1_000_000:
long avg = 0L;
for (long t : times) avg += t;
avg /= times.length;
return avg / 1_000_000.0;
If getTPS() or getTickTimes() returns an empty array (which can happen very early in server startup), the corresponding field is reported as -1.0 in the API response rather than throwing an exception.

Build docs developers (and LLMs) love