A client-side Fabric mod that automates rod fishing on Hypixel Skyblock — cast, wait for the bite, reel in, and recast, all with configurable human-like timing.
Named after the Greek god of the sea.
GitHub: https://github.com/noname-mods/Poseidon
Requires PlayerAPI and YetAnotherConfigLib to run.
ModMenu is optional — it adds a settings button to the mod list.
Poseidon scans nearby entities for the !!! signal the server places when your bobber gets a bite. When detected it reels in after a configurable, randomised human reaction delay so the timing never looks mechanical.
After every catch the rod is automatically recast. A configurable decision window gives server chat time to arrive before committing, so chat triggers that suppress or stop the recast always fire in time. Recast delay is independently randomisable (min/max ms) and can be disabled entirely for manual-cast mode.
Define up to 5 keyword triggers that match incoming catch messages. Each trigger can:
&d / §d codes fully supported)Triggers only fire within 10 seconds of a reel-in and are filtered to Hypixel catch-related messages (§a catch lines, §e double hook announcements, ⛃ treasure messages), so unrelated chat never causes a false trigger.
Server-message gate. Every chat alert in Poseidon — chat triggers, the reboot alert, and the Golden Fish alert — reacts only to messages from the server, never to player chat. A player typing a trigger phrase (or the Golden Fish line) in chat can't drive the bot. Signed player messages are rejected by their sender, and Hypixel-style reformatted player chat ([rank] Name: …, Guild > …, DMs) is rejected by shape.
Reads the bait from your Fishing Bag (last hotbar slot) at cast time:
Pulls Double Hook Chance, Sea Creature Chance, Fishing Speed, and Treasure Chance from the Hypixel tab list and displays them live in the HUD panel.
Detects Hypixel's scheduled-reboot server message and plays a looping alarm until you warp to a different area. The HUD accent bar turns red and a warning row appears at the top of the panel so you can't miss it.
Watches chat for the Golden Fish surface message. When it appears, Poseidon shows a golden title card, plays an alert sound, reels in any active cast, and stops the bot — handing control to you so you can catch the Golden Fish manually. Re-enable the bot afterwards to resume. The trigger phrase, title text, and sound are all configurable in the Golden Fish config tab.
After each reel-in, Poseidon scans the area for ⚓ nameplate entities. Tracked creatures are shown in the HUD and you get an alert when you hit the Hypixel cap of 10. A second alert fires when a creature approaches its despawn timer (~6 minutes) so you know to kill it before it vanishes. Nameplate entity refreshes (same creature, new ID) are detected by position and handled correctly — no false double-counts.
If the hook attaches to a moving entity, the bobber drifts away from where it landed. Poseidon detects drift beyond a configurable horizontal threshold (after a 1-second settle period), plays an alert, reels in, and optionally recasts — keeping the bot from stalling on a moving target. Auto-recast on drift is a separate toggle from the global auto-recast setting.
Delays all reel-ins for 21 seconds after each cast (11 seconds with a max-level Slug Pet equipped). Slugfish only bite after ≥ 20 seconds, so this prevents accidentally catching regular creatures while targeting the Slugfish trophy fish. The HUD shows a live countdown and turns green when the timer has elapsed.
⚠ Only enable while actively farming the Slugfish trophy fish.
After the player closes any GUI screen, the bot waits a random 0.75 – 2.5 second delay before reacting to bite signals. Instant reactions right after closing a menu look suspicious — this eliminates that pattern entirely.
An in-game overlay (default key: H) shows:
All timings, thresholds, sounds, and toggles are exposed through a YACL config screen. Open it from ModMenu, the /poseidon command, or a keybind. No file editing required.
All keybinds are rebindable in Options → Controls → Poseidon.
| Action | Default Key |
|---|---|
| Toggle Fishing | Y |
| Toggle HUD | H |
| Open Config | (unbound) |
Type /poseidon in chat to open the config screen directly.
poseidon-*.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.0 (config schema v13)
Platform: Fabric 26.1.2, Java 21
Dependencies: PlayerAPI, Fabric API, YACL v3, ModMenu (optional)
Mod ID: poseidon
Entry point: com.poseidon.PoseidonMod
Config file: <game_dir>/config/poseidon/config.json
Log file: <game_dir>/config/poseidon/poseidon.log
Poseidon is a client-side fishing automation mod designed for Hypixel Skyblock. It automates the full fishing loop:
!!! entity near the bobber)Poseidon depends on PlayerAPI for all Minecraft interaction and scheduling. It never calls Minecraft APIs directly for player input — everything goes through MovementActions, Scheduler, TabListInfo, SoundActions, PlayerAPIEvents.
PoseidonMod (entry point)
├── registers keybinds (Y, H, no-default)
├── registers /poseidon command
├── subscribes to PlayerAPIEvents.TICK → onTick()
├── subscribes to PlayerAPIEvents.CHAT_RECEIVED → onChatReceived()
├── subscribes to PlayerAPIEvents.WORLD_JOIN → onWorldJoin()
└── registers HudRenderCallback → PoseidonHudRenderer.render()
onTick() each game tick:
├── opens config screen if openConfigNextTick flag set
├── FishingManager.tick() — core state machine
├── RebootAlertManager.tick() — drives reboot alarm loop
└── handleKeybinds() — polls keybind presses
onChatReceived(sender, message):
├── RebootAlertManager.onChatReceived() — always runs
├── Guard: isInCatchWindow() — only within 10s of a reel-in
├── Guard: isCatchMessage() — §a, §e, or ⛃-prefixed only
└── iterates FishingConfig.getTriggerLevels(), first match fires
FishingManager.tick() (only when active):
├── GUI-close lock: tracks open→closed transitions, arms random delay
├── IDLE state: waits for bobber; idle watchdog retries failed recasts
├── WAITING state: runs detectBite() every tick
│ ├── bite found + guiLocked → skip (retry next tick)
│ ├── bite found + slugfish timer not elapsed → skip (retry next tick)
│ ├── bite found → saves bobber pos → BITING, schedules reel-in
│ └── no bite: updates nearbyText, runs checkHookStuck()
├── BITING state: waits for scheduled reel-in; reacts to bobber loss
└── REELING state: waits for bobber to disappear
Threading model: Everything runs on the main Minecraft client thread. PlayerAPIEvents.TICK fires on the client tick. Scheduler callbacks also execute on the client thread. The update checker uses a daemon thread for HTTP. PoseidonLogger file I/O also runs on a background thread (append mode).
com.poseidon
├── PoseidonMod.java — ClientModInitializer, event wiring, keybinds, commands
├── core/
│ ├── FishingState.java — enum: IDLE, WAITING, BITING, REELING
│ ├── FishingManager.java — singleton state machine, all fishing logic
│ ├── FishingConfig.java — singleton config, persistence, migrations
│ ├── RebootAlertManager.java — detects Hypixel reboot messages, drives alarm loop
│ └── PoseidonLogger.java — singleton logger, in-memory ring buffer + file output
├── gui/
│ ├── PoseidonHudRenderer.java — HUD overlay drawn each frame
│ └── PoseidonConfigScreen.java — YACL config screen builder
├── mixin/
│ └── MouseClickMixin.java — blocks right-click during active cast (not in GUIs)
└── modmenu/
└── PoseidonModMenuPlugin.java — ModMenu integration
com.poseidon.core.FishingState
| State | Meaning |
|---|---|
IDLE |
Bot active but no rod cast yet. No bobber present. |
WAITING |
Bobber in water. Scanning every tick for the !!! bite signal. Also watching for nearby countdown text and hook drift. |
BITING |
The !!! signal was detected. Reaction delay counting down via Scheduler. |
REELING |
The tapKey("use", 100) command has been sent. Waiting for the bobber entity to disappear. |
Transitions:
IDLE → WAITING when hasBobber becomes true
WAITING → BITING when detectBite() returns true (and all guards pass)
WAITING → IDLE if bobber disappears while watching
BITING → REELING when scheduled reel-in fires (BITING path) — or recast scheduled directly (IDLE path)
BITING → IDLE if bobber disappears before reel-in fires
REELING → IDLE after 10-tick reset (or if bobber disappears)
com.poseidon.core.FishingManager — singleton, FishingManager.getInstance()
FishingManager.getInstance().setActive(true); // start watching
FishingManager.getInstance().setActive(false); // stop, reset to IDLE
FishingManager.getInstance().toggle(); // flip active state
setActive(false) resets all flags: state → IDLE, pendingSuppressRecast, pendingStopBot, lastRecastTick, lastReelTick, castTick, guiWasOpen, guiLockUntilTick, lastBaitName, lowBaitAlertFired.
Every tick, tick() checks whether mc.currentScreen transitioned from non-null → null. On that transition a random lock duration is chosen (GUI_RESUME_MIN_TICKS=15 to GUI_RESUME_MAX_TICKS=50 ticks, ~0.75–2.5 s) and guiLockUntilTick is set. The boolean guiLocked is true while a screen is open OR within the post-close delay. The bite-detection guard checks guiLocked and returns early if true.
detectBite(MinecraftClient mc) scans a box ±detectionRadius in XZ, -1 to +detectionRadius+2 in Y around the bobber. Checks each entity for hasReelNowSignal():
entity.getCustomName().getString().contains("!!!")TextDisplayEntity.getText().getString().contains("!!!") for display entitiesscheduleReelIn() picks a random delay and calls Scheduler.scheduleMs(). The lambda handles two paths:
tapKey("use", 100), schedules creature scan and 10-tick state reset.tapKey, logs the skip, falls through to the common recast-decision tail.Both BITING and IDLE paths then schedule the recast decision after recastDecisionTicks. The decision checks pendingStopBot, pendingSuppressRecast, and cfg.isAutoRecast() in priority order.
lastRecastTick is stamped when scheduleRecast fires its tapKey. If the bot stays in IDLE more than IDLE_TIMEOUT_TICKS (100) ticks without detecting a bobber, the watchdog logs a warning and calls scheduleRecast() again. lastRecastTick is cleared when a bobber is detected (IDLE→WAITING) or on setActive(false).
castTick is stamped when the bobber is first detected (IDLE→WAITING). In the WAITING bite-detection path, if cfg.isSlugfishMode() is true and currentTick - castTick < required (420 ticks normal / 220 ticks with Slug Pet), the bite is silently ignored and the method returns. castTick is cleared on bobber loss and setActive(false).
lastReelTick is stamped when the reel-in tapKey fires. isInCatchWindow() returns true for CATCH_WINDOW_TICKS (200 ticks / 10 s) after that stamp. Used by PoseidonMod.onChatReceived() to gate trigger evaluation.
| Method | Returns |
|---|---|
isActive() |
Whether the bot is currently enabled |
getState() |
Current FishingState |
getTrackedCount() |
Number of currently tracked sea creatures |
getCurrentArea() |
Area string from tab list, or "" |
getNearbyText() |
Countdown/nearby entity text, or "" |
getBaitName() |
Current bait display name, or "" |
getBaitCount() |
Bait count from lore / stack size, or 0 |
getStatFishingSpeed() |
Fishing Speed from tab list, or "" |
getStatSeaCreatureChance() |
SCC from tab list, or "" |
getStatDoubleHookChance() |
DHC from tab list, or "" |
getStatTreasureChance() |
Treasure Chance from tab list, or "" |
getSlugfishRemainingTicks() |
Ticks until slugfish timer elapses (≤0 = ready, MIN_VALUE = mode off / no bobber) |
isInCatchWindow() |
True within 10 s of the last reel-in |
shouldBlockRightClick() |
True in WAITING/BITING state with no GUI open |
com.poseidon.core.FishingConfig — singleton, FishingConfig.getInstance()
Config stored as JSON at config/poseidon/config.json. Loaded once on init. Every setter calls save() immediately.
Detection
detectionRadius — scan box half-size for !!! (default 4.0)hookStuckDetectionEnabled (default true)hookStuckMaxDistance — drift threshold in blocks (default 1.5)hookStuckAutoRecast — recast after drift, independent of global auto-recast (default true)hookStuckSoundslugfishMode — suppress reel-ins until timer elapses (default false)slugPet — halves the slugfish timer (default false)Reaction / Recast
reactionDelayMinMs / reactionDelayMaxMsautoRecast (default true)recastDelayMinMs / recastDelayMaxMsrecastDecisionTicks (default 10)Bait Monitoring
baitHudVisible (default true)baitLowThreshold (default 5)baitLowAlertSoundbaitSwitchAlertSoundSea Creature Tracking
trackSeaCreatures (default true)creatureScanRadius (default 12.0)SEA_CREATURE_CAP = 10 (static constant, Hypixel-standardised)seaCreatureCapSounddespawnWarningEnabled (default true)despawnWarningMinutes (default 5)despawnWarningSoundStats & Alerts
fishingStatsHudVisible (default true)rebootAlertEnabled (default true)rebootAlertSoundTriggers
triggerLevels — list of 5 TriggerLevel objects (all disabled by default)biteAlertSound (silent by default, durationSeconds=0)Developer
debugMode (default false)logLevel (default LEVEL_WARN = 2)com.poseidon.gui.PoseidonHudRenderer
Visibility: static hudVisible, toggled by H keybind. Closing the HUD while active calls setActive(false).
Position (4, 4), width 200 px. Height is dynamic.
Header: "Poseidon" label left; state label right (coloured by state). Accent bar on left edge; flashes red during reboot alert.
Rows (in order, each optional):
| Row | Label | When shown | Color logic |
|---|---|---|---|
! Reboot |
SOON | Reboot alert active | Red 0xFFFF4444 |
Active |
Yes / No | Always | Green / Red |
State |
State name | Always | State colour |
Bobber |
None / Detected / countdown | Always | Grey=none, Green=detected, Yellow=countdown |
Slug |
-- / Xs / READY |
Slugfish mode on | Grey=no bobber, Orange=counting, Green=ready |
Bait |
Name (count) | Bait HUD on | Red if no bait |
Area |
Island name | SC tracking on + area known | Grey |
SC |
count / 10 | SC tracking on | Grey=0, Orange=>0, Red=at cap |
DHC |
stat or -- |
Stats HUD on + any stat known | Light grey |
SCC |
stat or -- |
Stats HUD on + any stat known | Light grey |
Speed |
stat or -- |
Stats HUD on + any stat known | Light grey |
Treasure |
stat or -- |
Stats HUD on + any stat known | Light grey |
Log panel: Last 5 log lines below the main panel (prefix stripped, 50-char max).
| State | Color |
|---|---|
| Reboot alert | Red 0xFFFF4444 (overrides state colour) |
| IDLE (active=false) | Red 0xFFEE4444 |
| IDLE (active=true) | Orange 0xFFFFAA00 |
| WAITING | Green 0xFF44EE44 |
| BITING | Yellow 0xFFFFFF44 |
| REELING | Blue 0xFF44AAFF |
com.poseidon.gui.PoseidonConfigScreen
Opened via /poseidon, the Open Config keybind, or ModMenu.
OptionGroup blocks (one per trigger slot): enabled, name, patterns, action (reserved), show title, title text (supports &x/§x codes), don't recast, stop bot, sound optionscom.poseidon.mixin.MouseClickMixin
Injects at HEAD of Mouse.onMouseButton(), cancellable. Blocks right-click when FishingManager.shouldBlockRightClick() returns true.
shouldBlockRightClick() is true when:
WAITING or BITINGmc.currentScreen == null (no GUI is open — never blocks inside menus)com.poseidon.core.PoseidonLogger — singleton, PoseidonLogger.getInstance()
| Constant | Value | Usage |
|---|---|---|
LEVEL_DEBUG |
0 | Verbose output |
LEVEL_INFO |
1 | Normal events |
LEVEL_WARN |
2 | Unexpected situations (default) |
LEVEL_ERROR |
3 | Failures |
ArrayDeque<String> → HUD log panelconfig/poseidon/poseidon.log[HH:mm:ss] [LEVEL] messagecom.poseidon.PoseidonMod — implements ClientModInitializer
FishingConfig.getInstance().load()registerKeybinds() — Y, H, unbound config keyregisterCommands() — /poseidon + ALLOW_COMMAND fallbackHudRenderCallback.EVENT.register(PoseidonHudRenderer::render)PlayerAPIEvents.TICK.register(this::onTick)PlayerAPIEvents.CHAT_RECEIVED.register(this::onChatReceived)PlayerAPIEvents.WORLD_JOIN.register(this::onWorldJoin) — triggers update checkRebootAlertManager.getInstance().onChatReceived(sender, message) — always runsif (!FishingManager.getInstance().isInCatchWindow()) return — timing gateif (!isCatchMessage(message)) return — colour gate (§a, §e, ⛃)parseLegacyText()), call notifyTriggerFired()showTitle() calls mc.inGameHud.setTitle() / setSubtitle() / setTitleTicks() directly with a MutableText built by parseLegacyText(). Both & and § are accepted as format-code prefixes. Colour codes reset bold/italic/etc. to match vanilla behaviour; §r/&r resets all.
isInCatchWindow() — true for 200 ticks (10 s) after the reel-in tapKey fires.isCatchMessage(msg) — true if msg starts with §a (green catch), §e (yellow/gold, e.g. Double Hook), or has ⛃ as the first non-format-code character (treasure catch).String name // label shown in config header and logs
boolean enabled
String patterns // comma-separated, case-insensitive substrings
AlarmSound sound
String action // reserved, unused
boolean dontRecast // suppress auto-recast for this catch
boolean stopBot // deactivate bot after this catch
boolean showTitle // show MC title overlay
String titleText // supports &x / §x colour codes; falls back to name
TriggerLevel.matches(String chatText) — splits patterns on ,, lowercases both, returns true if any non-empty pattern is a substring of the chat text. Case-insensitive, no regex.
isSeaCreatureDisplay(Entity) — checks for ⚓ (U+2693) in custom name or TextDisplayEntity text.
extractCreatureName(Entity) — strips [LvN] ⚓ prefix and HP suffix from the full nameplate text.
Runs SCAN_DELAY_TICKS (5) ticks after the reel-in, anchored to the saved lastBobberX/Y/Z position.
At most one creature is added per reel-in to avoid picking up other players' nearby creatures.
Before adding a new entity, the scanner checks all tracked creatures with the same name. If any tracked creature is within 3 blocks of the new entity, it is treated as a nameplate refresh (new display entity for the same mob) and its entityId is updated in-place rather than adding a new entry.
cleanupDeadCreatures() runs every CLEANUP_PERIOD_TICKS (40) ticks:
despawnWarningTicks; fires sound once per creature.removeIf(t -> mc.world.getEntityById(t.entityId) == null). Position (lastX/lastZ) is kept fresh for the deduplication check while the entity is alive.SEA_CREATURE_CAP after removal, clears capAlertFired.SEA_CREATURE_CAP = 10 — a single static constant. The per-area cap map was removed in 1.1.0.
After a 1-second settle period (BOBBER_SETTLE_TICKS = 20), every WAITING tick:
dist = sqrt((bobber.X - initialX)² + (bobber.Z - initialZ)²)dist > hookStuckMaxDistance: play hookStuckSound, send tapKey("use", 100), schedule recast if cfg.isHookStuckAutoRecast() (independent of global autoRecast)XZ-only measurement avoids false positives from normal vertical bobbing (~0.5 blocks).
FishingConfig.AlarmSound — inner class, used for all sounds in Poseidon.
| Field | Type | Notes |
|---|---|---|
soundId |
String | Minecraft sound ID |
volume |
double | 0.1 – 2.0 |
pitch |
double | 0.5 – 2.0 |
durationSeconds |
int | 0 = silent/disabled |
intervalTicks |
int | Ticks between repeats |
play() — times = (durationSeconds × 20) / intervalTicks; calls SoundActions.playByIdRepeated(). Returns early if durationSeconds ≤ 0.
mergeFrom(src, defaults) — loads file values over defaults, protecting against zero/null fields.
v0 → v1: flat biteAlert* → biteAlertSound AlarmSound object; triggerLevels added
v1 → v2: seaCreatureCap int → seaCreatureCapByArea Map
v2 → v3: autoRecast added (inject true — GSON defaults bool to false)
v3 → v4: recastDecisionTicks added
v4 → v5: despawnWarningEnabled, despawnWarningMinutes added (inject true)
v5 → v6: hookStuckDetectionEnabled, hookStuckMaxDistance added (inject true)
v6 → v7: updateCheckEnabled added (inject true)
v7 → v8: seaCreatureCapByArea removed; SEA_CREATURE_CAP = 10 (constant)
v8 → v9: baitHudVisible, baitLowThreshold, baitLowAlertSound, baitSwitchAlertSound added (inject true for baitHudVisible)
v9 → v10: rebootAlertEnabled, rebootAlertSound, fishingStatsHudVisible added (inject true for both booleans)
v10 → v11: hookStuckAutoRecast added (inject true)
v11 → v12: slugfishMode, slugPet added (both default false — no injection needed)
GSON boolean caveat: GSON bypasses constructors. Any new boolean field that should default true must be injected in its migration step — Java field initializers are ignored when GSON deserializes.
| Key | Default | Action |
|---|---|---|
| Y | Y | Toggle Fishing — starts (if HUD visible) or stops the bot |
| H | H | Toggle HUD — also stops the bot if HUD is closed while active |
| (none) | Unbound | Open Config |
| Command | Effect |
|---|---|
/poseidon |
Opens config screen (tick-delayed to avoid chat-close race) |
ALLOW_COMMAND fallback handles servers that override the client command tree.
Panel: position (4, 4), width 200 px, height dynamic.
Header: "Poseidon" + right-aligned state label, coloured accent bar on left edge.
┌── Poseidon ─────────── [STATE] ──┐ ← accent bar + header
│ │ ← divider
│ ! Reboot SOON (opt) │ ← red when reboot detected
│ Active Yes / No │
│ State IDLE / WAITING / ... │
│ Bobber None / Detected / ... │
│ Slug -- / 18s / READY (opt)│ ← slugfish mode only
│ Bait Name (count) (opt) │
│ Area Hub (opt) │
│ SC 4 / 10 (opt) │
│ DHC value or -- (opt) │ ─┐ stats section
│ SCC value or -- (opt) │ │ shown only when at least
│ Speed value or -- (opt) │ │ one stat is available
│ Treasure value or -- (opt) │ ─┘
└───────────────────────────────────┘
[LOG]──────────────────────────────────
Last log line
...
| Key | Type | Default |
|---|---|---|
detectionRadius |
double | 4.0 |
hookStuckDetectionEnabled |
bool | true |
hookStuckMaxDistance |
double | 1.5 |
hookStuckAutoRecast |
bool | true |
slugfishMode |
bool | false |
slugPet |
bool | false |
| Key | Type | Default |
|---|---|---|
reactionDelayMinMs |
int | 180 |
reactionDelayMaxMs |
int | 700 |
autoRecast |
bool | true |
recastDelayMinMs |
int | 200 |
recastDelayMaxMs |
int | 600 |
recastDecisionTicks |
int | 10 |
| Key | Type | Default |
|---|---|---|
baitHudVisible |
bool | true |
baitLowThreshold |
int | 5 |
baitLowAlertSound |
AlarmSound | orb.pickup, 1.0, 0.5, 3s, 20t |
baitSwitchAlertSound |
AlarmSound | bell.use, 1.0, 0.8, 2s, 20t |
| Key | Type | Default |
|---|---|---|
trackSeaCreatures |
bool | true |
creatureScanRadius |
double | 12.0 |
SEA_CREATURE_CAP |
int constant | 10 |
seaCreatureCapSound |
AlarmSound | levelup, 1.0, 0.8, 10s, 20t |
despawnWarningEnabled |
bool | true |
despawnWarningMinutes |
int | 5 |
despawnWarningSound |
AlarmSound | bell.use, 1.0, 0.8, 5s, 20t |
| Key | Type | Default |
|---|---|---|
fishingStatsHudVisible |
bool | true |
rebootAlertEnabled |
bool | true |
rebootAlertSound |
AlarmSound | bell.use, 1.0, 1.0, 300s, 40t |
| Key | Type | Default |
|---|---|---|
triggerLevels |
List<TriggerLevel\> | 5 empty/disabled |
biteAlertSound |
AlarmSound | orb.pickup, 1.0, 1.5, 0s (silent), 15t |
| Key | Type | Default |
|---|---|---|
debugMode |
bool | false |
logLevel |
int | 2 (WARN) |
configVersion |
int | 12 (auto-managed) |
updateCheckEnabled |
bool | true |
| Constant | Value | Purpose |
|---|---|---|
SCAN_DELAY_TICKS |
5 | Delay after reel-in before scanning for sea creatures |
CLEANUP_PERIOD_TICKS |
40 | How often dead creatures are removed (2 s) |
AREA_REFRESH_TICKS |
40 | How often the tab-list area is re-read (2 s) |
BOBBER_SETTLE_TICKS |
20 | Settle window before hook-stuck drift check (1 s) |
IDLE_TIMEOUT_TICKS |
100 | Idle watchdog: recast retry if no bobber after this long (5 s) |
CATCH_WINDOW_TICKS |
200 | Trigger evaluation window after a reel-in (10 s) |
SLUGFISH_NORMAL_TICKS |
420 | Slugfish delay, no pet (21 s) |
SLUGFISH_PET_TICKS |
220 | Slugfish delay, max Slug Pet (11 s) |
GUI_RESUME_MIN_TICKS |
15 | Min post-GUI-close lock (~0.75 s) |
GUI_RESUME_MAX_TICKS |
50 | Max post-GUI-close lock (~2.5 s) |
| State reset delay | 10 | REELING → IDLE after reel-in |
recastDecisionTicks |
10 (configurable) | Trigger window before recast decision |
20 ticks = 1 second. 1 tick ≈ 50 ms.
Reacting to a bite the instant a GUI closes is a strong automation signal. The random 15–50 tick delay after mc.currentScreen goes null breaks the deterministic pattern without requiring the player to do anything special. The lock is managed entirely by FishingManager.tick() using the existing tick loop — no separate callback is needed.
Rather than checking all chat, triggers only run within 10 s of a reel-in. This prevents a player's death message (mentioning a creature name) from triggering an alert mid-session. The window is generous enough to cover high-latency servers but tight enough to exclude unrelated chat.
isCatchMessage() strips leading §X format-code pairs and checks the remaining content. §a covers normal catch lines; §e covers the Double Hook announcement (§e§lDOUBLE HOOK!) that precedes a catch; ⛃ covers treasure catches which use a variable colour prefix. Any other colour prefix (red death notices, gray system messages) is rejected before pattern matching runs.
DisplayActions.showTitle(String, String) wraps its string in Text.literal() internally, which does not parse § codes. Poseidon therefore bypasses it and calls mc.inGameHud.setTitle() directly with a MutableText built by parseLegacyText(). Both & and § are accepted; colour codes reset style flags to match vanilla.
Hypixel periodically refreshes sea creature nameplate display entities (new entity ID, same physical mob). Without deduplication, each refresh would count as a new catch. The fix stores lastX/lastZ for each tracked creature (updated every cleanup cycle while the entity is visible) and checks proximity (3-block radius) before adding a same-named entity to the list.
shouldBlockRightClick() and GUIsThe right-click guard is lifted inside GUI screens because: (a) you cannot cancel a cast through a container/menu anyway, and (b) blocking right-click inside a GUI prevents normal item interactions (picking up items, clicking slots). The guard returns to full strength the moment mc.currentScreen is null again.
After scheduleRecast fires tapKey, lastRecastTick is stamped. If the IDLE state persists for more than 100 ticks without a bobber appearing, the watchdog fires again. This recovers from two failure modes: (1) the tapKey packet was dropped by the server, and (2) the bobber surfaced and vanished within a single tick before the IDLE case ran, leaving the state machine with nothing to act on.
These are intentionally separate. A player may prefer manual-cast mode (global autoRecast = false) so they decide when to cast, but still wants the bot to auto-recover when the hook gets stuck on a mob — which isn't a "catch" and should always retry. hookStuckAutoRecast covers exactly that case without forcing global auto-recast on.
GSON deserializes objects by bypassing constructors. Java field initializers such as private boolean foo = true are never run during GSON deserialization. Any boolean that should default to true in an existing config (i.e., one that was written before the field existed) must be injected in its migration step. This is why migrations v2→v3, v4→v5, v5→v6, v6→v7, v9→v10, and v10→v11 all explicitly inject true for their new boolean fields.