A client-side Fabric library that exposes a clean, high-level API for player interaction, world querying, and human-like automation. Designed to be a shared foundation so other mods don't have to reimplement the same low-level mixins.
GitHub: https://github.com/noname-mods/PlayerAPI
PlayerAPI does nothing on its own. If you downloaded this, another mod you use requires it as a dependency. Simply place the .jar in your mods folder alongside that mod.
This library targets one Minecraft version at a time. When it updates to a new Minecraft version, previous versions receive zero further support — no backports, no bug fixes, and a release is never published with support for multiple Minecraft versions at once. Use the PlayerAPI build that matches your Minecraft version and the mods that depend on it.
Version: 1.12.0
Minecraft: 26.1.2 (Fabric)
Maven coordinate: com.playerapi:playerapi:1.12.0
PlayerAPI is a client-side Fabric library that provides a clean, stable abstraction over everything a client-side automation or utility mod needs to do with the local player. It exists so that consumer mods never have to import Minecraft internals directly — all game interaction flows through PlayerAPI's public API classes.
Core design principles:
0, false, "", empty list, EMPTY snapshot) if the player is not in a world. Consumer mods never need null checks.ItemSnapshot, EntitySnapshot, BlockSnapshot, EffectSnapshot) are immutable Java records. They can be stored and compared freely without the underlying game object becoming stale.┌─────────────────────────────────────────────────────────┐
│ Consumer Mod │
│ (depends on PlayerAPI, never imports MC internals) │
└───────────────────┬─────────────────────────────────────┘
│ uses
┌───────────────────▼─────────────────────────────────────┐
│ PlayerAPI Public Surface │
│ │
│ Events Scheduler Actions (Forced) │
│ PlayerAPIEvents Scheduler MovementActions │
│ LookActions │
│ Info (read) InventoryActions │
│ PlayerInfo InteractionActions │
│ InventoryInfo ChatActions │
│ WorldInfo SoundActions │
│ TabListInfo DisplayActions │
│ │
│ Actions (Human) Data Types │
│ HumanActions ItemSnapshot │
│ HumanProfile EntitySnapshot │
│ BlockSnapshot │
│ EffectSnapshot │
└───────────────────┬─────────────────────────────────────┘
│ wraps
┌───────────────────▼─────────────────────────────────────┐
│ PlayerAPI Internals (not public) │
│ │
│ PlayerAPIMod — wires Fabric events, drives ticks │
│ KeyStateTracker — held-key set, mixin read target │
│ SchedulerState — tick-based task queue │
│ HumanLookState — spring-damper look interpolation │
│ MovementInputMixin — @Mixin(KeyboardInput) override │
│ PlayerInventoryAccessor — @Mixin accessor for slots │
└─────────────────────────────────────────────────────────┘
ClientTickEvents.END_CLIENT_TICK
│
├─ 1. SchedulerState.tick() — fires due scheduled tasks
├─ 2. HumanLookState.tick() — advances spring interpolation
├─ 3. diff-based event checks — health, position changes
└─ 4. PlayerAPIEvents.TICK.invoke() — consumer mod tick callbacks
MovementInputMixin is a @Mixin on KeyboardInput with a TAIL injection into its tick() method. At the end of every vanilla input tick, if KeyStateTracker.isActive() is true, the mixin overwrites input.pressingForward, input.pressingBack, input.pressingLeft, input.pressingRight, input.jumping, and input.sneaking with the values stored in KeyStateTracker. This means the override is completely transparent to the rest of the game — movement, sprint physics, and server packets all behave normally.
build.gradlerepositories {
mavenLocal()
}
dependencies {
modImplementation "com.playerapi:playerapi:1.12.0"
}
gradle.propertiesplayerapi_version=1.12.0
fabric.mod.json"depends": {
"playerapi": ">=1.12.0"
}
Build PlayerAPI first:
cd PlayerAPI
./gradlew publishToMavenLocal
Then build your mod normally.
All PlayerAPI calls must be made from the main game thread. This is the thread that runs ClientTickEvents, renders frames, and processes network packets. In practice this means:
PlayerAPIEvents.TICK handlers — ✅ always safeCompletableFuture — ❌ never safe; use MinecraftClient.getInstance().execute(() -> ...) to marshal backThe Scheduler always fires callbacks on the main thread.
PlayerAPIEventsAll events live on com.playerapi.PlayerAPIEvents. Register listeners from your mod's onInitializeClient().
PlayerAPIEvents.TICK.register(() -> {
// runs every tick
});
All events use Fabric's EventFactory.createArrayBacked pattern — multiple mods can register independently and all listeners fire.
TICKEvent<PlayerAPIEvents.Tick> TICK
Fires once per game tick, after END_CLIENT_TICK, after the scheduler has processed due tasks.
Interface:
@FunctionalInterface
interface Tick {
void onTick();
}
Notes:
PlayerInfo.isInWorld() at the top if your logic requires a loaded world.TICK handler runs.CHAT_RECEIVEDEvent<PlayerAPIEvents.ChatReceived> CHAT_RECEIVED
Fires when any chat message arrives — player chat, system messages, or game messages. Covers both signed player messages and unsigned server messages.
Interface:
@FunctionalInterface
interface ChatReceived {
void onChatReceived(String sender, String message);
}
| Parameter | Description |
|---|---|
sender |
Display name of the sender, stripped of colour codes. Empty string for system/game messages. |
message |
Full message text, stripped of colour codes. |
Notes:
overlay=true) are not forwarded.ClientReceiveMessageEvents.CHAT (player messages) and ClientReceiveMessageEvents.GAME (system/game messages) feed into this single event.HEALTH_CHANGEDEvent<PlayerAPIEvents.HealthChanged> HEALTH_CHANGED
Fires whenever the local player's health value changes by any amount.
Interface:
@FunctionalInterface
interface HealthChanged {
void onHealthChanged(float oldHealth, float newHealth);
}
Notes:
PLAYER_DEATH fires first if health dropped to 0, then HEALTH_CHANGED fires immediately after.INVENTORY_CHANGEDEvent<PlayerAPIEvents.InventoryChanged> INVENTORY_CHANGED
Fires when the player's main inventory changes.
Interface:
@FunctionalInterface
interface InventoryChanged {
void onInventoryChanged(int slot, String newItemId);
}
| Parameter | Description |
|---|---|
slot |
Inventory slot that changed. -1 means a bulk/unknown change. |
newItemId |
Namespaced item ID of the new item in that slot, e.g. "minecraft:diamond_sword". "minecraft:air" for an empty slot. |
POSITION_CHANGEDEvent<PlayerAPIEvents.PositionChanged> POSITION_CHANGED
Fires when the player moves more than 0.1 blocks from their position at the last firing. This is a threshold-based event — it does not fire every tick, only on meaningful movement.
Interface:
@FunctionalInterface
interface PositionChanged {
void onPositionChanged(double x, double y, double z);
}
Notes:
PlayerInfo.getX/Y/Z() inside TICK for that.WORLD_JOINEvent<PlayerAPIEvents.WorldJoin> WORLD_JOIN
Fires once after the client connects to a server or loads a world and the player entity is available.
Interface:
@FunctionalInterface
interface WorldJoin {
void onWorldJoin();
}
Notes:
HEALTH_CHANGED and POSITION_CHANGED will not fire spuriously on the first tick.PlayerInfo.isInWorld() returns true at the time this fires.WORLD_LEAVEEvent<PlayerAPIEvents.WorldLeave> WORLD_LEAVE
Fires when the client disconnects or leaves a world. All held keys are released and any active human look interpolation is cancelled automatically before this event fires.
Interface:
@FunctionalInterface
interface WorldLeave {
void onWorldLeave();
}
PLAYER_DEATHEvent<PlayerAPIEvents.PlayerDeath> PLAYER_DEATH
Fires when the player's health reaches 0.
Interface:
@FunctionalInterface
interface PlayerDeath {
void onPlayerDeath();
}
Notes:
HEALTH_CHANGED also fires immediately after with newHealth = 0.TAB_LIST_UPDATEDEvent<PlayerAPIEvents.TabListUpdated> TAB_LIST_UPDATED
Fires when the server updates the tab-list player list. Throttled to at most once per tick.
Interface:
@FunctionalInterface
interface TabListUpdated {
void onTabListUpdated();
}
BLOCK_BROKENEvent<PlayerAPIEvents.BlockBroken> BLOCK_BROKEN
Fires when the local player successfully breaks a block. Backed by Fabric's ClientPlayerBlockBreakEvents.AFTER.
Interface:
@FunctionalInterface
interface BlockBroken {
void onBlockBroken();
}
Notes:
WorldInfo.getBlockAtCrosshair() from the TICK event just before.com.playerapi.Scheduler — tick-based task scheduling on the main game thread.
1 tick ≈ 50 ms at 20 TPS.
All callbacks are Runnable and fire on the main game thread at the end of the tick they are due.
schedule(int delayTicks, Runnable task) → intSchedule a task to run after delayTicks ticks. Returns a cancel token.
Scheduler.schedule(20, () -> doSomethingAfterOneSecond());
// token = return value, save it if you need to cancel
delayTicks = 0 fires on the very next tick.scheduleMs(long delayMs, Runnable task) → intConvenience overload. Converts milliseconds to ticks by dividing by 50, rounded up to a minimum of 1.
Scheduler.scheduleMs(500, () -> doSomethingAfterHalfSecond());
scheduleRepeating(int periodTicks, int times, Runnable task) → intSchedule a repeating task.
| Parameter | Description |
|---|---|
periodTicks |
Ticks between each invocation. |
times |
Number of times to fire. Pass 0 for infinite (runs until cancelled). |
task |
The callback to run. |
// Fire 5 times, once per second:
Scheduler.scheduleRepeating(20, 5, () -> BotLogger.info("tick!"));
// Fire forever (infinite loop — cancel manually):
int token = Scheduler.scheduleRepeating(20, 0, () -> doPeriodicCheck());
// later:
Scheduler.cancel(token);
Important: Infinite repeating tasks self-reschedule after each firing. Cancelling the initial token only prevents the current pending invocation from firing — if the task has already fired once, use cancelAll() or track re-scheduled tokens yourself if you need hard cancellation.
cancel(int token)Cancel a pending task by its token. Safe to call with an invalid/already-fired token.
cancelAll()Cancel every pending task across all mods using this scheduler. Useful in stopBot() to ensure no lingering delayed actions fire after stopping.
getCurrentTick() → longReturns the current global tick count as tracked by PlayerAPI. Starts at 0 on mod load and increments once per END_CLIENT_TICK. Useful for timestamps and rate-limiting.
long start = Scheduler.getCurrentTick();
// ...later...
long elapsed = Scheduler.getCurrentTick() - start; // in ticks
double seconds = elapsed / 20.0;
Forced actions are instant and computer-precise. They take effect on the very next game tick with no delay, noise, or spring physics. Use these when precision matters more than appearance.
MovementActionsControls which movement keys the player holds. The override only applies when setActive(true) has been called.
Valid key names: "forward", "back", "left", "right", "sprint", "sneak", "jump", "attack", "use"
setActive(boolean active)Enable or disable the movement key override. When disabled, all keys are released and the player regains full manual control. Call setActive(true) before pressing any keys.
MovementActions.setActive(true);
MovementActions.pressKey("forward");
MovementActions.pressKey("sprint");
// player now walks forward
isActive() → booleanReturns whether the movement override is currently enabled.
pressKey(String key)Hold a key indefinitely. The key stays held on every subsequent tick until releaseKey or releaseAll is called.
MovementActions.pressKey("jump"); // holds space bar
releaseKey(String key)Release a single previously held key.
MovementActions.releaseKey("sprint");
releaseAll()Release all currently held keys (forward, back, left, right, sprint, sneak, jump, attack, use). Does not disable the override — setActive remains unchanged.
tapKey(String key, long durationMs)Press a key for durationMs milliseconds then automatically release it. Internally converts to ticks.
MovementActions.tapKey("jump", 100); // tap space for 100 ms (2 ticks)
pressKeys(Iterable<String> keys)Press multiple keys simultaneously. Equivalent to calling pressKey for each.
releaseDirectionKeys()Release only the four directional keys (forward, back, left, right). Sprint, sneak, and jump states are unchanged. Useful for stopping movement while staying in sprint mode.
getHeldKeys() → Set<String>Returns an immutable snapshot of all currently held key names.
isPressed(String key) → booleanReturns true if the given key is currently being held by the override.
randomDelay() → longReturns a random delay between 50 ms and 260 ms. Useful as a timing jitter between programmatic key presses for anti-pattern detection.
LookActionsInstantly set the player's camera direction. All changes take effect immediately — there is no animation.
Minecraft yaw convention:
0° = South (+Z)90° = West (−X)180° = North (−Z)270° = East (+X)Pitch: −90° = straight up, 0° = horizontal, 90° = straight down.
setYaw(float yaw)Set the player's horizontal rotation to exactly yaw degrees.
setPitch(float pitch)Set the player's vertical rotation to exactly pitch degrees. Automatically clamped to [−90, 90].
lookAt(double x, double y, double z)Instantly rotate to look at an exact world position. Calculates the required yaw and pitch automatically from the player's current eye position.
LookActions.lookAt(100.0, 64.0, -200.0);
// For level aim: pass player.getY() + 1.62 as the y argument
lookAtBlock(int x, int y, int z)Instantly look at the centre of a block (x+0.5, y+0.5, z+0.5).
lookAtBlock(BlockPos pos)Same as above, accepting a BlockPos.
lookAtBlock(int x, int y, int z, Direction face)Look at the centre of a specific face of a block. face is a Minecraft Direction enum value (UP, DOWN, NORTH, SOUTH, EAST, WEST).
LookActions.lookAtBlock(10, 64, -5, Direction.UP); // aim at top face
lookAtBlock(int x, int y, int z, double xOffset, double yOffset, double zOffset)Look at a custom point within a block. Offsets are fractions in [0, 1] where 0.5, 0.5, 0.5 is the block centre.
LookActions.lookAtBlock(10, 64, -5, 0.5, 1.0, 0.5); // top-face centre
snapToNearestCardinal()Snap the player's yaw to the nearest multiple of 90°. Useful for aligning before a cardinal-facing path.
getSnappedYaw() → intReturns the current yaw rounded to the nearest cardinal direction (0, 90, 180, or 270).
InventoryActionsDirect inventory manipulation. All operations take effect instantly on the next tick.
switchToSlot(int slot)Switch the selected hotbar slot to slot (0–8). Has no effect if slot is out of range.
switchToItem(String displayName) → booleanSwitch to the first hotbar slot whose item's display name matches exactly (case-insensitive). Returns true if found and switched, false if not in hotbar.
InventoryActions.switchToItem("Wheat Hoe");
switchToItemStartingWith(String prefix) → booleanSwitch to the first hotbar slot whose item display name starts with the given prefix (case-insensitive). Useful for tiered items like "Pest Repellent I" / "Pest Repellent MAX" where you only know the prefix.
InventoryActions.switchToItemStartingWith("Pest Repellent");
switchToItemId(String idSubstring) → booleanSwitch to the first hotbar slot whose item's namespaced ID contains idSubstring (case-insensitive). More stable than display name matching when item names are localised or can change.
InventoryActions.switchToItemId("diamond_hoe");
dropItem()Drop one item from the currently held stack (Q key equivalent).
dropStack()Drop the entire currently held stack (Ctrl+Q equivalent).
dropAllInHotbar(String displayName)Switch to each hotbar slot matching displayName and drop the entire stack. Restores the original selected slot afterward.
InteractionActionsPlayer interactions with items, blocks, and entities.
useItem()Use (right-click) the item in the main hand. Sends the appropriate use-item packet to the server. Works for consumables, throwables, placing blocks, opening blocks, etc.
useOffhandItem()Same as useItem() but for the off-hand slot.
useItemHeld(long durationMs)Continuously send useItem() every tick for durationMs milliseconds. Useful for items that require holding right-click (fishing rods, bows, charging crossbows).
InteractionActions.useItemHeld(1500); // hold right-click for 1.5 seconds
attackTargeted()Attack the entity currently under the player's crosshair (client.targetedEntity). Does nothing if no entity is targeted.
attackBlockAtCrosshair()Send a left-click-block event for the block currently under the crosshair. Call every tick to simulate holding left-click to mine a block. Does nothing if the crosshair is not targeting a block.
interactTargeted()Right-click interact with the entity currently under the crosshair (client.targetedEntity). Used for talking to NPCs, riding entities, etc.
closeScreen()Close any currently open screen (inventory, container, sign, etc.). Equivalent to pressing Escape.
respawn()Send a respawn request to the server. Call this when the player is on the death screen to respawn.
ChatActionssendChat(String message)Send a regular chat message on behalf of the player. Do not include a leading /.
ChatActions.sendChat("Hello, world!");
sendCommand(String command)Send a command without the leading slash. PlayerAPI prefixes the slash internally.
ChatActions.sendCommand("tp 0 64 0"); // sends /tp 0 64 0
ChatActions.sendCommand("warp garden"); // sends /warp garden
SoundActionsPlay sounds from the built-in Minecraft sound library or from your own mod's .ogg files.
Browse all Minecraft sound IDs at: https://misode.github.io/sounds/
registerSound(String namespace, String name) → SoundEventRegister a new sound event. Call once during onInitializeClient(). The .ogg file must be at assets/<namespace>/sounds/<name>.ogg inside your mod's resources jar.
SoundActions.registerSound("mymod", "my_alert"); // assets/mymod/sounds/my_alert.ogg
play(Identifier soundId, float volume, float pitch)Play a sound by its Identifier. Works for both registered mod sounds and all built-in Minecraft sounds.
| Parameter | Range | Description |
|---|---|---|
volume |
0.0 – 2.0 | 1.0 = normal volume |
pitch |
0.5 – 2.0 | 1.0 = normal pitch/speed |
play(String namespace, String name, float volume, float pitch)Convenience overload accepting namespace and name as separate strings.
SoundActions.play("minecraft", "entity.player.levelup", 1.0f, 1.0f);
playById(String fullSoundId, float volume, float pitch)Play by a full string ID such as "minecraft:entity.player.levelup". If no namespace colon is present, defaults to "minecraft".
SoundActions.playById("entity.experience_orb.pickup", 1.0f, 1.5f);
playRepeated(Identifier soundId, float volume, float pitch, int times, int intervalTicks)Play a sound times times with intervalTicks ticks between each play. Uses the Scheduler internally.
// Play level-up sound 3 times, 1 second apart:
Identifier id = Identifier.of("minecraft", "entity.player.levelup");
SoundActions.playRepeated(id, 1.0f, 1.0f, 3, 20);
playRepeated(Identifier soundId, float volume, float pitch, int times)Same as above with a fixed 20-tick (1 second) interval.
playByIdRepeated(String fullSoundId, float volume, float pitch, int times, int intervalTicks)String-ID convenience version of playRepeated.
SoundActions.playByIdRepeated("minecraft:entity.player.levelup", 1.0f, 1.0f, 5, 20);
stopAll()Stop all currently playing sounds.
DisplayActionsShow in-game HUD text without relying on Minecraft internals directly.
showTitle(String title, String subtitle)Show a title and optional subtitle with the default timing (10 ticks fade-in / 70 ticks stay / 20 ticks fade-out).
Supports § colour codes. Pass "" for either parameter to leave it blank.
DisplayActions.showTitle("§aBot Started", "§7Primary path loaded");
showTitle(String title, String subtitle, int fadeInTicks, int stayTicks, int fadeOutTicks)Same as above with custom timing.
showActionBar(String message)Show a short message on the action bar — the line that appears above the hotbar. Disappears after approximately 2 seconds. Supports § colour codes.
DisplayActions.showActionBar("§ePaused — waiting for repellent");
EntityHighlightActionsDraws a translucent, depth-tested coloured box matching an entity's hitbox. Built on Minecraft's Gizmos debug-draw API, so it is independent of the vanilla entity-outline (glow) render pass — it is not weakened in line of sight the way the glow outline is, and is unaffected by how renderer mods (Sodium, etc.) implement the outline pass.
Highlights are namespaced by an owner string so multiple consumer mods can highlight entities at the same time without overwriting each other. PlayerAPI redraws all owners' highlights every tick; consumers just publish their current set.
Added in 1.10.0.
setHighlights(String owner, Map<Integer, Integer> idToColor, float alpha)Replace all of owner's highlights in one call. Keys are entity IDs, values are packed RGB ints (0xRRGGBB). alpha is the box opacity, 0.0–1.0.
Map<Integer, Integer> highlights = Map.of(
entity.getId(), 0xFF5555);
EntityHighlightActions.setHighlights("esp", highlights, 0.35f);
setHighlight(String owner, int entityId, int color, float alpha)Add or update a single entity's highlight under owner, leaving that owner's other highlights untouched.
clearHighlight(String owner, int entityId)Remove one entity from owner's highlight set.
clearOwner(String owner)Remove every highlight registered under owner. Call this when your feature is disabled or the player leaves the world.
BlockHighlightActionsDraws coloured boxes around world block positions — a "block ESP" / xray-style highlight. Each box is drawn always-on-top, so it is visible through walls (the complement to EntityHighlightActions, whose entity overlay is depth-tested / line-of-sight only). Built on the same Gizmos API, and namespaced by an owner string.
Added in 1.11.0.
setHighlights(String owner, Collection<BlockPos> positions, int color, float alpha)Replace all of owner's block highlights with the given positions, all in one colour (0xRRGGBB). alpha is the fill opacity (0.0–1.0); the outline is drawn a little stronger so boxes stay readable.
BlockHighlightActions.setHighlights("esp-blocks", positions, 0x55FFFF, 0.35f);
clearOwner(String owner)Remove every block highlight registered under owner. Call when your feature is disabled or the world changes.
The Human API mirrors the Forced API but adds human-like imperfection: reaction delays, spring-physics camera movement with overshoot, random end-of-movement noise, and scroll-wheel slot switching. All timing parameters are tunable through HumanProfile.
HumanActionsAll look methods start a spring-damper interpolation toward the target. There is a configurable reaction delay before movement begins, the camera accelerates toward the target, naturally overshoots, and settles with a small random noise offset. A 3-second watchdog forces completion if the spring is too slow.
| Method | Description |
|---|---|
lookAt(float yaw, float pitch) |
Smooth look to a yaw/pitch pair. |
lookAt(double x, double y, double z) |
Smooth look toward an exact world position. |
lookAt(int x, int y, int z) |
Smooth look at the centre of a block (integer coords). |
lookAt(BlockPos pos) |
Smooth look at a block position. |
lookAt(int x, int y, int z, Direction face) |
Smooth look at a specific face of a block. |
lookAt(BlockPos pos, Direction face) |
Same, with a BlockPos. |
lookAt(int x, int y, int z, double xOffset, double yOffset, double zOffset) |
Smooth look at a custom point within a block. |
lookYaw(float yaw) |
Change only yaw, keep current pitch. |
lookPitch(float pitch) |
Change only pitch, keep current yaw. |
cancelLook() |
Abort any in-progress look interpolation. View stays where it is. |
isLooking() → boolean |
Returns true while a look (including reaction delay) is active. |
| Method | Description |
|---|---|
pressKey(String key) |
Hold a key after a random [reactionMin, reactionMax] tick delay. |
releaseKey(String key) |
Release a key after a short [keyDelayMin, keyDelayMax] tick delay. |
tapKey(String key, int holdTicks) |
Tap a key for approximately holdTicks ticks, with jitter on both press and release. |
pressKeys(String... keys) |
Press multiple keys simultaneously, all after the same reaction delay. |
releaseAll() |
Release all keys after 1–2 ticks. |
| Method | Description |
|---|---|
switchToSlot(int targetSlot) |
Switch to hotbar slot, optionally scrolling through intermediate slots if HumanProfile.scrollThroughSlots is true. |
switchToItem(String displayName) |
Switch to first matching display name, with delay. |
switchToItemId(String idSubstring) |
Switch to first matching item ID, with delay. |
| Method | Description |
|---|---|
useItem() |
Use main-hand item after a [useItemDelayMin, useItemDelayMax] tick delay. |
useOffhandItem() |
Use off-hand item after the same delay. |
attackTargeted() |
Attack crosshair entity after a reaction delay. |
interactTargeted() |
Interact with crosshair entity after a reaction delay. |
lookThenDo(double x, double y, double z, Runnable callback)Start a human look toward the world position, then execute callback once the look has fully settled. Internally polls isLooking() every tick until false, then fires the callback. A 3-second watchdog fires the callback anyway to prevent hangs.
HumanActions.lookThenDo(100.0, 64.0, -200.0, () -> {
HumanActions.useItem(); // fires only after camera settles
});
Overloads:
lookThenDo(int x, int y, int z, Runnable callback) — block centrelookThenDo(BlockPos pos, Runnable callback) — BlockPoslookThenDo(BlockPos pos, Direction face, Runnable callback) — block facelookThenDo(float yaw, float pitch, Runnable callback) — raw yaw/pitchgetProfile() → HumanProfileReturns the shared HumanProfile instance for reading or changing timing parameters.
HumanProfilecom.playerapi.HumanProfile — a singleton configuration object. All fields are public and can be modified at any time. Changes take effect on the next HumanActions call.
HumanProfile p = HumanProfile.getInstance();
| Field | Type | Default | Description |
|---|---|---|---|
reactionMinTicks |
int |
2 (~100 ms) |
Minimum delay before any human action begins. |
reactionMaxTicks |
int |
5 (~250 ms) |
Maximum delay before any human action begins. A real human averages 200–300 ms. |
A random value in [reactionMin, reactionMax] is chosen each time.
| Field | Type | Default | Description |
|---|---|---|---|
lookSpringK |
float |
0.30 |
Spring constant. Fraction of angular error added to velocity per tick. Higher = faster approach. Range: 0.15 (slow) – 0.50 (fast). |
lookDamping |
float |
0.55 |
Damping multiplier per tick. Values below ~2·√K produce overshoot. Range: 0.4 (bouncy) – 0.85 (barely any overshoot). Critical damping for K=0.30 is ≈1.095. |
lookMaxDegPerTick |
float |
35° |
Hard cap on rotational speed per tick. Prevents instant flicks. |
lookNoiseMaxDeg |
float |
0.8° |
Random noise added once the look settles. Simulates imprecision. |
lookMaxSettleTicks |
int |
40 |
If the look hasn't settled after this many ticks, it is forced to the exact target. Watchdog against infinite loops. |
| Field | Type | Default | Description |
|---|---|---|---|
enableMicroLook |
boolean |
false |
When true, tiny random camera nudges apply every tick while no look is in progress. |
microLookChancePerTick |
float |
0.012 |
Probability per tick of a micro-movement firing (≈ once per 4 seconds). |
microLookMaxDeg |
float |
0.4° |
Maximum yaw change per micro-movement. Pitch is half this value. |
| Field | Type | Default | Description |
|---|---|---|---|
keyDelayMinTicks |
int |
1 |
Minimum delay between key command and key going down. |
keyDelayMaxTicks |
int |
4 |
Maximum delay. |
tapHoldJitterTicks |
int |
3 |
Extra random ticks added to a tap's hold duration. |
| Field | Type | Default | Description |
|---|---|---|---|
scrollThroughSlots |
boolean |
true |
When true, switchToSlot scrolls through intermediate slots rather than jumping directly. |
scrollIntervalTicks |
int |
2 |
Ticks between each scroll step when scrollThroughSlots is enabled. |
| Field | Type | Default | Description |
|---|---|---|---|
useItemDelayMinTicks |
int |
1 |
Minimum delay before a use-item action fires. |
useItemDelayMaxTicks |
int |
3 |
Maximum delay. |
HumanProfile.getInstance().applyFastPreset(); // near-instant, snappy look, minimal noise
HumanProfile.getInstance().applyCasualPreset(); // slow reactions, bouncy look, micro-movements
HumanProfile.getInstance().resetDefaults(); // restore all factory defaults
| Preset | reactionMin | reactionMax | lookSpringK | lookDamping | enableMicroLook |
|---|---|---|---|---|---|
| Default | 2 | 5 | 0.30 | 0.55 | false |
| Fast | 1 | 2 | 0.48 | 0.58 | false |
| Casual | 3 | 7 | 0.20 | 0.50 | true |
Info classes provide read-only access to game state. They never modify anything. All return safe defaults if the player is not in a world.
PlayerInfoQuery the local player's state.
| Method | Returns | Description |
|---|---|---|
getX() |
double |
Player feet X coordinate. |
getY() |
double |
Player feet Y coordinate. |
getZ() |
double |
Player feet Z coordinate. |
getEyeY() |
double |
Player eye-level Y (getY() + eyeHeight). |
getYaw() |
float |
Horizontal rotation (degrees, Minecraft convention). |
getPitch() |
float |
Vertical rotation (degrees). |
getVelocityX/Y/Z() |
double |
Per-axis velocity in blocks per tick. |
isOnGround() |
boolean |
True if standing on a solid surface. |
isSprinting() |
boolean |
True if the sprint flag is set. |
isSneaking() |
boolean |
True if sneaking/crouching. |
isSwimming() |
boolean |
True if in swim animation. |
isFlying() |
boolean |
True if creative flight is active. |
isCreativeFlightEnabled() |
boolean |
True if the player has fly ability (creative/spectator). |
isSubmergedInWater() |
boolean |
True if fully submerged. |
isInLava() |
boolean |
True if touching lava. |
| Method | Returns | Description |
|---|---|---|
getHealth() |
float |
Current health points (typically 0–20). |
getMaxHealth() |
float |
Maximum health points. |
getAbsorptionAmount() |
float |
Absorption (yellow hearts) amount. |
getFoodLevel() |
int |
Hunger level (0–20). |
getSaturation() |
float |
Saturation level. |
getAir() |
int |
Remaining air ticks (max 300). |
getMaxAir() |
int |
Maximum air ticks (typically 300). |
| Method | Returns | Description |
|---|---|---|
getXpLevel() |
int |
Current XP level. |
getXpProgress() |
float |
Progress toward next level (0.0–1.0). |
getTotalXp() |
int |
Total accumulated XP points. |
| Method | Returns | Description |
|---|---|---|
getName() |
String |
Player's Minecraft username. |
getUuid() |
String |
Player's UUID as a string. |
getGameMode() |
String |
"SURVIVAL", "CREATIVE", "ADVENTURE", "SPECTATOR", or "UNKNOWN". |
getHeldItem() |
ItemSnapshot |
Snapshot of the main-hand item. |
getOffhandItem() |
ItemSnapshot |
Snapshot of the off-hand item. |
getActiveEffects() |
List<EffectSnapshot> |
All active status effects. |
hasEffect(String idSubstring) |
boolean |
True if any active effect's ID contains the substring (case-insensitive). |
isInWorld() |
boolean |
True if the player entity exists in a loaded world. Use this as a guard at the top of tick handlers. |
isScreenOpen() |
boolean |
True if any GUI screen is open (inventory, chest, chat, etc.). |
InventoryInfoRead inventory contents. Never modifies anything.
Inventory slot layout:
| Range | Contents |
|---|---|
| 0–8 | Hotbar |
| 9–35 | Main storage |
| 36 | Head armour |
| 37 | Chest armour |
| 38 | Leg armour |
| 39 | Feet armour |
| 40 | Off-hand |
| Method | Returns | Description |
|---|---|---|
getSelectedSlot() |
int |
Currently selected hotbar slot (0–8). |
getHotbarSlot(int slot) |
ItemSnapshot |
Snapshot of one hotbar slot. |
getHotbar() |
List<ItemSnapshot> |
Snapshots of all 9 hotbar slots. |
getHotbarSnapshot() |
List<ItemSnapshot> |
Identical to getHotbar(). Intended for change-detection by comparing with .equals(). |
hasItemInHotbar(String displayName) |
boolean |
True if any hotbar slot has an item matching the display name (case-insensitive exact match). |
hasItemIdInHotbar(String idSubstring) |
boolean |
True if any hotbar slot has an item whose ID contains the substring. |
findHotbarSlotByName(String displayName) |
int |
First matching slot index, or -1. |
findHotbarSlotById(String idSubstring) |
int |
First matching slot index by item ID, or -1. |
| Method | Returns | Description |
|---|---|---|
getMainSlot(int slot) |
ItemSnapshot |
Snapshot of any slot 0–35. |
getMainInventory() |
List<ItemSnapshot> |
All 36 main inventory slots. |
countByName(String displayName) |
int |
Total item count matching display name across all 36 slots. |
countById(String idSubstring) |
int |
Total item count matching ID substring across all 36 slots. |
hasEmptySlot() |
boolean |
True if at least one main inventory slot is empty. |
emptySlotCount() |
int |
Number of empty slots in the main inventory. |
| Method | Returns | Description |
|---|---|---|
getArmorSlot(int armorIndex) |
ItemSnapshot |
0=head, 1=chest, 2=legs, 3=feet. |
getArmor() |
List<ItemSnapshot> |
All 4 armour slots in order (head → feet). |
getOffhandItem() |
ItemSnapshot |
Off-hand slot (slot 40). |
WorldInfoQuery the current world/dimension.
| Method | Returns | Description |
|---|---|---|
getDimensionId() |
String |
e.g. "minecraft:overworld", "minecraft:the_nether". |
isInOverworld() |
boolean |
|
isInNether() |
boolean |
|
isInEnd() |
boolean |
|
getServerAddress() |
String |
Hostname:port of the server, "local" for singleplayer, "none" if not connected. |
isSinglePlayer() |
boolean |
True if singleplayer or LAN. |
isWorldLoaded() |
boolean |
True if a world is currently loaded client-side. |
| Method | Returns | Description |
|---|---|---|
getTimeOfDay() |
long |
Ticks into the current day (0–24000). Day starts at 0, night at ~13000. |
getWorldAge() |
long |
Total world age in ticks (never resets). |
isDay() |
boolean |
True if time < 13000. |
isNight() |
boolean |
Inverse of isDay(). |
| Method | Returns | Description |
|---|---|---|
isRaining() |
boolean |
|
isThundering() |
boolean |
| Method | Returns | Description |
|---|---|---|
getBlockId(int x, int y, int z) |
String |
Namespaced block ID, e.g. "minecraft:grass_block". Returns "minecraft:air" if unloaded. |
getBlockIdRelative(int dx, int dy, int dz) |
String |
Block ID at an offset from the player's feet. |
isAir(int x, int y, int z) |
boolean |
True if the block is air. |
getSkyLight(int x, int y, int z) |
int |
Sky light level 0–15. |
getBlockLight(int x, int y, int z) |
int |
Block light level 0–15. |
getLight(int x, int y, int z) |
int |
Max of sky and block light. |
isChunkLoaded(int x, int z) |
boolean |
True if the chunk at world coords x,z is loaded. |
getBiomeId() |
String |
Biome at the player's current position. |
| Method | Returns | Description |
|---|---|---|
getNearbyEntities(double radius) |
List<EntitySnapshot> |
All living entities within radius of the player. Excludes self. Uses a bounding-box search. |
getNearbyPlayers(double radius) |
List<EntitySnapshot> |
Other player entities within radius. |
getNearbyEntitiesMatching(double radius, Predicate<EntitySnapshot> filter) |
List<EntitySnapshot> |
Filtered version of getNearbyEntities. |
getEntityAtCrosshair() |
Optional<EntitySnapshot> |
Entity under the crosshair (Minecraft's raycast target), or empty. |
getBlockAtCrosshair() |
Optional<BlockSnapshot> |
Block under the crosshair, or empty. Includes all block-state properties. |
getEntityNbt(int entityId) |
Map<String, String> |
Entity NBT as a flat string map. Currently returns an empty map — see Known Limitations. |
// Find all wheat crops within 10 blocks:
List<BlockSnapshot> wheat = WorldInfo.getNearbyBlocks(10.0, "minecraft:wheat");
// Custom filter — mature crops only:
List<BlockSnapshot> matureWheat = WorldInfo.getNearbyBlocksMatching(10.0,
b -> b.blockId().equals("minecraft:wheat") && b.stateEquals("age", "7"));
Performance: getNearbyBlocks and getNearbyBlocksMatching scan a full sphere. Keep radius ≤ 32 to avoid frame drops. The scan is O(r³).
TabListInfoQuery the tab-list player list. Servers use display names in the tab list to show sidebar information (scores, status text, etc.).
All methods call MinecraftClient.getNetworkHandler().getPlayerList() and return safe defaults when not connected.
Note on text stripping: Display names in the tab list are Minecraft Text objects. getAllLines() and search methods strip all formatting codes (colours, bold, etc.) and return plain strings. To inspect formatting (e.g. detect strikethrough), use isLineStrikethrough().
getAllLines() → List<String>Returns all tab-list display-name strings, stripped of colour codes. Ordered by score (descending) then by username.
getAllLinesRaw() → List<String>Returns all tab-list display-name strings. Intended for raw inspection, though note that Text.getString() in Fabric already strips §-style codes. Useful primarily to iterate PlayerListEntry objects when combined with other methods.
findLineWithPrefix(String prefix) → StringReturns the first stripped tab-list line that starts with prefix, or null.
String line = TabListInfo.findLineWithPrefix("Area:");
// → "Area: Garden"
findLinesWithPrefix(String prefix) → List<String>Returns all stripped lines starting with prefix.
findLineContaining(String substring) → StringReturns the first stripped tab-list line that contains substring (case-insensitive), or null.
String line = TabListInfo.findLineContaining("Alive:");
// → " Alive: 3 pests"
findLinesContaining(String substring) → List<String>Returns all stripped lines containing substring (case-insensitive).
isLineStrikethrough(String substring) → booleanReturns true if the first tab-list line containing substring has strikethrough styling applied to any of its text segments. Uses Text.visit() to walk the Style tree — the only reliable way to detect strikethrough since getString() strips all formatting.
// Detect a disabled/crossed-out line:
if (TabListInfo.isLineStrikethrough("Bonus Pest Chance:")) {
// line is crossed out → bonus is disabled
}
extractValueAfterPrefix(String prefix) → StringFind the first line starting with prefix and return the text after the prefix, trimmed. Returns null if not found.
String area = TabListInfo.extractValueAfterPrefix("Area:"); // → "Garden"
parseKeyValueLines(String... prefixes) → Map<String, String>Extract multiple key-value pairs in one call. Returns a map of prefix → value (or null if not found).
Map<String, String> data = TabListInfo.parseKeyValueLines("Area:", " Alive:", " Repellent:");
String area = data.get("Area:");
String alive = data.get(" Alive:");
extractInt(String pre