New Release#164
Open
tastybento wants to merge 34 commits into
Open
Conversation
Add StoneGeneratorPladdon loader, config/ and utils/ packages, and GeneratorExhaustionData to the docs; clarify the 3 @table objects. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01D7NWPeGXmsUJnnX42X24Rd
The existing GeneratorBuyEvent fires after a purchase completes, so it cannot be used to veto a purchase. Add a new cancellable GeneratorPreBuyEvent fired at the start of StoneGeneratorManager.purchaseGenerator, before any money is withdrawn and before GeneratorBuyEvent is fired. Cancelling it aborts the purchase. This lets other plugins add their own requirements to the generator purchasing process. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01D7NWPeGXmsUJnnX42X24Rd
Unlocked generator tiers were a permanent grant that was never revoked when an island's owner changed. If a player with a generator permission created an island, unlocked a permission-gated tier, then left and handed ownership to a player without that permission, the tier stayed unlocked and usable. checkGeneratorUnlockStatus now revokes permission-gated tiers from the island's unlocked and active lists when the current (online) owner does not hold the required permissions. This runs on the existing TeamSetownerEvent -> validateIslandData -> checkGeneratorUnlockStatus path, so it fires on ownership transfer. Purchase records are preserved, so a generator becomes available again if the permission is regained. Nothing is revoked while the owner is offline, since permissions cannot be checked reliably then. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01D7NWPeGXmsUJnnX42X24Rd
Generator lists were sorted by default-flag, priority, type and finally by friendly name. The friendly-name tiebreaker meant renaming a generator moved it in the player GUI, which was confusing. Use the stable unique id as the final tiebreaker instead, in both getAllGeneratorTiers (drives the player list) and the bundle edit panel. The existing per-generator priority field already lets admins order generators explicitly (e.g. 10/20/30/40); this makes ordering within an equal priority stable and rename-independent. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01D7NWPeGXmsUJnnX42X24Rd
Players could accidentally buy a generator with a single click. Add a buy-confirmation config option (default true) that asks the player to confirm in chat before the purchase is made. The three BUY click handlers in the player panels now delegate to a new shared CommonPanel.purchaseGenerator helper, which: - refreshes the panel and bails out if the generator cannot be purchased (the reason is already messaged by canPurchaseGenerator), - purchases directly when confirmation is disabled, - otherwise requests a chat confirmation and only purchases on confirm. Adds the buy-confirmation setting, a confirm-generator-purchase locale string, and tests for the helper and the setting default. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01D7NWPeGXmsUJnnX42X24Rd
SonarCloud flagged the new GeneratorPreBuyEvent as duplicated code: it repeated the targetPlayer/islandUUID/generator/generatorID fields and accessors that GeneratorBuyEvent, GeneratorActivationEvent and GeneratorUnlockEvent already duplicated among themselves. Introduce an abstract GeneratorEvent base holding those common fields and their getters/setters, and have all four events extend it. The change is backwards compatible: the public accessors are simply inherited, so external listeners are unaffected. Each concrete event keeps its own HandlerList, as Bukkit requires for correct per-type routing. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01D7NWPeGXmsUJnnX42X24Rd
Add cancellable GeneratorPreBuyEvent (#137)
Generators produce blocks from a BlockFormEvent (lava/water flow) rather than a player mining a block, so Bukkit's BlockDropItemEvent - which requires a Player and a broken BlockState - does not fit. Instead add a dedicated cancellable GeneratorTreasureDropEvent, fired in MagicGenerator just before a treasure is dropped. Listeners can cancel the event to veto the drop, or replace the ItemStack / drop location to modify it. A backwards-compatible processBlockReplacement overload threads the island through for event context; the existing two-argument method delegates with a null island. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01D7NWPeGXmsUJnnX42X24Rd
Now that the shared GeneratorEvent base exists on develop (#137), make GeneratorTreasureDropEvent extend it to drop the duplicated generator/generatorID/islandUUID fields and accessors. Treasure drops have no associated player, so null is passed for the user. The location and itemStack remain event-specific. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01D7NWPeGXmsUJnnX42X24Rd
Add cancellable GeneratorTreasureDropEvent for treasure drops (#140)
Revoke permission-gated generators when island owner loses permission (#133)
Stable generator ordering by unique id (#123)
Add optional purchase confirmation before buying a generator (#109)
Generators can now require other generator tiers to be unlocked before they become available, enabling progression chains (e.g. Gen1 before Gen2). - GeneratorTierObject gains a requiredGeneratorTiers set (unique ids), persisted via @expose and copied in clone(). - checkGeneratorUnlockStatus only unlocks a generator once all of its required tiers are already unlocked. Tiers are streamed in priority order, so a lower-priority prerequisite is unlocked earlier in the same pass. - The requirements description shows a "Required Generators" section for locked generators, with new en-US locale strings. Configurable via generator export/import for now; an admin GUI selector can follow. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01D7NWPeGXmsUJnnX42X24Rd
Add a MultiGeneratorSelector (mirroring MultiBiomeSelector) and a REQUIRED_GENERATORS button in the generator edit panel so admins can pick prerequisite generators from a GUI. Shift-click resets the list. New en-US locale strings for the button, the selector title and its accept button. Also add GeneratorTierObjectTest covering the new requiredGeneratorTiers field default, accessors and clone copy, addressing the SonarCloud new-code coverage note on the data model. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01D7NWPeGXmsUJnnX42X24Rd
- Requirements lore and the edit-panel button now fall back to showing the raw generator id when a prerequisite id cannot be resolved (deleted/renamed), instead of silently dropping it, so a locked generator always shows what is blocking it. - MultiGeneratorSelector now filters to deployed generators only, since non-deployed tiers can never be unlocked and would permanently lock their dependents; this matches its documented behaviour. - Fix the misleading @param consumer Javadoc (null is passed as the value on cancel; the consumer itself is never null). - Drop the now-unused Objects import in GeneratorEditPanel. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01D7NWPeGXmsUJnnX42X24Rd
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
SonarCloud: - GeneratorEditPanel: extract duplicated "shift-click-to-reset" tip and ".list" suffix literals into constants (S1192). - MultiGeneratorSelector: use Stream.toList() instead of collect(Collectors.toList()) (S6204) and replace the two-branch switch with an if/else (S1301); drop the now-unused Collectors import. Review: - GeneratorTierObject.requiredGeneratorTiers is now null-safe: the setter normalizes null to an empty set, the getter lazily initialises a null field (guards deserialized JSON), and clone() goes through the getter, so clone()/containsAll()/isEmpty() can no longer NPE. - MultiGeneratorSelector now also shows generators that are already selected even if they would otherwise be filtered out (undeployed or default), so existing selections remain visible and deselectable instead of being hidden yet persisted. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01D7NWPeGXmsUJnnX42X24Rd
Add prerequisite-generator requirement (#88)
Generators can now be flagged to activate automatically as soon as they are unlocked, making it easy to manage progressive generator tiers via bundles without relying on default generators. - GeneratorTierObject gains an activateOnUnlock boolean (@expose, cloned). - unlockGenerator auto-activates the generator when the flag is set, via a new userless autoActivateGenerator helper that respects the active-generator limit and the overwrite-on-active setting, fires the GeneratorActivationEvent, and skips the (now irrelevant) click-to-activate notification. - Generator edit panel gains an ACTIVATE_ON_UNLOCK toggle button, with new en-US locale strings. Auto-activation bypasses activation/purchase cost, as it is a configuration-driven automatic action. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01D7NWPeGXmsUJnnX42X24Rd
autoActivateGenerator now: - Returns whether it actually activated. unlockGenerator only skips the click-to-activate notification when activation succeeded, so a tier that stays unlocked-but-inactive (active limit reached without overwrite, or activation event cancelled) still notifies the player. - Fires the cancellable activation event *before* mutating the active list, so a cancelled activation no longer loses an already active generator when overwrite-on-active is enabled. - Frees a slot via deactivateGenerator (firing the deactivation event) when a user is present, instead of silently removing the old generator; aborts if the deactivation is cancelled. - Sends the "generator disabled" hint when the addon is not allowed on the island, matching manual activation. Adds a regression test that a cancelled activation event preserves the existing active generator. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01D7NWPeGXmsUJnnX42X24Rd
Add activate-on-unlock option for generators (#106)
Adds "/{admin} generator reset <player>", a confirmable admin subcommand
that resets a single island's generator data (unlocked, purchased and
active generators) without touching the rest of the database.
- StoneGeneratorManager.resetIslandData wipes the island's stored data
and recreates a fresh default data object so the island keeps working.
- New ResetCommand subcommand (permission admin.stone-generator.reset)
with player tab-completion and a confirmation prompt.
- New en-US locale strings for the command and the success message.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D7NWPeGXmsUJnnX42X24Rd
SonarCloud flagged the new ResetCommand as duplicating GeneratorWhyCommand (identical player tab-completion and target-resolution). Extract two shared static helpers in GeneratorAdminCommand - playerTabComplete and resolveTargetUUID - and use them from both subcommands, removing the duplicated block. Review feedback: - resetIslandData now recreates the data object via addIslandData, which works even for ownerless islands (e.g. spawn), where validateIslandData returns early; validateIslandData is still called for owned islands. This ensures reset never deletes data without recreating it. - The reset command falls back to the typed argument for the player name when the server cannot resolve a name for the UUID, so confirmation and success messages are never blank. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01D7NWPeGXmsUJnnX42X24Rd
The static helpers only removed part of the duplication SonarCloud flagged between ResetCommand and GeneratorWhyCommand; the identical execute preamble (arg check + UUID resolution) and tab-completion remained. Introduce an abstract PlayerTargetCommand base (extends ConfirmableCommand) that handles argument validation, target-UUID resolution and player tab-completion, and delegates to an abstract executeForTarget(user, name, uuid). GeneratorWhyCommand and ResetCommand now extend it and only implement setup() and their own executeForTarget, removing the duplicated block. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01D7NWPeGXmsUJnnX42X24Rd
The remaining SonarCloud duplication was the structurally identical constructor + setup() shared by GeneratorWhyCommand and ResetCommand (Sonar normalizes the differing string literals). Implement setup() once in the PlayerTargetCommand base, deriving the permission and locale keys from the subcommand label, and remove the per-command setup() overrides. The subcommands now only provide a constructor and their own executeForTarget. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01D7NWPeGXmsUJnnX42X24Rd
Add admin command to reset a player's generator data (#149)
Adds a lose-tiers-on-level-loss config option (default false). When enabled, generators that were unlocked purely by reaching an island level are locked again if the island level later drops below their required level. - Settings.loseTiersOnLevelLoss (lose-tiers-on-level-loss, default false). - checkGeneratorUnlockStatus now calls revokeLevelLockedGenerators, which removes level-gated tiers from the unlocked and active lists when the island level is below their requirement. Runs on the existing IslandLevelCalculatedEvent -> checkGeneratorUnlockStatus path. - Purchased tiers are always kept, so players never lose generators they actually paid for. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01D7NWPeGXmsUJnnX42X24Rd
Add option to lose level-gated tiers when island level drops (#118)
Generators can now require an AOneBlock phase to be reached before they unlock, enabling OneBlock progression-gated generators. - Adds aoneblock as a provided-scope dependency (mirrors level/bank). - GeneratorTierObject.requiredPhase (String, @expose, cloned, empty by default; null-normalised). - checkGeneratorUnlockStatus only unlocks a phase-gated generator once the island's block count has reached the required phase's starting block, via AOneBlock's getOneBlockManager().getPhase(name) and getOneBlocksIsland(island).getBlockNumber(). Non-AOneBlock worlds never satisfy a phase requirement. - Requirements lore shows a "Required Phase" line ([phase]) with new en-US locale strings. Configurable via generator export/import for now; an admin GUI editor can follow (the edit panel is currently full). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01D7NWPeGXmsUJnnX42X24Rd
…ment Add AOneBlock phase requirement for generators (#121)
Completes the OneBlock progression unlocking from #117 (the phase part is handled by #121): a generator can now require a number of OneBlock blocks to have been broken on the island before it unlocks - a level-free way to gate generators behind digging progress. - GeneratorTierObject.requiredBlockCount (int, @expose, cloned, 0 = none). - checkGeneratorUnlockStatus only unlocks such a generator once the island's OneBlock block count (getOneBlocksIsland(island).getBlockNumber, same value as /ob count) has reached the requirement. Non-AOneBlock worlds never satisfy it. Shares a getAOneBlock helper with the phase check. - Requirements lore shows a "Required Blocks Broken" line ([block-count]) with new en-US locale strings. Configurable via generator export/import for now; admin GUI editor to follow (edit panel is full). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01D7NWPeGXmsUJnnX42X24Rd
Add OneBlock block-count requirement for generators (#117)
|
Contributor
There was a problem hiding this comment.
Pull request overview
This PR bumps the addon version and introduces several new generator-related capabilities: richer event hooks (treasure drops + pre-buy), new unlock/visibility requirements (prerequisite generators, AOneBlock phase/block-count gating), optional auto-activation on unlock, a purchase confirmation flow in panels, and an admin “reset player generator data” command.
Changes:
- Add cancellable events:
GeneratorTreasureDropEvent(treasure interception) andGeneratorPreBuyEvent(pre-purchase veto), and refactor existing generator events to share a common base. - Extend generator tier requirements (required generators, AOneBlock phase, block count) + optional auto-activate-on-unlock, with corresponding panel UI and unlock logic.
- Add buy-confirmation chat flow for panel purchases and introduce an admin reset subcommand, plus extensive new tests and locale strings.
Reviewed changes
Copilot reviewed 28 out of 29 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| src/main/java/world/bentobox/magiccobblestonegenerator/tasks/MagicGenerator.java | Fires treasure-drop event and uses it to allow cancellation/modification of treasure drops. |
| src/main/java/world/bentobox/magiccobblestonegenerator/listeners/GeneratorListener.java | Passes island context into block replacement for better event context. |
| src/main/java/world/bentobox/magiccobblestonegenerator/events/GeneratorTreasureDropEvent.java | New cancellable event for treasure drops with mutable drop item/location. |
| src/main/java/world/bentobox/magiccobblestonegenerator/events/GeneratorPreBuyEvent.java | New cancellable pre-purchase event to allow external requirements/veto. |
| src/main/java/world/bentobox/magiccobblestonegenerator/events/GeneratorEvent.java | New shared base for generator events (common fields + accessors). |
| src/main/java/world/bentobox/magiccobblestonegenerator/events/GeneratorActivationEvent.java | Refactored to extend GeneratorEvent. |
| src/main/java/world/bentobox/magiccobblestonegenerator/events/GeneratorBuyEvent.java | Refactored to extend GeneratorEvent. |
| src/main/java/world/bentobox/magiccobblestonegenerator/events/GeneratorUnlockEvent.java | Refactored to extend GeneratorEvent and clarify semantics. |
| src/main/java/world/bentobox/magiccobblestonegenerator/managers/StoneGeneratorManager.java | Adds prerequisite/phase/block-count gating, revocation logic, auto-activation, pre-buy event, and island data reset. |
| src/main/java/world/bentobox/magiccobblestonegenerator/database/objects/GeneratorTierObject.java | Adds new tier requirement fields + activate-on-unlock flag and clones them correctly. |
| src/main/java/world/bentobox/magiccobblestonegenerator/config/Settings.java | Adds buy-confirmation and lose-tiers-on-level-loss configuration options. |
| src/main/java/world/bentobox/magiccobblestonegenerator/panels/CommonPanel.java | Centralizes purchase flow and adds optional chat confirmation. |
| src/main/java/world/bentobox/magiccobblestonegenerator/panels/player/GeneratorViewPanel.java | Routes BUY action through the shared confirmed purchase helper. |
| src/main/java/world/bentobox/magiccobblestonegenerator/panels/player/GeneratorUserPanel.java | Routes BUY action through the shared confirmed purchase helper. |
| src/main/java/world/bentobox/magiccobblestonegenerator/panels/admin/GeneratorEditPanel.java | Adds UI for prerequisite generators + activate-on-unlock toggle. |
| src/main/java/world/bentobox/magiccobblestonegenerator/panels/admin/BundleEditPanel.java | Makes generator ordering stable by unique id to avoid rename reorder. |
| src/main/java/world/bentobox/magiccobblestonegenerator/panels/utils/MultiGeneratorSelector.java | New multi-select UI for prerequisite generator selection. |
| src/main/java/world/bentobox/magiccobblestonegenerator/commands/admin/GeneratorAdminCommand.java | Adds player-target base command + new reset subcommand with confirmation. |
| src/main/resources/locales/en-US.yml | Adds/updates messages for new UI, requirements, confirmations, and reset flow. |
| pom.xml | Bumps build version and adds provided aoneblock dependency. |
| CLAUDE.md | Updates contributor documentation and package map. |
| src/test/java/world/bentobox/magiccobblestonegenerator/tasks/MagicGeneratorTest.java | New tests for treasure-drop event behavior (cancel/replace/drop). |
| src/test/java/world/bentobox/magiccobblestonegenerator/panels/CommonPanelPurchaseTest.java | New tests for buy-confirmation purchase flow. |
| src/test/java/world/bentobox/magiccobblestonegenerator/managers/StoneGeneratorManagerTest.java | Adds tests for ordering, gating, revocation, auto-activation, pre-buy event, reset. |
| src/test/java/world/bentobox/magiccobblestonegenerator/events/GeneratorTreasureDropEventTest.java | New unit tests for the new treasure drop event. |
| src/test/java/world/bentobox/magiccobblestonegenerator/events/GeneratorPreBuyEventTest.java | New unit tests for the new pre-buy event. |
| src/test/java/world/bentobox/magiccobblestonegenerator/database/objects/GeneratorTierObjectTest.java | New unit tests for new tier fields (required gens/phase/blockcount/activate). |
| src/test/java/world/bentobox/magiccobblestonegenerator/commands/admin/GeneratorAdminCommandTest.java | Updates tests to cover new reset admin command/help output. |
| .idea/modules.xml | Adds IntelliJ module metadata (likely unintended to commit). |
Files not reviewed (1)
- .idea/modules.xml: Generated file
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+150
to
+163
| if (!treasureEvent.isCancelled() && treasureEvent.getItemStack() != null) | ||
| { | ||
| ItemStack finalDrop = treasureEvent.getItemStack(); | ||
| Location dropLocation = treasureEvent.getLocation(); | ||
|
|
||
| Why.report(location, "Dropping treasure " + finalDrop + " by " + generatorTier.getUniqueId()); | ||
|
|
||
| // drop item naturally in the location of the block | ||
| dropLocation.getWorld().dropItemNaturally(dropLocation, finalDrop); | ||
| } | ||
| else | ||
| { | ||
| Why.report(location, "Treasure drop cancelled by " + generatorTier.getUniqueId()); | ||
| } |
Comment on lines
+31
to
+42
| * @param generator the generator | ||
| * @param user the user, or null if there is no associated user | ||
| * @param islandUUID the island unique id | ||
| */ | ||
| protected GeneratorEvent(GeneratorTierObject generator, @Nullable User user, String islandUUID) | ||
| { | ||
| this.generator = generator.getFriendlyName(); | ||
| this.generatorID = generator.getUniqueId(); | ||
|
|
||
| this.targetPlayer = user == null ? null : user.getUniqueId(); | ||
| this.islandUUID = islandUUID; | ||
| } |
Comment on lines
+45
to
+53
| /** | ||
| * Gets target player. | ||
| * | ||
| * @return the target player | ||
| */ | ||
| public UUID getTargetPlayer() | ||
| { | ||
| return targetPlayer; | ||
| } |
Comment on lines
+67
to
+75
| /** | ||
| * Gets island uuid. | ||
| * | ||
| * @return the island uuid | ||
| */ | ||
| public String getIslandUUID() | ||
| { | ||
| return islandUUID; | ||
| } |
Comment on lines
+98
to
+101
| this.filterElements = this.elements.stream(). | ||
| filter(element -> element.getFriendlyName().toLowerCase().contains(this.searchString.toLowerCase())). | ||
| distinct(). | ||
| toList(); |
Comment on lines
+1
to
+8
| <?xml version="1.0" encoding="UTF-8"?> | ||
| <project version="4"> | ||
| <component name="ProjectModuleManager"> | ||
| <modules> | ||
| <module fileurl="file://$PROJECT_DIR$/magiccobblestonegenerator.iml" filepath="$PROJECT_DIR$/magiccobblestonegenerator.iml" /> | ||
| </modules> | ||
| </component> | ||
| </project> No newline at end of file |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



No description provided.