▶️ ЗАБЕРИ СВОИ 8 ПОДАРКОВ 🎁 ПРИ СОЗДАНИИ СВОЕГО МАЙНКРАФТ СЕРВЕРА
Моды/CobblemonQuests

CobblemonQuests

Drop-in daily & weekly quest system with configurable rewards, streaks, milestones and hidden quests.

Оцените первым
511
1
Все версииCobblemonQuests 1.8.0

CobblemonQuests 1.8.0

Release07.05.2026

Список изменений

[1.8.0] — 2026-04-23 — "Audit + Hardening Pass"

Six-agent audit of the entire codebase (REPEATABLE coverage, config round-trip, switch exhaustiveness + null safety, GUI navigation, admin / audit surface, i18n keys). Fourteen fixes across four rounds. Version bumped to 1.8.0 because this touches the public config schema (new sections now actually persisted).

Fixed — Config round-trip erasure (BLOCKERS)

  • effects.* and hud.* were public POJO fields with defaults, but ConfigLoader never read them and ConfigWriter never wrote them. The first ConfigWriter.save() (triggered by any admin config GUI) erased every admin-tuned sound ID / volume / pitch / show-title flag and every HUD setting from the on-disk file. Round-tripped now; bundled default_config.conf includes the effects { } and hud { } sections so admins discover them on first install.
  • event-hooks was read by ConfigLoader but never written by ConfigWriter. Admin-authored hook commands vanished the first time anyone saved a different config section from the GUI. Now round-tripped with a comment block.
  • quest-text.category-format was defined in GuiConfig.QuestText but GuiConfigLoader.loadMainMenu never read it from main_menu.conf. Admins couldn't customize the category/rarity line on quest tiles. Now loaded.

Fixed — Scheduler null-deref crashes during lifecycle windows

  • QuestsMainGui, QuestsHubGui, DailyQuestsGui, WeeklyQuestsGui all called scheduler().nextDailyReset() / nextWeeklyReset() unguarded. Between SERVER_STOPPING and the next SERVER_STARTED, scheduler is null — a player still in a GUI crashed the GUI render with an NPE (and in some cases a mixin-side exception cascaded).
  • New null-safe accessors nextDailyResetOrFallback() / nextWeeklyResetOrFallback() on CobblemonQuests. Return a sane 24h / 7d future instant so the UI renders a bogus-but-harmless timer instead of crashing. All six call sites switched.

Fixed — QuestDetailGui back routed to the wrong menu

  • Same shape as the RepeatableQuestsGui back bug fixed in 1.7.9. QuestDetailGui hardcoded back to QuestsHubGui regardless of caller. Opening detail from QuestsMainGui, DailyQuestsGui, WeeklyQuestsGui, RepeatableQuestsGui, HiddenQuestsGui, ChainDetailGui, or QuestAdminActionGui then clicking back dumped the player into the config-driven hub they never opened.
  • QuestDetailGui now takes an optional Runnable backAction. Every caller (all eight) passes a back lambda that reopens the caller. Legacy one-arg constructor kept for back-compat.

Fixed — QuestAdminCommand.complete missed REPEATABLE

  • When an admin force-completed a REPEATABLE quest, the command incremented totalCompleted but didn't bump repeatableCompletions. The per-id farming counter shown in the Repeatable GUI header and future leaderboards undercounted admin completions.

Fixed — PermissionHelper silently swallowed provider failures

  • catch (Throwable) fell back to op-level without logging. A broken LuckPerms (misconfig, missing mod, class-load failure) silently gave every op unrestricted access AND prevented the admin from noticing. Now logs a WARN once per JVM with the node name and exception so the signal reaches latest.log.

Fixed — Chain step picker allowed REPEATABLE

  • StepPickerGui.filteredAndSorted returned every registered quest. An admin building a chain could pick a REPEATABLE step, which would get stuck in activeHiddens and break the chain (the advance hook fires on claim, but REPEATABLE claims reset in place — the step never "leaves" the active list). Now filtered out along with NORMAL (internal-only type) at the source.

Fixed — Missing i18n key

  • notification.community_goal_complete was referenced by CommunityGoalManager.java:128, 142 but absent from en_us.json — players saw raw notification.community_goal_complete instead of the localized banner. Key added.

