Reading State¶
Quick Start: Extend the plugin.
Several matches can run concurrently, one per lobby. Unknown ids read as
empty everywhere: empty optionals, empty collections, false states, never
null and never thrown. Every call must run on the server main thread; events
fire synchronously on the main thread.
Matches¶
api.matches() covers live matches plus lifecycle actions. Actions run the
same paths as the built-in commands and GUI, so edition caps and
preconditions apply exactly as in game.
| Method | Meaning |
|---|---|
match(matchId) |
One live match, empty for unknown or ended ids. |
liveMatches() |
All live matches, oldest first. |
matchOf(playerId) |
The player's live match, empty when in none. |
lobbyMatches(lobbyId) |
Live matches started from one lobby, oldest first. |
start(lobbyId) |
Starts a match, same checks as the start command. Returns a StartResult (OK, UNKNOWN_LOBBY, ALREADY_RUNNING, CONCURRENCY_CAPPED, REFUSED); nothing is allocated unless the result is OK. |
begin(matchId) |
Ends the pre-start window early and begins the game. false for unknown or already-begun matches. |
cancel(matchId) |
Cancels a live match with no winner (the end-command path). false for unknown matches. |
ManhuntMatch carries the match id, origin lobby id, MatchPhase
(LOBBY, PREPARING, PRESTART, IN_PROGRESS, ENDING),
begun/ending flags,
start and elapsed timestamps, per-role player lists (players(),
hunters(), runners(), spectators()), and the winner once announced.
Lobbies¶
api.lobbies() covers lobby membership:
| Method | Meaning |
|---|---|
lobbyIds() |
Every known lobby id. |
lobby(lobbyId) |
One lobby (members, running match ids), empty for unknown ids. |
members(lobbyId) |
Member UUIDs, empty for unknown ids. |
lobbyOf(playerId) |
The player's lobby, empty when in none. |
Players¶
api.players() covers per-player state:
| Method | Meaning |
|---|---|
player(playerId) |
UUID, name, role, live match id, alive flag, lives left, score, kills, deaths. Empty for unknown players. |
roleOf(playerId) |
HUNTER, RUNNER, SPECTATOR, AFK, or NONE. |
isParticipant(playerId) |
true for hunters and runners. |
Compass¶
api.compass() reads the tracking compass:
| Method | Meaning |
|---|---|
targetOf(holderId) |
The holder's live CompassTarget: hunter, kind (PLAYER, LOCATION, NONE), target id/name, location, and distance in meters. Empty when the holder tracks nothing. |
Compass reads are snapshots of live state: NONE covers idle, fuzzy, and
untracked alike.
Scores¶
api.scores() reads live match scores and applies bonus/penalty
adjustments:
| Method | Meaning |
|---|---|
scoreOf(matchId, playerId) |
One participant's live score, empty for unknown rows. |
scores(matchId) |
Every scored row (MatchScore with player, score, kills), empty for unknown ids. |
liveMvp(matchId) |
The live score leader (MvpInfo with player, name, score), empty when nobody leads. |
adjustScore(matchId, playerId, delta) |
Adds a bonus (positive) or penalty (negative) to one participant's live score. Adjustments fold into the same ledger the engine scores into, so MVP picks and end reports see them. false when the match has no live unfinalized ledger for the player. |
Scores can go negative at runtime; saved match snippets clamp them at zero.
Placeholders¶
api.placeholders() resolves the same keys PlaceholderAPI serves,
programmatically:
| Method | Meaning |
|---|---|
resolve(player, key) |
One key without the %jmanhunt_ prefix or % markers (for example career_kills). The player may be null for player-less keys; viewer keys with a null player resolve empty. Empty when the key is unknown, disabled, or unavailable. |
keys() |
Every resolvable key, in config order. |
This is how integrations feed scoreboards, holograms, and Discord bots without depending on PlaceholderAPI.
Modifiers¶
api.modifiers() toggles global modifier and preset state:
| Method | Meaning |
|---|---|
modifiers() |
Every known modifier (ModifierInfo with id, display name, author, enabled flag, preset flag). |
modifier(id) |
One modifier, empty for unknown ids. |
setEnabled(id, enabled) |
Enables or disables one modifier globally (a preset flips every transitive member). Known ids always return true, even when the flag already held the value; false for unknown ids. |
Modifier scripting itself belongs to JMHScript (see Your first modifier): the API covers global toggles for integrations, while per-match behavior stays in modifier files.
Queues¶
api.queues() extends the Quick Match actionbar, which refreshes twice
per second while a player queues:
| Method | Meaning |
|---|---|
addQueueActionbarItem(id, priority, renderer) |
Adds one actionbar point under the id (prefix it with your plugin name, for example myplugin:line), replacing any point already there. A null render hides the point for that tick; a throwing renderer logs and hides. |
removeQueueActionbarItem(id) |
Removes one point. True when one was registered under the id. |
rankedPenaltyStrikes(playerId) |
Ranked penalty strikes inside the remember window, or 0. Expired windows read 0. |
rankedPenaltyExpiryMillis(playerId) |
Ranked queue cooldown expiry in epoch millis, or empty when no cooldown runs. |
- Priorities run from
QueueActionbarPriorities.MIN_PRIORITY(0) toMAX_PRIORITY(10000); out-of-range values clamp, and lower renders first. The engine's own points consume the same constants, so place yours around them:
| Constant | Value | Point |
|---|---|---|
ROOT |
0 | The elapsed line (Queued for {elapsed}, or Starting in {time} while the attached match counts down). Never a bullet. |
MATCH |
1000 | The attached playlist headcount, hidden while still searching. |
EXIT_HINT |
9000 | The trailing double-shift exit hint. |
- Two points at one slot halve toward the requested priority (0.5, 0.25, 0.125, ...) up to ten probes, then the newcomer overwrites the slot; both cases log severe, so spread companion points across the gaps.
- Renderer input is a
QueueActionbarContextrecord: the viewingplayerId,elapsedSecondssince the attempt started, the attachedplaylistId(null while searching),memberCountandtotalof the attached instance (0 while searching), plusstartingandsecondsLeft(-1 unless the match is starting). Renderers run on the main thread every actionbar tick, so keep them cheap.
import com.jruk8.jmanhunt.api.model.QueueActionbarContext;
api.queues().addQueueActionbarItem("myplugin:streak", 2000,
(QueueActionbarContext view) -> streakLine(view.playerId()));
When the queue engine is unavailable, every call degrades: points never render, strikes read 0, expiry reads empty. The surface never throws, so companions never branch on it.