A client-side Fabric mod that automates crop farming — follow a recorded waypoint path, hold the attack key to break crops, manage Pest Repellent automatically, and monitor a live dashboard of farming metrics.
Named after the Roman goddess of agriculture.
GitHub: https://github.com/noname-mods/Ceres
Requires PlayerAPI and YetAnotherConfigLib to run.
ModMenu is optional — it adds a settings button to the mod list.
Ceres follows a sequence of recorded waypoints while holding the attack key to break crops. Two independent path slots (Primary and Secondary) let you define separate routes — for example an outward pass and a return pass. Each path has its own sprint toggle. Paths are recorded in-game by walking your route and pressing "Add Here" in the Path Editor.
When you start the bot, Ceres reads your held tool's display name and loads the matching crop profile automatically. A Wheat Hoe loads your Wheat profile; a Carrot Hoe loads Carrot — even reforged tools work because matching is substring-based. Profiles save the full path configuration (both slots + sprint settings) as named files you can switch between at any time.
Four independent monitors run continuously while farming:
| Checker | Behaviour |
|---|---|
| Inventory | Watches your hotbar for item changes. If nothing moves for 6 seconds the bot assumes it is stuck and stops. |
| Tool | Detects when your held item changes from what you started with and logs a warning. Does not stop the bot — other systems legitimately switch items. |
| Yaw / Pitch | Detects if an external force rotates the camera unexpectedly. Plays an alert sound and shows a title overlay but keeps farming — the bot is still running. |
| Pest | Reads the live pest count from the tab list. Plays an alert sound when it reaches your configured threshold. Does not stop the bot. |
The area check is always active regardless of checker toggles: if the tab list shows you have left the Garden, the bot stops immediately and returns full control to you.
Reads the "Repellent:" timer from the Hypixel tab list. When it reads "None", Ceres pauses the bot, switches to the repellent in your hotbar, uses it, waits for the tab list to update, and resumes farming — all without you touching anything. Works with all repellent tiers.
A configurable overlay panel shows up to 14 live rows of farming data pulled directly from the Hypixel tab list:
Every row can be individually shown or hidden in the config screen. A small log panel below the main HUD shows the last 5 bot messages.
Ceres counts every crop block broken and keeps a rolling 30-second window. The live BPS figure in the HUD reflects your actual throughput, giving you a consistent number to compare across paths and crops.
All settings are exposed through a YACL config screen with seven tabs. Open it from ModMenu, the /ceres command, or a keybind. No file editing required.
All keybinds are rebindable in Options → Controls → Ceres.
| Action | Default Key |
|---|---|
| Start Primary Path | O |
| Start Secondary Path | U |
| Pause | P |
| Resume | J |
| Stop | K |
| Toggle HUD | ; |
| Open Path Editor | I |
| Open Config | (unbound) |
Type /ceres in chat to open the config screen directly.
ceres-*.jar into your mods folder| Minecraft | Fabric Loader | Java |
|---|---|---|
| 26.1.2 | ≥ 0.19.2 | 21 |
This mod 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.
The in-game update checker is Minecraft-version aware: if the latest release targets a different Minecraft version than you're running, it tells you so instead of prompting you to install an incompatible build.
Version: 1.1.2
Minecraft: 26.1.2 (Fabric)
Depends on: PlayerAPI 1.12.0+
Read this first if you are a new Claude Code session working in this folder.
Ceres is a client-side farming automation bot for Hypixel Skyblock. It moves the player along a pre-recorded waypoint path, holds the attack key to break crops, auto-uses Pest Repellent, monitors safety conditions, and displays a live HUD. It is built entirely on top of PlayerAPI and never imports Minecraft internals directly.
| Dependency | Version field | Location |
|---|---|---|
| PlayerAPI | playerapi_version in gradle.properties |
C:\Users\willi\Documents\completeMods\PlayerAPI |
Build order: If you changed PlayerAPI, run ./gradlew publishToMavenLocal there first, then build Ceres.
src/main/java/com/ceres/
├── CeresMod.java — entry point, event wiring, keybind handling
├── core/
│ ├── BotState.java — enum: STOPPED / PAUSED / RUNNING
│ ├── BotStateManager.java — THE central singleton: all live state, tab list data, BPS tracking
│ ├── BotConfig.java — all persistent settings, JSON config, versioned migrations
│ └── BotLogger.java — ring-buffer logger + file output
├── path/
│ ├── Waypoint.java — record(x, y, z, pathType)
│ ├── PathType.java — enum: PRIMARY / SECONDARY / EVACUATION
│ ├── PathConfig.java — the in-memory path model (waypoints + loop flag)
│ ├── PathManager.java — walks the path each tick (movement + attack)
│ ├── ProfileManager.java — loads/saves named .json profile files
│ └── CropToolMapper.java — maps tool item IDs → profile names (auto-load)
├── tablist/
│ └── CeresTabListReader.java — parses Hypixel tab list each tick → BotStateManager fields
├── checkers/
│ ├── CheckerController.java — orchestrates all checkers, random reset interval
│ ├── InventoryChecker.java — detects stalled inventory (crops not changing)
│ ├── ToolChecker.java — verifies correct tool is held
│ ├── YawPitchChecker.java — detects unexpected look direction changes
│ └── PestChecker.java — stops bot when pest count reaches threshold
├── repellent/
│ └── PestRepellentManager.java — detects repellent expiry, auto-uses from inventory
└── gui/
├── BotHudRenderer.java — all HUD rendering (main panel + log panel)
├── CeresConfigScreen.java — YACL config screen (5 tabs)
└── PathEditorScreen.java — path recording/editing GUI
<game>/config/ceres/)| File | Contents |
|---|---|
config.json |
All BotConfig settings (schema versioned, auto-migrated) |
paths.json |
The active waypoint data (Primary + Secondary + Evacuation paths) |
profiles/<name>.json |
One file per saved profile (same format as paths.json) |
ceres.log |
Appended log output |
When adding a new config field that defaults to true (boolean), you must add a migration step — GSON defaults missing booleans to false. Pattern:
CURRENT_VERSIONmigrateVn() methodmigrate()load()If INSTANCE needs to iterate a new static list in the constructor, declare the list before INSTANCE in the class — static fields initialise in declaration order and a NullPointerException will result otherwise (this was a real bug).
"profile", "area", "xyz", "look", "pests", "plots", "spray", "repellent", "bonus", "cooldown", "pest_chance", "path", "bps", "target"
These keys are the source of truth. BotConfig.ALL_HUD_LINES is the authoritative list. The config screen, HUD renderer, and migration all derive from it.
Ceres currently uses PlayerAPI 1.12.0. Key additions in recent versions used here:
TabListInfo.isLineStrikethrough(String substring) — used to detect the crossed-out "Bonus Pest Chance" linePlayerAPIEvents.BLOCK_BROKEN — used for BPS (blocks per second) trackingSoundActions.playByIdRepeated() — used for all alarm soundsUpdateChecker — shared update checker (1.12.0); replaced Ceres's own copyDisplayActions — not used in Ceres (used in Poseidon)Adding a new HUD row:
BotConfig.ALL_HUD_LINESBotConfig.CURRENT_VERSION and add a migrationCeresConfigScreen (use the hudLineOption() helper)BotHudRenderer (gate it with cfg.isHudLineVisible("key"))CeresTabListReader and a field + getter in BotStateManagerAdding a new config setting:
BotConfigBotConfig.load()CeresConfigScreenChanging tab list parsing:
CeresTabListReader.javaBotStateManager via settersTabListInfo is the PlayerAPI class used (static methods, no instantiation)Ceres never imports net.minecraft.* except in BotHudRenderer (rendering only) and CeresMod (keybind registration + Fabric hooks). All player interaction, world queries, and scheduling go through PlayerAPI classes.
Ceres is a client-side Fabric farming automation mod for Minecraft 26.1.2. It moves the player along a pre-recorded path, holds the attack key to break crops, and manages a suite of supporting systems: repellent auto-use, safety checkers, a live HUD overlay, and a GUI for editing paths and configuration.
Ceres is built entirely on top of PlayerAPI — it never imports Minecraft internals directly. All player movement, inventory access, interaction, and world queries go through PlayerAPI's abstraction layer.
What Ceres does:
What Ceres does not do:
CeresMod (entry point)
│
├── onTick() — called every tick via PlayerAPIEvents.TICK
│ ├── CeresTabListReader.update() — pull tab list data into state
│ ├── PestRepellentManager.tick() — check and apply repellent
│ ├── PathManager.tick() [RUNNING] — advance waypoint following
│ ├── CheckerController.tick() [RUNNING] — run all safety checkers
│ ├── MovementActions.pressKey("attack") — heartbeat, every 20 ticks
│ └── handleKeybinds() — process key presses
│
├── BotStateManager (singleton) — single source of truth for all runtime state
│
├── BotConfig (singleton) — persistent settings (config.json)
│
├── PathConfig (singleton) — persistent waypoints (paths.json)
│
├── ProfileManager — named profiles (profiles/<name>.json)
│
├── BotHudRenderer — HUD overlay drawn via HudRenderCallback
│
├── CeresConfigScreen — YACL config GUI (/ceres)
│
├── PathEditorScreen — waypoint editor GUI (I key)
│
└── BotLogger — in-memory ring buffer + file log
PlayerAPIEvents.TICK (main game thread, every tick)
│
├─ CeresTabListReader.update()
│ Reads all tab-list lines → pushes values into BotStateManager
│
├─ PestRepellentManager.tick()
│ If repellent timer = "None" and cooldown elapsed → pause bot, apply, resume
│
├─ [if RUNNING] PathManager.tick()
│ Advance toward next waypoint; at each cycle end: loop or stop+alert
│
├─ [if RUNNING] CheckerController.tick()
│ Every 60–100 ticks: reset checker baselines
│ Between resets: run all four checkers
│
├─ [if RUNNING] pressKey("attack") every 20 ticks
│ Heartbeat to prevent the attack key from being dropped
│
├─ [if PAUSED] releaseAll()
│ Safety: ensure no movement keys are held while paused
│
└─ handleKeybinds()
Process any keybind presses from this tick
playerapi-1.12.0.jar in your mods folder.ceres-1.1.1.jar in your mods folder.Ceres generates its config files in .minecraft/config/ceres/ on first launch.
All Ceres data lives in .minecraft/config/ceres/:
| File / Directory | Contents |
|---|---|
config.json |
All bot settings (schema versioned, auto-migrated). |
paths.json |
The currently loaded waypoints for Primary and Secondary paths. |
alias.json |
Command aliases (name → command string map). |
ceres.log |
Append-only log file. All INFO/WARN/ERROR messages land here. |
profiles/ |
Directory of named profile files, one .json per profile. |
profiles/<name>.json |
A profile: waypoints + sprint settings for both path types. |
Profiles are completely separate from paths.json. Loading a profile in the Path Editor copies its data into the live edit buffer. Clicking Done saves that buffer to paths.json. If you close the editor without clicking Done, changes are discarded and paths.json is unchanged.
The bot is always in one of three states, tracked by BotStateManager.getCurrentState():
STOPPED ──startBot()──► RUNNING ──pauseBot()──► PAUSED
▲ │ │
└──────stopBot()──────────┘◄──resumeBot()────────┘
startBot(PathType) performs these actions in order:
checksBypassed is set).MovementActions.setActive(true).stopBot() performs these actions:
MovementActions.setActive(false).Scheduler.cancelAll() — clears all pending scheduled tasks.When the bot is started via the O (Primary) or U (Secondary) keybind, autoLoadAndStart() runs first:
CropToolMapper.resolveProfile() to identify the held tool.BotConfig, loads the profile into PathConfig before calling startBot().PathConfig.A Waypoint is a single point the bot must reach on its path.
class Waypoint {
double x;
double y; // Y is recorded but not used for movement (2D navigation only)
double z;
List<String> forcedKeys; // which movement keys to hold between this and the next waypoint
}
forcedKeys determines exactly how the bot moves toward this waypoint:
Valid key names for forcedKeys: "forward", "back", "left", "right", "sneak", "jump". ("sprint" is handled separately by the sprint toggle.)
Waypoint reach threshold: 0.5 blocks (2D distance on X/Z plane). Y coordinate is ignored for reach detection.
There are exactly two path types:
| Enum value | Default keybind | Typical use |
|---|---|---|
PRIMARY |
O | Main farming route |
SECONDARY |
U | Secondary or return route |
Each path type has its own independent waypoint list and sprint setting in PathConfig.
Stores the currently active waypoint lists. Persisted to config/ceres/paths.json.
{
"version": 2,
"sprint": {
"PRIMARY": true,
"SECONDARY": false
},
"paths": {
"PRIMARY": [
{ "x": 100.5, "y": 64.0, "z": -200.5, "forcedKeys": ["forward"] },
{ "x": 110.5, "y": 64.0, "z": -200.5, "forcedKeys": ["forward"] }
],
"SECONDARY": []
}
}
PathConfig is the live file the bot actually runs from. Profiles are separate — loading a profile copies data into PathConfig only when you press Done in the Path Editor.
Drives movement every tick while the bot is RUNNING.
Waypoint following loop:
tick()
→ if not yet following: startPathFollowing()
→ if messUpTimer > 0: release all keys, count down (anti-detection pause)
→ otherwise: followPathStep()
→ compute 2D distance to current waypoint
→ if within 0.5 blocks: advance index, log "reached waypoint N"
→ else: apply forcedKeys (+ sprint if enabled)
→ attemptMessUp(): ~1/180,000 chance each tick of a 10–30 tick pause
Cycle completion (index reaches end of list):
Cycle-start command: A command (default: "warp garden") sent at the start of every cycle (including the first) and after every loop reset. Sent with a 5-tick delay to allow state to settle. The leading / is stripped if accidentally included.
Sprint: Applied on top of forcedKeys when PathConfig.isSprintEnabled(currentPathType) is true. Sprint is per-path and toggled independently for Primary and Secondary.
Sneak on path start: If BotConfig.isSneakOnPathStart() is true, the bot briefly presses sneak for 5 ticks (250 ms) at the start of each path to snap orientation before moving.
Manages named profiles saved in config/ceres/profiles/.
A profile contains:
Profiles are identified by filename (without the .json extension). File names are sanitised — any characters in \ / : * ? " < > | are replaced with underscores.
Profile operations:
| Operation | Result |
|---|---|
| Save profile | Writes current editor state to profiles/<name>.json. Does not touch paths.json. |
| Load profile | Reads profiles/<name>.json, returns a ProfileData record. Caller applies it to PathConfig. |
| Delete profile | Deletes profiles/<name>.json. |
| List profiles | Returns alphabetically sorted list of all .json filenames in the profiles directory. |
| Open profiles folder | Opens the OS file browser to the profiles directory. |
Profile file format:
{
"version": 2,
"sprint": { "PRIMARY": true, "SECONDARY": false },
"paths": {
"PRIMARY": [ { "x": 100.0, "y": 64.0, "z": -200.0, "forcedKeys": ["forward"] } ],
"SECONDARY": []
}
}
Maps the player's held tool display name to a profile name. Used only at bot start by autoLoadAndStart().
Matching is substring-based and case-insensitive. The key fragment (e.g. "wheat hoe") only needs to appear somewhere in the full display name, so reforged or tiered items like "Blessed Euclid's Wheat Hoe Mk. II" are matched correctly.
Full tool → profile mapping:
| Tool name substring | Resolves to profile |
|---|---|
"cactus knife" |
Cactus |
"carrot hoe" |
Carrot |
"cocoa chopper" |
Cocoa Beans |
"fungi cutter" |
Mushroom |
"melon dicer" |
Melon |
"nether wart hoe" |
Nether Wart |
"potato hoe" |
Potato |
"pumpkin dicer" |
Pumpkin |
"sugar cane hoe" |
Sugarcane |
"wheat hoe" |
Wheat |
"wild rose hoe" |
Wild Rose |
"eclipse hoe" |
see below |
Eclipse Hoe special case: The Eclipse Hoe is used for both Sunflower and Moonflower (they are the same plant but flower at different times of day). Resolution priority:
Sunflower and Moonflower profiles exist on disk → resolves to "Sunflower".null (no auto-load; bot starts with current paths).ALL_CROPS — the complete list of profile names CropToolMapper can resolve to, in alphabetical order. Used by BotConfig to build the per-crop toggle storage and by the config screen to build the UI:
Cactus, Carrot, Cocoa Beans, Melon, Moonflower, Mushroom,
Nether Wart, Potato, Pumpkin, Sugarcane, Sunflower, Wheat, Wild Rose
All checkers are coordinated by CheckerController. They only run while the bot is RUNNING. Each checker can individually be enabled/disabled in BotConfig.
Runs every tick while RUNNING. Operates in two phases that alternate on a 60–100 tick (3–5 second) random interval:
Reset phase: Snapshots the current player state as the new baseline for all checkers. Randomised interval prevents detectable patterns.
Check phase: Runs all four checkers against the current state. Each checker returns true (OK) or false (problem).
Area check (always on, regardless of checker toggles): If the tab-list area is known (non-empty) and is not "Garden", the bot stops and plays the stop alert sound immediately. This is the only hard-stop that cannot be bypassed through checker toggles.
Bypass mode: If BotStateManager.isChecksBypassed() is true, the entire checker tick is skipped. This is useful during development and path-recording. Not exposed in the standard config screen — toggle programmatically or via debug commands.
Purpose: Detect when the bot has become stuck — if no items are entering or leaving the hotbar for 6 seconds (120 ticks), farming has likely stopped.
How it works:
ItemSnapshot list).On failure: Stops the bot and plays the stop alert sound.
Important: The 120-tick window is checked against the last change, not the last reset. If inventory changes frequently but then freezes, the checker correctly triggers after 6 seconds of no change — even if a reset happened recently.
Purpose: Detect if the player's held item changed from what was held when the bot started.
How it works:
BotStateManager.getInitialTool() (the display name of the held item when startBot() was called).On failure: Logs a warning and continues. Does not stop the bot. This is intentional — other systems (including the Repellent Manager) legitimately switch items, and the bot should continue farming regardless.
Purpose: Detect if an external force (another mod, a player, or server-side teleportation) has changed the player's look direction unexpectedly.
How it works:
On failure: Shows a screen title (§c⚠ LOOK CHANGED / §eBot is still running) and plays the warn alert sound. Does not stop the bot — farming continues uninterrupted. The purpose is to alert the player so they can manually intervene if needed.
Purpose: Alert when the live pest count from the tab list reaches the configured minimum threshold.
How it works:
BotStateManager.getPestCount() and compares to BotConfig.getMinPestCount().pestCount >= minPestCount, returns false.On failure: Plays the warn alert sound. Does not stop the bot. The alert is informational — it is up to the player to decide whether to stop and deal with the pests.
Automatically applies Pest Repellent when it expires. Runs every tick regardless of bot state (RUNNING, PAUSED, or STOPPED — but not when STOPPED).
Detection trigger: Watches BotStateManager.getPestRepellentTimerText(). When this value equals "None" (case-insensitive, trimmed), repellent has expired.
Cooldown: 1200 ticks (60 seconds) minimum between applications. This prevents rapid re-application if the tab list is slow to update after the repellent is used.
Application sequence:
"Pest Repellent" (matches all tiers: I, II, MAX, etc.). If not found, log a warning, skip, and resume.While applying: isApplying flag blocks any re-entrant application during the 1200-tick wait window.
Enable/disable: Controlled by BotConfig.isRepellentReapplyEnabled(). When disabled, the entire manager tick is a no-op.
CeresTabListReader.update() is called every tick. It reads specific lines from the tab list using PlayerAPI's TabListInfo and pushes values into BotStateManager. All values are stored as strings (or integers for pest count) with the prefix stripped.
Parsed lines:
| Tab list prefix | BotStateManager field | Notes |
|---|---|---|
"Area:" |
currentArea |
Not cleared if line disappears — retains last known area. |
"Alive:" |
pestCount (int) |
Parses the first integer from the value. |
"Plots:" |
plotsText |
Cleared to "" if line is absent. |
"Spray:" |
sprayText |
Cleared to "" if line is absent. |
"Repellent:" |
pestRepellentTimerText |
Cleared to "" if line is absent. |
"Bonus:" |
bonusText |
Cleared to "" if line is absent. |
"Cooldown:" |
sprayCooldownText |
Cleared to "" if line is absent. |
"Bonus Pest Chance:" |
bonusPestChanceText |
If line has strikethrough styling → stores "DISABLED". Otherwise stores the value (e.g. "217"). Cleared to "" if absent. |
Strikethrough detection for Bonus Pest Chance: Uses TabListInfo.isLineStrikethrough() which walks the Minecraft Text object's style tree via text.visit(). This is the only reliable method — getString() strips all formatting including strikethrough.
Area retention: Unlike the other fields, currentArea is not cleared when the "Area:" line disappears. This prevents false-positive area-check failures during brief tab-list gaps.
BotStateManager is the single source of truth for all runtime state. It is a singleton accessed via BotStateManager.getInstance().
| Method | Description |
|---|---|
startBot(PathType) |
Start the bot on the given path type. Validates area unless bypassed. Clears BPS data and records run start tick. |
pauseBot() |
Pause if currently RUNNING. Releases all keys. Clears BPS data. |
resumeBot() |
Resume if currently PAUSED. Re-presses attack key. Resets BPS window. |
stopBot() |
Stop unconditionally. Releases all keys, cancels all scheduled tasks, clears BPS data. |
| Field | Type | Description |
|---|---|---|
currentState |
BotState |
RUNNING / PAUSED / STOPPED. |
currentPathType |
PathType |
Which path type is active (PRIMARY or SECONDARY). |
isFollowingPath |
boolean |
True once PathManager has started following (set false on stop). |
currentPathIndex |
int |
Index of the next waypoint to reach. |
currentPath |
List<Waypoint> |
Copy of the active waypoint list (or null when stopped). |
currentArea |
String |
Last known area from the tab list. |
pestCount |
int |
Live pest count from "Alive:" tab line. |
plotsText |
String |
Value of "Plots:" tab line, or "". |
sprayText |
String |
Value of "Spray:" tab line, or "". |
pestRepellentTimerText |
String |
Value of "Repellent:" tab line, or "". |
bonusText |
String |
Value of "Bonus:" tab line, or "". |
sprayCooldownText |
String |
Value of "Cooldown:" tab line, or "". |
bonusPestChanceText |
String |
Value of "Bonus Pest Chance:" line — a number, "DISABLED", or "". |
guiVisible |
boolean |
Whether the HUD overlay is shown. |
checksBypassed |
boolean |
Whether all checkers are skipped. |
checkFailed |
boolean |
Set when a hard-stop checker triggers. |
initialTool |
String |
Display name of the held item when startBot() was called. |
activeProfileName |
String |
Name of the last named profile loaded ("Custom" if paths were edited manually or no profile was loaded). |
The BPS system uses a 30-second sliding window of block-break timestamps:
recordBlockBroken(long tick) — called from CeresMod whenever PlayerAPIEvents.BLOCK_BROKEN fires while in RUNNING state. Adds the tick to a deque and prunes entries older than 600 ticks.getBlocksPerSecond() — returns the rolling BPS. The divisor is min(elapsed seconds since run start, 30) rather than always 30, so early readings are accurate instead of artificially low.startBot(), pauseBot(), and stopBot(), and reset (fresh window) on resumeBot(). This ensures each continuous run session is measured independently.BotConfig persists to config/ceres/config.json. Schema version 4. All migrations run automatically — old config files are upgraded transparently.
| Version | Change |
|---|---|
| 0 | Initial release (no version field). |
| 1 | repeatCount (int, plays) → durationSeconds (int, seconds) in alarm sounds. |
| 2 | Added autoLoadEnabled and autoLoadCrops (all default true). |
| 3 | Added hudLines per-row visibility map (all default true). |
| 4 | Added updateCheckEnabled (defaults true). |
| Setting | Type | Default | Description |
|---|---|---|---|
minPestCount |
int |
4 |
Pest count threshold for the PestChecker alert. Alert fires when pestCount >= minPestCount. |
logLevel |
int |
2 (WARN) |
Minimum severity to log. 1=ERROR, 2=WARN, 3=INFO, 4=DEBUG. |
sneakOnPathStart |
boolean |
true |
If true, sneak is pressed for 250 ms at the start of each path to snap orientation. |
repellentReapplyEnabled |
boolean |
true |
If false, the repellent manager is entirely disabled. |
oneCycleMode |
boolean |
false |
If true, the bot stops and plays the cycle-complete alarm after one full pass instead of looping. |
cycleRestartCommand |
String |
"warp garden" |
Command sent (without /) at the start of every cycle. Leave blank to disable. |
| Setting | Default | Description |
|---|---|---|
inventoryCheckerEnabled |
true |
Enable the inventory change detector (stuck detector). |
toolCheckerEnabled |
true |
Enable the held-item change monitor. |
yawPitchCheckerEnabled |
true |
Enable the look-direction drift monitor. |
pestCheckerEnabled |
true |
Enable the pest count threshold alert. |
Three independent alarm sound configurations, each with five sub-fields:
| Alarm | Trigger |
|---|---|
cycleCompleteSound |
One-Cycle Mode finishes. |
stopAlertSound |
InventoryChecker hard-stops the bot, or area check fails. |
warnAlertSound |
YawPitchChecker detects look change, or PestChecker threshold reached. |
Each alarm has:
| Sub-field | Type | Description |
|---|---|---|
soundId |
String |
Minecraft sound ID, e.g. "entity.player.levelup". Namespace minecraft: is optional. Browse at https://misode.github.io/sounds/ |
volume |
double |
0.1–2.0 (1.0 = normal). |
pitch |
double |
0.5–2.0 (1.0 = normal pitch/speed). |
durationSeconds |
int |
Total alarm duration in seconds (sound repeats for this long). Set 0 to play once. |
intervalTicks |
int |
Ticks between each repeat play (20 ticks = 1 second). |
Defaults:
| Alarm | soundId | volume | pitch | durationSeconds | intervalTicks |
|---|---|---|---|---|---|
| Cycle Complete | entity.player.levelup |
1.0 | 1.0 | 10 | 20 |
| Stop Alert | entity.player.levelup |
1.0 | 1.0 | 10 | 20 |
| Warn Alert | entity.experience_orb.pickup |
1.0 | 1.5 | 5 | 15 |
| Setting | Type | Default | Description |
|---|---|---|---|
autoLoadEnabled |
boolean |
true |
Master toggle. When false, no profile is auto-loaded regardless of per-crop settings. |
autoLoadCrops |
Map<String, Boolean> |
all true |
Per-crop enable. Keys are the 13 profile names from CropToolMapper.ALL_CROPS. |
| Setting | Type | Default | Description |
|---|---|---|---|
hudLines |
Map<String, Boolean> |
all true |
Per-row visibility. See HUD Overlay for key names. |
| Setting | Type | Default | Description |
|---|---|---|---|
updateCheckEnabled |
boolean |
true |
On every world join, Ceres contacts GitHub to check for a newer release. If one is found, a single chat message is shown with the version and a link. Nothing is downloaded automatically. Disable if you are offline, on a restricted network, or do not want the notification. |
| Setting | Type | Default | Description |
|---|---|---|---|
bypassAreaCheck |
boolean |
false |
If true, startBot() skips the area validation. Useful for testing paths outside the farming area. |
microLookEnabled |
boolean |
false |
Enables HumanProfile.enableMicroLook for subtle idle camera drift. |
debugMode |
boolean |
false |
Prints extra diagnostic messages (useful for diagnosing /ceres command interception issues). |
The HUD is a small overlay panel drawn in the top-left corner when the HUD is visible (toggled with the ; key by default). Each row can be individually hidden in the HUD Lines config tab.
The panel has a coloured left accent bar showing the current bot state:
The header shows "Ceres" on the left and the state name on the right, in the state colour.
Rows, in order:
| Row label | Config key | Always shown? | Description |
|---|---|---|---|
| Profile | "profile" |
Yes | Name of the currently loaded profile. Shows "Custom" if paths were edited manually or no named profile was loaded this session. |
| Area | "area" |
Yes | Current area from the tab list. Shows "Unknown" if no area has been received yet. |
| XYZ | "xyz" |
Yes | Player coordinates formatted as X / Y / Z (1 decimal place). |
| Look | "look" |
Yes | Yaw and pitch. Yaw is wrapped to [−180, 180]. Format: Y 45.0 P -10.0. |
| Pests | "pests" |
Yes | Live pest count vs. the alarm threshold. Colour: red if count >= threshold, green if below. |
| Plots | "plots" |
Only when tab line present | Value from the "Plots:" tab line. Neutral colour. |
| Spray | "spray" |
Only when tab line present | Value from the "Spray:" tab line. Red if "None", green otherwise. Indicates whether the current plot has an active spray. |
| Repellent | "repellent" |
Only when tab line present | Value from the "Repellent:" tab line. Red if "None" (expired), green if a timer is showing. |
| Bonus | "bonus" |
Only when tab line present | Value from the "Bonus:" tab line. Red if "INACTIVE", green otherwise. |
| Cooldown | "cooldown" |
Only when tab line present | Pest spawn cooldown timer. Colour: green if "READY", yellow if ≤ 10 seconds remaining, red if more than 10 seconds. Useful for timing gear swaps around when a new pest can spawn. |
| Pest Ch. | "pest_chance" |
Only when tab line present | Bonus pest chance value. Dark green when active (e.g. "217"), red when "DISABLED" (line is crossed out in tab list). |
| Path | "path" |
Only when RUNNING | Path type name and waypoint progress: PRIMARY 12 / 48. |
| Bps | "bps" |
Only when RUNNING | Blocks broken per second (rolling 30-second window, dynamic early divisor). Green if > 0, grey if 0. Format: 3.4/s. |
| Target | "target" |
Only when RUNNING and has next waypoint | Coordinates of the next waypoint. Format: 100 / 64 / -200. |
The panel height is calculated dynamically based on how many rows are visible. The panel is always wide enough to show all content (210px wide, label column at offset 7, value column at offset 60 from the panel left edge).
Below the main panel, a secondary log panel shows the last 5 log lines from BotLogger. Timestamps and log level prefixes are stripped for brevity. Lines longer than 52 characters are truncated with ….
The log panel only appears when there are log entries. It uses a different background colour (#90000000) and a grey accent bar to visually distinguish it from the main panel.
In the bottom-right corner, a small panel shows the default keybind hints:
O=Primary U=Secondary
P=Pause J=Resume K=Stop
I=Paths ;=Toggle HUD
This panel is always visible when the HUD is visible, regardless of which rows are hidden.
/ceres)Opened by:
/ceres command in chat.The config screen is built with YACL (Yet Another Config Library) and has seven tabs:
CropToolMapper.ALL_CROPS)Three alarm sound groups (Cycle Complete, Stop Alert, Warn Alert), each with:
Screen opening note: The /ceres command sets a flag (CeresMod.openConfigNextTick = true) and the screen is opened on the next tick. This avoids a race condition where the chat screen closes after the command fires but before the new screen opens. If the server overrides the client command tree (preventing ClientCommandManager from intercepting /ceres), a ALLOW_COMMAND fallback catches it and sets the same flag.
Opened by the I keybind (default).
The Path Editor is a custom screen (not YACL) that lets you record, edit, and manage waypoints for both path types.
config/ceres/profiles/.forward, back, left, right, sneak, jump).Per-path sprint can be toggled in the editor. The toggle state is saved to paths.json on Done and included in profile saves.
The editor tracks whether the current state is a clean load of a named profile or has been modified:
"Custom"."Custom".Clicking Done saves the current editor state to paths.json. Sprint settings are applied first (so they are included in the save). Closing without Done discards all unsaved changes.
All bindings are in the Minecraft Controls menu under the "Ceres" category. All can be rebound or unbound.
| Action | Default Key | Description |
|---|---|---|
| Toggle HUD | ; (semicolon) |
Show/hide the HUD overlay. |
| Open Path Editor | I |
Open the waypoint editor screen. |
| Open Config | (none) | Open the config screen. |
| Start Primary | O |
Auto-load profile from held tool, then start on PRIMARY path. Requires HUD to be visible first. |
| Start Secondary | U |
Auto-load profile from held tool, then start on SECONDARY path. Requires HUD to be visible first. |
| Pause Bot | P |
Pause the bot (releases all movement keys). |
| Resume Bot | J |
Resume from pause (re-presses attack key). |
| Stop Bot | K |
Stop the bot entirely. |
Start requires HUD visible: If you press Start Primary or Start Secondary while the HUD is hidden, the bot will not start and a warning is logged. This prevents accidental starts.
/ceresOpens the config screen. The command sets a flag and the screen is opened on the next tick to avoid a chat-close race condition.
If the server overrides the client command tree (preventing /ceres from being intercepted by the client), a fallback ALLOW_COMMAND listener catches the command instead, sets the same flag, and returns false to suppress the message being sent to the server. Enable Debug Mode in the config to see which path fired.
BotLogger is a singleton that writ