Added — Audit log entries for previously silent state changes

  • /cq admin reload now audits ADMIN_RELOAD.
  • /cq admin goal set/stop/reset/progress now audit ADMIN_GOAL_SET / ADMIN_GOAL_STOP / ADMIN_GOAL_RESET / ADMIN_GOAL_PROGRESS with the relevant detail. Admin-initiated community-goal mutations are now fully traceable in cobblemonquests-audit.log.

Added — BaseGui no-permission message localizable

  • BaseGui.open() hardcoded Text.literal("No permission."). Now reads from gui.no_permission with MiniMessage rendering, so server owners can rebrand / translate the rejection without patching the jar.

[1.7.9] — 2026-04-23 — "Repeatable Menu Config + Correct Back Routing"

Added — gui/repeatable_menu.conf

  • Full customization of the Repeatable Quests viewer, matching the pattern of leaderboard_menu.conf / stats_menu.conf. Admins can now retitle the menu, resize it (1–6 rows), change the filler item / background color, relocate every button, edit every label / lore / glow, change the empty-state message, and customize the missing-quest placeholder (for orphaned quest ids after a .conf delete).
  • New GuiConfig.RepeatableMenu model + GuiConfigLoader.loadRepeatableMenu
    • bundled default_gui/repeatable_menu.conf.
  • Configurable: title, rows, background-color, filler-item, max-per-page, quest-slots[], and button blocks for header, claim-all, prev-page, page-info, next-page, back, close, empty-state, missing-quest, plus custom-buttons. Button-lore placeholders: {available}, {lifetime_runs}, {ready}, {page}, {pages}, {quest_id}.
  • RepeatableQuestsGui is now fully config-driven — no more hardcoded slot constants. Tile rendering still delegates to the shared QuestItemRenderer so dailies/weeklies/repeatables all look consistent.

Fixed — Back button opened the wrong main menu

  • The Repeatable page's back button always routed to QuestsMainGui (the layout-driven menu backed by gui/player_main.conf). Players who opened the page from /quests — which uses QuestsHubGui (config-driven, gui/main_menu.conf) — hit back and landed on a completely different menu layout they'd never opened.
  • RepeatableQuestsGui now takes an optional Runnable backAction and uses it for the back button. QuestsHubGui passes a back that returns to itself; QuestsMainGui passes a back that returns to itself. Back now always returns to the menu you came from.

[1.7.8] — 2026-04-23 — "Hub Repeatable, Offline Names, Wild Hunt"

Fixed — /quests had no Repeatable button

  • /quests opens QuestsHubGui (config-driven via gui/main_menu.conf), which had zero awareness of the new REPEATABLE type. The Repeatable button I added in 1.7.5 lived only on the layout-driven QuestsMainGui — two different player menus, both reachable, different slot maps. Players running /quests saw no Repeatable tab at all.
  • Added mainMenu.repeatable button in GuiConfig, wired through GuiConfigLoader, rendered in QuestsHubGui, default slot 46 with {available} + {lifetime_runs} placeholders. Opens RepeatableQuestsGui on click and re-runs assigner.syncRepeatables so the page is always current after /cq admin reload.
  • Default main_menu.conf bundled resource now carries the same block so fresh installs get the button without editing config.

Fixed — Leaderboard/Community-Quest showed "#1 ???" for offline players

  • ServerQuestGui.java:112 hardcoded "???" for any contributor whose entity wasn't currently online. The top contributor logging off erased their name from the board the moment they left.
  • New resolvePlayerName helper on the GUI: live profile → stored PlayerQuestData.playerName (stamped on every join since 1.6.x) → 8-char UUID prefix. Never returns null, never falls through to a placeholder string.

