This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Upgrades is a BentoBox addon (Paper/Bukkit plugin) that lets island players purchase upgrades using Vault economy. It hooks into BentoBox GameMode addons (BSkyBlock, AcidIsland, CaveBlock, SkyGrid, AOneBlock) and optionally integrates with the Level and Limits addons.
Upgrades runs within the BentoBox system as a plugin/addon to it. For coding, testing, and other patterns, it can and should draw on what other addons and BentoBox itself does. So the wider code base should be utilized when needed. This can be found at https://bentobox.world (GitHub) and the CI system is in https://ci.bentobox.world (CodeMC).
# Build (produces JAR in target/)
mvn clean package
# Run all tests
mvn test
# Run a single test class
mvn test -Dtest=UpgradesAddonTest
# Run a specific test method
mvn test -Dtest=UpgradesAddonTest#testOnEnableJava 21 is required. The surefire plugin is configured with --add-opens flags so tests work with MockBukkit.
UpgradesAddon — Main entry point extending BentoBox's Addon. Lifecycle:
onLoad: loads config, createsSettingsonEnable: iterates all non-disabled GameMode addons, registersPlayerUpgradeCommandin each, createsUpgradesManager, hooks optional soft-deps (Level, Limits, Vault), instantiates and registers allUpgradeobjectsonDisable: async-saves all cachedUpgradesDatato DB
UpgradesManager — Resolves upgrade tiers per-world by merging global defaults with game-mode-specific overrides from Settings. Every public method takes a World to look up the active GameModeAddon name and apply the right tier config.
Settings — Parses config.yml into typed tier maps. Per-upgrade-type maps exist in two layers: default (global) and custom (per game mode). UpgradesManager merges them on each lookup.
Upgrade (abstract) — Base class for all upgrade types. Key contract:
updateUpgradeValue(user, island)— called each time the panel opens; must populateplayerCacheviasetUpgradeValues()andsetOwnDescription()canUpgrade(user, island)— checks island level and Vault balance; override and callsuperdoUpgrade(user, island)— withdraws Vault cost, increments level inUpgradesData; override and callsuperisShowed(user, island)— returnstrueby default; override to hide when maxed out
Concrete subclasses: RangeUpgrade, BlockLimitsUpgrade, EntityLimitsUpgrade, EntityGroupLimitsUpgrade, CommandUpgrade.
UpgradesData — BentoBox DataObject (table UpgradesData) storing a Map<String, Integer> of upgrade name → current level per island (uniqueId = island UUID). Levels start at 1 (first call to getUpgradeLevel inserts 1 via putIfAbsent).
Panel / PanelClick — BentoBox Panel API GUI. Panel.showPanel() iterates registered upgrades, calls updateUpgradeValue, and builds panel items. PanelClick handles the click → canUpgrade → doUpgrade flow.
- Player runs
/[gamemode] upgrades→PlayerUpgradeCommand→ opensPanel - Panel calls
upgrade.updateUpgradeValue()for each registered upgrade (populates per-user cache) - Player clicks an item →
PanelClick.onClick()→upgrade.canUpgrade()→upgrade.doUpgrade()→ panel reopens
- Island upgrade data is memory-cached in
UpgradesAddon.upgradesCache(Map<islandUniqueId, UpgradesData>) and saved async on disable or island uncache. - Per-user
UpgradeValues(islandLevel req, moneyCost, upgradeValue) are stored inUpgrade.playerCache(Map<UUID, UpgradeValues>) and are stale between panel opens. - Soft dependencies (Level, Limits, Vault) are each guarded by
isLevelProvided(),isLimitsProvided(),isVaultProvided(). Block/Entity Limits upgrades are only registered if Limits is present. - Permission-based max level overrides: upgrades check player permissions (e.g.
[gamemode].island.maxrange.[n]) to cap upgrades, taking the highest permission value found. - Tier configs support formula strings for
islandMinLevel,vaultCost, andupgradevalues that can reference%level%,%islandlevel%, and%numberofmembers%.
- Extend
Upgrade, implementupdateUpgradeValue()and overridedoUpgrade()/canUpgrade()/isShowed()as needed - Register an instance via
UpgradesAddon.registerUpgrade()inonEnable() - Add any new config sections to
Settingsand expose them viaUpgradesManager - Add locale keys to
src/main/resources/locales/en-US.yml