Fixed — Wild Hunt / DEFEAT_WILD never triggered

  • CobblemonBridge.hasNpcParticipant had two bugs: (1) the class- name check folded "wild" into the NPC match, and (2) the tail of the method unconditionally returned true whether or not an NPC actor was found. Net effect: the call always returned true, so BattleTracker's isWild = !hasNpcParticipant(battle) was permanently false and DEFEAT_WILD never fired. Wild Hunt, Wilderness Warrior, and every other defeat_wild quest stayed at 0/N forever — wins were credited (WIN_BATTLE fires unconditionally) but never as wild wins.
  • Split into two explicit helpers: hasNpcParticipant (positively identifies trainer/NPC actor classes) and isWildBattle (positively identifies PokemonBattleActor / *wild* on the enemy side, with NPC taking precedence in the rare mixed case). BattleTracker now calls isWildBattle(battle) directly.
  • Other objective types audited in the same pass: CATCH, HATCH_EGG, LEVEL_UP, GAIN_LEVELS, EVOLVE, USE_CANDY, USE_POKEBALL, VISIT_BIOME, VISIT_DIMENSION, CATCH_SHINY, CATCH_LEGENDARY — all wired correctly; no additional gaps.

[1.7.7] — 2026-04-22 — "Bypass-off-by-default"

Changed — Bypass permissions now gated by config toggle

  • cobblemonquests.bypass.reroll-cost (and the reserved cobblemonquests.bypass.rate-limit) were previously consulted any time they were granted, so a forgotten LuckPerms group inheritance or a staff member with a wildcard * node silently had the new per-rotation reroll caps disabled. Granting the node is no longer sufficient on its own.
  • New permissions.bypass.reroll-cap / permissions.bypass.rate-limit flags in config.conf, both defaulting to false. The runtime only honors the matching LuckPerms node when the flag is true. Turn the flag on and grant the node to activate a bypass.
  • No change required on existing installs: the default-false flag means previously-bypassable staff now hit the same 1-per-rotation cap as everyone else until the admin explicitly opts back in.

[1.7.6] — 2026-04-22 — "Seed Missing Defaults + Reroll Exploit Fix"

Fixed — Bundled repeatable defaults never reached existing servers

  • QuestRegistry.reload only copied bundled default_quests/*.conf files when the config dir was empty. Upgrading from 1.7.4 to 1.7.5 left the three new repeatable_* templates stuck inside the jar — the Repeatable tab had a button on the GUI but zero tiles behind it because the registry's REPEATABLE pool was empty.
  • Now each bundled default is copied individually if missing; existing admin-authored files are never overwritten, and admins can still delete a default to remove it permanently.

Fixed — Reroll-to-riches exploit

  • The v1.0 reroll flow allowed unlimited paid rerolls after the one free one. Players could spend 50 stars repeatedly to fish the weekly pool for high-reward quests (Apex Predator = 300 stars + 15 000 pd), making the reroll button positive-EV and printing currency. Two known abuse paths: 13 000 pd / 290 stars per weekly rotation by the time it was reported.
  • New model: hard per-rotation caps, no paid fallback. reroll.daily-per-day (default 1) resets with the daily rotation; reroll.weekly-per-week (default 1) resets with the weekly rotation. Hidden quests still reject rerolls; repeatables don't participate in rerolls at all since they don't rotate. Counters are consumed before the roll and refunded if no replacement can be produced, so concurrent double-clicks can't double-spend and an empty pool doesn't burn the cap.
  • Legacy fields (free-per-day, currency, cost-stars, cost-pokedollars) stay in the schema for back-compat parsing but are no longer read by the runtime. The admin Reroll Config GUI (/cq admin → Config → Reroll) is rewritten around the two per-rotation caps — the old price sliders are gone.
  • QuestsMainGui reroll tooltip shows daily X/Y · weekly X/Y instead of free today: N.

[1.7.5] — 2026-04-21 — "Repeatable Quests"

Added — REPEATABLE quest type

  • New type = "repeatable" alongside daily / weekly / elite_weekly / hidden. Repeatables never rotate. The registry's REPEATABLE pool is mirrored into every player's activeRepeatables on join and on /cq admin reload, and the claim service resets each tile's progress after the reward is paid out so the player can run it again immediately. Rewards are intentionally small — tune in the quest .conf file; nothing hardcoded.
  • PlayerQuestData.repeatableCompletions tracks per-id lifetime runs, separate from completedAllTime, so dashboards can distinguish "ran the daily once" from "farmed Quick Catch 400×".
  • Bundled three demo templates (repeatable_catch_any, repeatable_battle_win, repeatable_level_up) that show the reward floor. Delete them to start fresh.

Added — Dedicated RepeatableQuestsGui

  • Opens from the new Repeatable button on the main player quests GUI (slot 49 in the default layout — configurable via gui/player_main.conf with role button_repeatable). Lists every available repeatable, 28 per page with prev/next pagination, a Claim All button scoped to ready repeatables, and a header showing total available + lifetime runs.
  • Clicking a tile opens the standard QuestDetailGui, so the same reroll/claim flow players already know works here too.

Added — Admin tooling

  • QuestWizardGui type picker now cycles repeatable (and skips the internal NORMAL type entirely, which was always a footgun). Creating a repeatable immediately re-syncs every online player so the new tile shows up without reconnecting.
  • QuestBrowserGui gains a "Repeat" tab filter next to Hidden.
  • QuestEditorGui type picker uses the same cycle.

Fixed — Exhaustive-switch compile holes exposed by the new type

  • QuestItemRenderer.typeTag, QuestHudManager.colorFor, QuestAdminCommand.give/complete, QuestsHubGui.typeTag all now cover REPEATABLE explicitly. Was silently working thanks to Java's implicit default on arrow-switch of enum — this commit makes it load-bearing.

[1.7.4] — 2026-04-21 — "Viewable Hidden Quests"

Fixed — Hidden-quest button routed to Stats, never to the quest

  • The Hidden button on the player quests GUI called new StatsGui(player).open() instead of a page that lists the unlocked hidden quests. Players who triggered a hidden quest saw the "Unlocked: 1" counter on the button but the click silently opened their stats — so there was no in-game way to read the hidden quest's description, objective, or progress. They knew something had unlocked but couldn't see what or how to finish it.

Added — HiddenQuestsGui

  • Dedicated viewer for unlocked hidden quests, opened from the Hidden button. Lists every quest in activeHiddens (in-flight, live progress, clickable to open the standard detail view) plus every id in discoveredHiddenQuests that has already been completed (rendered as a "Completed" trophy tile). 14 tiles per page; refreshes on the shared GUI ticker so progress updates while the player is looking.
  • Empty-state hint when neither list has anything yet, so newly joined players don't get a blank screen if an admin gives them the Hidden button by accident.

[1.7.3] — 2026-04-21 — "Reliable Crate Keys"

Fixed — Pebble's Crates keys never landed (Apex Predator etc.)

  • Default integrations.crate-key-command was padmin givekey "{player}" {amount} {key} crate. Pebble's Crates (the plugin this template targets) parses /padmin givekey <player> <amount> <crate> as three plain words — the quoted player arg and the trailing literal crate both broke Brigadier parsing, so the Apex Predator reward and any other crate_key reward was silently dropped (visible as a WARN in latest.log only).
  • New default: padmin givekey {player} {amount} {key}. Matches the real Pebble's admin command.

Added — Per-key command override map

  • integrations.crate-key-commands in config.conf. Reward's key value -> a full command template that takes priority over the global crate-key-command. Lets admins point lunar at Pebble's and vote at ExcellentCrates in the same server without branching elsewhere. Placeholders: {player} {amount} {key}.
  • CrateKeyBridge consults the per-key map first, falls back to the global template. A missing/blank template now logs the specific key that needs a command, and dispatch failures include the resolved command string plus a ready-to-paste admin-test command.

Added — Admin test commands

  • /cobblemonquests admin testkey <player> <key> [amount] — invokes the crate-key bridge live against the current config so admins can verify their template without waiting for a quest to finish.
  • /cobblemonquests admin testcommand <player> <command...> — runs an arbitrary command through the same SafeDispatch pipeline reward commands use, with {player} substituted. Useful for validating any new reward template before saving it into a quest.
  • Both write ADMIN_TEST_KEY / ADMIN_TEST_COMMAND audit entries.

Changed — Apex Predator elite weekly

  • Crate key renamed lunar -> legendary in the bundled template, so out-of-the-box it matches the streak/milestone rewards that already use legendary. A comment in the file explains how to remap with the new per-key override if your plugin uses a different id.

[1.7.2] — 2026-04-21 — "Guaranteed Reset Fill"

Fixed — Empty quest list after timer reset

  • On daily/weekly reset, the exclusion set passed to the pool picker contained every quest the player had completed in the prior period (completedToday / completedThisWeek). With the bundled defaults (5 daily, 3 weekly), a player who cleared yesterday's board had the entire pool swallowed by the exclusion set and pickDaily returned 0 — players woke up to an empty quest GUI.
  • QuestPool.pick now runs a second pass that falls back to the full pool (ignoring exclude, blocking only already-picked ids) to top up to the requested count. Guarantees 7 dailies and 7 weeklies as long as the registry has at least that many of each type.

Added — Larger bundled default quest pool

  • First-time bootstrap now copies 9 dailies and 7 weeklies (plus the elite weekly and the hidden quest) so a fresh install has enough pool depth for the default dailyQuestCount=7 / weeklyQuestCount=7 schedule without any partial-fill warnings.
  • New daily templates: daily_hatch_egg, daily_defeat_wild, daily_catch_shiny, daily_use_candy.
  • New weekly templates: weekly_defeat_wild, weekly_hatch_eggs, weekly_level_up, weekly_win_battles.

[1.7.1] — 2026-04-21 — "Deep Audit Pass"

Two-phase audit of the whole mod (trackers, rewards, persistence, scheduler, community goals, chains, pool). Targeted the classes of bug that produce "player report: quests stopped working" but leave no trace in the logs — silent executor failures, missing saves, fragile reflection, lost data in races.

Added — Unified util/SafeDispatch

  • Single canonical path for every "run an admin-configured command as console" call in the mod: RewardDispenser.runCommand, CrateKeyBridge.grant, ImpactorEconomy.depositStars / withdrawStars. One place that:
    • uses CommandDispatcher.execute() (returns an int) instead of CommandManager.executeWithPrefix() (void wrapper that eats parse errors)
    • treats result < 1 as a hard failure with a WARN carrying the resolved command string
    • guards against re-entry per context key so a misconfigured template can't loop back into itself
    • separates CommandSyntaxException from generic throws

Fixed — COMMAND-type rewards silently vanished

  • RewardDispenser.runCommand used executeWithPrefix (void return). A typoed reward command got swallowed into feedback and the player was told "reward granted" with nothing actually having run. Now routed through SafeDispatch — typos / unknown commands / wrong syntax appear as WARNs in latest.log with the exact resolved invocation and the REWARD_GRANT audit entry correctly marks allOk=false.

Fixed — Chain advancement lost on missing quest

  • If a chain step referenced a quest that had been removed from the config, ChainManager would silently advance the progress counter but never assign the step's active quest, leaving the player "in the chain with no quest to do". assignStep now returns a success boolean; onQuestClaimed + startChain only commit the new chainProgress value if assignment succeeds. Failed advance → progress rolls back, WARN logged.
  • ChainRegistry.validateAgainst(QuestRegistry) runs at startup and /questsadmin reload, logging a WARN for every dangling step reference so admin sees the issue before a player hits it.

Fixed — PlayerDataStore.getOrLoad TOCTOU race

  • Old code loaded from disk outside any lock, then putIfAbsent'd into the cache. Two concurrent calls → both loaded → loser's data was discarded. If the disk state changed between the two reads, one read was lost. Replaced with computeIfAbsent whose load runs under the map's internal lock — exactly-once.

Fixed — ImpactorEconomy.withdrawStars race

  • Old flow: guard-check under lock, release, dispatch, re-check, commit. If the re-check failed (another thread raced the balance below threshold), dispatch had already debited Impactor — player lost external currency without the mirror reflecting it.
  • New flow: single synchronized (data) block that covers guard → dispatch → mirror-subtract, with store.save released outside the lock. Dispatch is synchronous Brigadier (CPU-bound), so the per-player lock window is fine.

Fixed — Community-goal boss-bar cleanup on a raw Thread

  • onGoalComplete spawned a new Thread that slept 10s then hit server.execute(...) — risky under event ordering and adds a thread per completion. Replaced with a tick-scheduled bossBarClearAt instant consumed by a new tick() method on CommunityGoalManager, wired into the existing END_SERVER_TICK hook. Same 10-second visible window, no thread.

Fixed — EggHatchTracker field-name reflection

  • Was searching CobblemonEvents class fields by substring looking for "egg" + "hatch" — fragile (could match the wrong field) and slow. Swapped to compile-time CobblemonEvents.HATCH_EGG_POST against Cobblemon 1.7.3. If the field name drifts in a future Cobblemon release the build fails loudly.

Added — Pool-exhaustion logging

  • When QuestPool.pick(type, count, exclude) can't fill the requested count, it now logs a WARN with pool size, exclusion count, and the partial count delivered. Previously the caller got a silently-short list and players saw empty quest slots with no explanation.

Hardened — catch blocks no longer fully silent

  • Player-message-send catches (sendMessage failures) in RewardDispenser.notifyCurrency, QuestClaimService.notify, ProgressTracker.notifyComplete, ChainManager now log at DEBUG. Enable log-level DEBUG when investigating "X told me it sent a message but nothing appeared" reports.

Technical notes

  • ImpactorEconomy re-entry guard (ThreadLocal<Boolean>) removed — SafeDispatch provides this per-context now and is shared across all command paths.
  • CrateKeyBridge — the inline dispatch block shipped in 1.6.5 is gone; it's 3 lines now delegating to SafeDispatch.
  • RewardDispenser.runCommand likewise trimmed to a delegate.

[1.7.0] — 2026-04-20 — "Quest Tracker Overhaul"

Major cleanup of the Cobblemon event integration. Catch quests and "Throw N Poké Balls" quests weren't progressing reliably — rewritten with compile-time event accessors instead of reflection, and the whole tracker layer now reports firing activity so it's obvious where something isn't wired up.

Fixed — "Throw N Poké Balls" quests never progressed

  • v1.6.4 switched ItemUseTracker to Fabric's UseItemCallback. That event only fires on air right-clicks (PlayerInteractItemC2SPacket). When the player aims at a visible wild Pokémon entity or at a block, the client sends a different packet — UseItemCallback never fires and the ball throw went uncounted.
  • Reverted to CobblemonEvents.THROWN_POKEBALL_HIT but resolved the thrower from the ball entity itself via EmptyPokeBallEntity.getOwner() (inherited from ProjectileEntity). Compile-time access — no more silent reflection mismatches against the event class.
  • The quest now counts every ball that actually contacts a wild Pokémon, regardless of whether the capture roll succeeds. Throws into empty air still don't count (matches the "engage with a Pokémon" spirit of the quest; prevents AFK-clicking farming).

Fixed — Apex Predator quest delivered nothing

  • Crate key template was excellentcrates key give …, but the server's actual crate plugin uses /padmin givekey. The default template is now:
    integrations.crate-key-command = "padmin givekey \"{player}\" {amount} {key} crate"
    
    (quoted {player} — matches pcrates' argument parser).
  • Live TestServer config was also migrated to the new default.
  • The 1.6.5 loud-failure work on CrateKeyBridge already made this surface in latest.log if the template is wrong; now the default itself is correct.

Fixed — Catch event reflection drift

  • PokemonCapturedEvent exposes getPokeBallEntity(), not getPokeBall() — the previous reflective call returned null, so ctx.ballId was silently missing. "Catch with Ultra Ball" filters never matched. Rewritten with compile-time event accessors throughout (event.getPlayer(), event.getPokemon(), event.getPokeBallEntity()); species / type extraction goes through the real Pokemon and Species classes.
  • Every catch now emits a DEBUG log with species, types, shiny, ball, biome so admin can confirm the tracker is seeing events.

Added — /questsadmin debug events — tracker activity dashboard

  • Reports per-tracker fire count + last-fired timestamp + last detail (e.g. "player123 caught bulbasaur"). Use it to triage "my quests aren't progressing" complaints in seconds:
    • counter at 0 while playing → Cobblemon event isn't reaching the mod (version mismatch / API rename)
    • counter increments but quest doesn't progress → filter problem on the quest .conf side
  • Reports external bridge activity too (PokeHunts, Raids).

Technical notes

  • New tracker/TrackerDiagnostics class — single source of truth for tracker activity, used by every tracker's success path. Thread-safe (AtomicLong + ConcurrentHashMap); zero overhead when nothing's reading it.
  • BattleTracker, EggHatchTracker, TrainingTracker each got one TrackerDiagnostics.record* call at their fire sites.
  • CobblemonBridge is still the reflection escape hatch for fields that DO vary between Cobblemon versions (Species.name vs Species. showdownId, etc.), but the event CLASSES themselves are compile- time now. The distinction matters: event shapes are public API and stable; sub-field names drift.

Migration

  • Existing configs: the integrations.crate-key-command default changes. If you had customized the template, your value is preserved. If you were on the shipped default, upgrade forces you onto the padmin format — swap back in config.conf if you're still on ExcellentCrates.

[1.6.5] — 2026-04-20 — "Quest Logic Hardening"

Three bug fixes from a live-server report: Apex Predator didn't deliver its crate key, the "visit biomes / dimensions" quests were exploitable via A-B ping-pong, and the leaderboard flipped rank on ties.

Fixed — Apex Predator weekly didn't deliver the crate key

  • The quest was configured with key = "elite", but the server's ExcellentCrates plugin doesn't have an elite crate — it has a lunar crate. The reward template excellentcrates key give {player} {key} {amount} resolved to excellentcrates key give … elite 1, which ExcellentCrates silently rejected (no such crate). The mod thought it had succeeded because executeWithPrefix is a void wrapper — same silent-failure class that bit stars in 1.6.3.
  • Changed elite_weekly_legendary.conf reward to key = "lunar" (both the bundled default and TestServer/config/...).
  • Rewrote CrateKeyBridge.grant to use CommandDispatcher.execute() directly. Exit-code < 1 or a CommandSyntaxException now logs a WARN with the resolved command string and returns false so the audit log records the failure. No more silent drops.

Fixed — "Visit N biomes / dimensions" exploitable via ping-pong

  • ExplorationTracker fires on every biome/dimension transition, so a player bouncing between two biomes (or three dimensions) was farming 1 progress per hop. The "visit 10 biomes" quest could be cleared without leaving a 2-biome radius.
  • ActiveQuest now stores per-quest visitedIds / visitedBonusIds sets (distinct biome/dimension ids already counted). The ProgressTracker dedup gate (shouldCountVisit) only increments when the set grows — so a player has to actually visit N distinct places. Sets reset naturally on daily/weekly quest re-issue.
  • Sets are persisted in <uuid>.json alongside the rest of the active-quest snapshot. Pre-1.6.5 saves simply start with empty sets; players mid-quest at upgrade time get a one-time reset of their visit dedup state.

Fixed — Leaderboard flipped rank on ties

  • When two players hit the same count, the one loaded later from disk was ranking higher. Report: "I got 9 quests first but then Killiment also got 9 and suddenly I'm #2."
  • Added four Instant timestamps to PlayerQuestData: lastTotalCompletedAt, lastWeeklyProgressAt, lastStreakChangedAt, lastStarsEarnedAt. Stamped at the mutation site for each counter.
  • LeaderboardManager.rebuild now sorts value desc, timestamp asc — the player who reached the tied value first (earlier timestamp) ranks higher. Null timestamps (pre-1.6.5 data, no recorded increase) sort last by design.
  • Serialized in <uuid>.json; missing fields tolerated.

Technical notes

  • Dedup sets use LinkedHashSet so the JSON order of visited ids matches the order the player visited them — useful for debugging "is the tracker firing?" reports via the admin player-detail GUI.
  • PlayerQuestData.incrementCompleted now stamps both lastTotalCompletedAt and lastWeeklyProgressAt in one go (a completed quest always contributes to both weekly and all-time counts, so the two timestamps co-move until weekly reset).

Файлы

cobblemonquests-1.8.0.jar(1.05 MiB)
Основной
Скачать

Метаданные

Канал релиза

Release

Номер версии

1.8.0

Загрузчики

Fabric

Версии игры

1.21.1

Загрузок

347

Дата публикации

07.05.2026

Загрузил

ID версии

Главная