Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
112 commits
Select commit Hold shift + click to select a range
5069573
Stage 0: addon scaffold — ocean gamemode with interstice world
tastybento Jul 29, 2026
3ba45a0
Stage 1: seeded galaxy — placement, bands, biomes, names, lazy regist…
tastybento Jul 29, 2026
c17ca91
Fix playtest round 1: spawn command, free islands, portal leak, disco…
tastybento Jul 29, 2026
11204fe
Stage 2: island content — docks, market plazas, villagers, golems
tastybento Jul 29, 2026
0ea5242
Fix Stage 2 playtest: dock-to-shore gap and villager profession loss
tastybento Jul 29, 2026
02676ad
Stage 2b: island identity — type landmarks, dressing, configurable we…
tastybento Jul 30, 2026
9215ef9
Stage 3: travel — warp dialog, route graph, fuel, charting
tastybento Jul 30, 2026
3160b5a
Resident protection, band flag policy, navigation boss bar, starter kit
tastybento Jul 30, 2026
1c526b6
Fix warp offer: trigger and arrival at the visible border
tastybento Jul 30, 2026
5482eb8
Tune warp arrival: land 130 blocks from the destination center
tastybento Jul 30, 2026
cee20c3
Creeper-proof the markets: no block damage, players still fair game
tastybento Jul 30, 2026
bfde2be
Stage 4: economy and cargo — prices, trade dialogs, hold, expanders
tastybento Jul 30, 2026
1dcd766
Trade UX (balance/space/back buttons) + embed BlueBook pricing engine
tastybento Jul 30, 2026
fca87ec
Cap warp dialog at 8 destinations so the list fits without scrolling
tastybento Jul 30, 2026
0d3eaa0
Spawn islet at the origin + safe bed-less respawns
tastybento Jul 31, 2026
942f184
Trade quantity rows (x1/x16/All) and hide Sell when hold is empty
tastybento Jul 31, 2026
25eb360
Rower navigation: hologram compass and Star Chart map
tastybento Jul 31, 2026
d1df6ae
Starter bundle carries a little coal so the first hop can be a warp
tastybento Jul 31, 2026
09f8941
Fuel guarantee: every island sells fuel, charcoal as the fallback
tastybento Jul 31, 2026
336dea7
Two economies: customs stamps, outfitters, wild islets, career restart
tastybento Jul 31, 2026
9b91f24
The Shipwright: buy boats and chest boats at every market
tastybento Jul 31, 2026
1b7e38f
Declare default permissions for all commands in addon.yml
tastybento Jul 31, 2026
bb83691
Protected spawn island using Stranger Realms geometry overrides
tastybento Jul 31, 2026
d75417e
Spawn island visitor allowances: boats, self-defense, crafting
tastybento Jul 31, 2026
4c30cbd
Show the hologram chart automatically on boarding a boat
tastybento Jul 31, 2026
98c9f79
Teleporting while boated picks the boat (and cargo) up with you
tastybento Jul 31, 2026
7e7fa90
Add stand-still friction to the warp (BentoBox delay covers /tw spawn)
tastybento Jul 31, 2026
ea7f57b
Make /tw warp and /tw trade op-only shortcuts
tastybento Jul 31, 2026
c69b0d1
Stage 5: risk at sea - the interstice and sea encounters
tastybento Jul 31, 2026
ae11597
Make spawn a real trading island at the origin
tastybento Jul 31, 2026
a9d87a0
Outfitter stores go to the pack; audible trade outcomes
tastybento Aug 1, 2026
ef96201
Fix rank flags being silently dropped on islands
tastybento Aug 1, 2026
5f6624e
Bootstrap the spawn island after islands load, and set flags last
tastybento Aug 1, 2026
24fdc57
Grant harbor allowances at every trading island, not just spawn
tastybento Aug 1, 2026
6a171a5
Make the hold carried: pouches and expanders, boat as a bonus
tastybento Aug 1, 2026
2c2f1c6
Shipwright sells trading pouches; cargo expanders are white
tastybento Aug 1, 2026
9e7a4dd
Respawn on the plaza, not in the trees at the island centre
tastybento Aug 1, 2026
970f585
Findable wild islets, openable cargo expanders, sighting range
tastybento Aug 1, 2026
40b3e89
Fix the pouch soft-lock: cheap first pouch and a harbourmaster's charity
tastybento Aug 1, 2026
77a5981
Flat pouch price: escalation was defeated by dropping a pouch
tastybento Aug 1, 2026
851251f
Port scan: opening the chart at an island charts its neighbours
tastybento Aug 1, 2026
76b32af
Make sea encounters fight: re-target, and crews abandon ship
tastybento Aug 1, 2026
aa3c88d
Crews abandon ship on sighting, not just at close range
tastybento Aug 1, 2026
8d7f99a
Vary the open sea through the ocean biomes, seeded and gradual
tastybento Aug 1, 2026
46962a3
Encounters: real monsters, spawned in their element
tastybento Aug 1, 2026
1942293
Convert the locale to MiniMessage
tastybento Aug 1, 2026
90547f8
Move all player-facing text into the locale, via the User API
tastybento Aug 1, 2026
8ba6c75
Rebuild the sea: seabed shape, vanilla structures, findable islets
tastybento Aug 1, 2026
2d7fd16
Seal the sea floor over vanilla's carvers
tastybento Aug 1, 2026
255c5e8
Break the circle: ragged coastlines and hilly islands
tastybento Aug 1, 2026
d13eb62
Stage 6a: port flag policy inverted, reputation core, fines
tastybento Aug 1, 2026
3c8ca99
Stage 6b: customs scans, contraband, and the smuggler's chase
tastybento Aug 1, 2026
c968fb0
Fix customs: title glyph, silent scans after a warp, patrols on land
tastybento Aug 1, 2026
e121086
Make contraband pay, and make the chase runnable
tastybento Aug 1, 2026
1f0c4da
Stage 6c: police response, PvP override, visible bounties
tastybento Aug 1, 2026
8a24166
Stop a failed warp from killing new players outright
tastybento Aug 1, 2026
b714f5b
Fix suffocation on warp arrival, and add /twadmin warpfail
tastybento Aug 1, 2026
77a5eeb
Low fuel warning, and show the security band on the boss bar
tastybento Aug 1, 2026
a6a9533
Remove /tw spawn: it had become a free warp home
tastybento Aug 1, 2026
c625963
Make /tw go a door into the ocean rather than a teleport
tastybento Aug 1, 2026
5f59c6b
Add a DOCK marker to the hologram chart
tastybento Aug 1, 2026
fee3fda
Star chart: fuel range ring, reachability in the list, white names
tastybento Aug 1, 2026
5a9eaaa
Close dialogs under attack, and refuse warps with enemies close
tastybento Aug 1, 2026
f6a3db4
Make the Star Chart ephemeral: it exists while you look at it
tastybento Aug 1, 2026
bf01998
Stop warp arrivals loading chunks, and never deploy over a running se…
tastybento Aug 1, 2026
063cfe1
Light and lid the interstice, and make the ghasts visible
tastybento Aug 1, 2026
c13a302
Bring the ghasts in, let them hunt, and let the dialog be dismissed
tastybento Aug 1, 2026
e2f747d
Fix silent ghast spawn failure, and log the interstice arrival
tastybento Aug 1, 2026
0e06c5f
Stop the interstice ghasts despawning the moment they arrive
tastybento Aug 1, 2026
cdc8d98
Search pockets for contraband, and stop patrols ambushing
tastybento Aug 1, 2026
2e888e7
Fix the deploy guard, which never matched the server jar
tastybento Aug 1, 2026
dab8c14
Launch customs patrols from the dock, and stop them hitting bystanders
tastybento Aug 1, 2026
cfb4b44
Make patrols reachable, fix a false escape, move arrivals to the border
tastybento Aug 1, 2026
4f3978d
The boat is the hold: whole-coin economy, tech levels, capture rules
tastybento Aug 3, 2026
170f068
Bring README and CLAUDE.md up to date with the current game
tastybento Aug 3, 2026
fd0b458
Record the salvage economy and the requisition-board mission pattern
tastybento Aug 4, 2026
37b69b4
Plan the salvage economy as Stage 7.5
tastybento Aug 4, 2026
6a828fd
Value drift by money rather than volume (Stage 7.5 Phase 1)
tastybento Aug 4, 2026
b1e4f4c
Give salvage a market of its own (Stage 7.5 Phase 2)
tastybento Aug 4, 2026
98c70e8
Gate salvage by a port's tech level (Stage 7.5 Phase 3)
tastybento Aug 4, 2026
c6777e8
Carry NBT in the hold (Stage 7.5 Phase 4)
tastybento Aug 4, 2026
305a865
Make the hold two-way for your own goods (Stage 7.5 Phase 5)
tastybento Aug 4, 2026
180be8d
Make prices discoverable without making them published (Phase 6)
tastybento Aug 4, 2026
7e0d6d3
Put notable goods back on the shelf (Stage 7.5 Phase 7)
tastybento Aug 4, 2026
10c4620
Mark the salvage plan delivered
tastybento Aug 4, 2026
28cf611
Survive config prices written without a decimal point
tastybento Aug 4, 2026
8d6ef73
Fix a 30-slot oak boat, and show what you are selling
tastybento Aug 4, 2026
6303c6d
Redesign selling as pick-then-quantity, and guard locale keys
tastybento Aug 4, 2026
a3ef99e
Format money ourselves: "$27", never "$27.00 Dollars"
tastybento Aug 4, 2026
4fdacab
Move fuel with the mouse, and let bought coal reach the tank
tastybento Aug 4, 2026
3fee482
Declare the permissions /tw prices and priceaudit shipped without
tastybento Aug 4, 2026
0e8e894
Park the price logbook behind a flag, off by default
tastybento Aug 4, 2026
6f929a0
Record the Paper 26.2 spinning-clock quirk as upstream
tastybento Aug 4, 2026
3159dde
Stage 7 complete, interstice resources, and a run of playtest fixes
tastybento Aug 7, 2026
af5ab5b
Answer "where did my boat go?" - four guards and a logbook
tastybento Aug 7, 2026
fa5d720
The interstice becomes a destination: ship graveyard, restless floor,…
tastybento Aug 7, 2026
b55e0fb
Keep the design docs out of the public repo
tastybento Aug 7, 2026
5083367
Ship the patched MockBukkit in-repo so CI builds green
tastybento Aug 7, 2026
281f5c7
Sonar sweep: ~90 of 114 open issues fixed, two real bugs among them
tastybento Aug 7, 2026
fc04cae
Build and analyze on GitHub Actions
tastybento Aug 7, 2026
a972c3b
Sonar round two: the CI scanner's deeper findings
tastybento Aug 7, 2026
fc0ab32
Sonar stragglers: matchMaterial over valueOf, last two literals
tastybento Aug 7, 2026
efef98d
The last three actionable Sonar opens
tastybento Aug 7, 2026
8ebe934
Band keys are enum names, not literals
tastybento Aug 7, 2026
2882adf
Coverage push: 363 to 598 tests, every latent-bug suspect run to ground
tastybento Aug 7, 2026
606b8b5
Clean the coverage push's own Sonar noise
tastybento Aug 7, 2026
a146e5e
Sonar test noise: the last eleven
tastybento Aug 7, 2026
d88001f
The galaxy is an ocean
tastybento Aug 8, 2026
9874348
Restart strikes the boat's avatars, not just its record
tastybento Aug 8, 2026
135ad46
The one aesthetic knob: pick the spawn island's biome in config
tastybento Aug 8, 2026
e06f414
End the campfire respawn death-loop
tastybento Aug 8, 2026
6f5eade
The respawn safety net covers island members too
tastybento Aug 8, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
name: Build
on:
push:
branches:
- develop
- main
- master
pull_request:
types: [opened, synchronize, reopened]
jobs:
build:
name: Build
runs-on: ubuntu-latest
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of Sonar analysis
# JDK 25, not the 17 SonarCloud's wizard suggests: the Paper 26.2 and
# BentoBox dependencies ship Java 25 bytecode (class version 69), which
# older compilers cannot read. The pom still compiles TradeWinds' own
# sources at release 21.
- name: Set up JDK 25
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: 25
- name: Cache SonarCloud packages
uses: actions/cache@v4
with:
path: ~/.sonar/cache
key: ${{ runner.os }}-sonar
restore-keys: ${{ runner.os }}-sonar
- name: Cache Maven packages
uses: actions/cache@v4
with:
path: ~/.m2
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
restore-keys: ${{ runner.os }}-m2
# No MockBukkit prep step (compare GushBlock): the locally patched
# MockBukkit the tests need ships INSIDE this repo under libs/ as a
# file-based Maven repository, so a bare checkout builds green.
- name: Build
run: mvn -B verify
# SonarCloud analysis: runs only when a SONAR_TOKEN is available and
# never fails the build. Project key, organization and host live in the
# pom's sonar.* properties.
- name: SonarCloud analysis
if: ${{ env.SONAR_TOKEN != '' }}
continue-on-error: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
run: mvn -B org.sonarsource.scanner.maven:sonar-maven-plugin:sonar
13 changes: 13 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
target/
*.iml
.idea/
.classpath
.project
.settings/
.DS_Store
database/
database_backup/
docs/
files/
files.zip
.claude/
181 changes: 181 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
# CLAUDE.md

Guidance for Claude Code working in this repository.

## Commands

```bash
mvn clean package # build (jar in target/)
mvn test # all tests
mvn test -Dtest=ClassName # one test class
```

Deploy for in-game testing: `./scripts/deploy.sh` (builds, then installs to
`/Users/ben/Minecraft/26.2/plugins/BentoBox/addons/`).

**Never overwrite the jar while the server is running** - the deploy script
refuses to. The plugin classloader reads classes lazily from the jar, so
replacing it invalidates the handle and any not-yet-loaded class throws
`NoClassDefFoundError`. When that lands inside chunk generation, Paper calls it
an unrecoverable chunk system failure and stops the server. The script has a
second guard: it also refuses while `latest.log` has been written in the last
minute, so a just-stopped server needs about a minute's wait - wait it out
rather than bypass it.

After any change to the hold, boat or ocean model, the test server needs a
**clean slate**: delete the `tradewinds_world*` folders and the `BoatHold`,
`TWPlayerData`, `TWIslandData` database folders. Stale records from a previous
model are indistinguishable from bugs. Say so when handing a build over.

## Project

**TradeWinds** is a BentoBox GameModeAddon for Paper **26.2**: an endless
procedurally generated ocean of NPC trading islands — buy low, sell high,
smuggle, hunt bounties, turn pirate. Requirements live in `docs/TRADEWINDS_SPEC.md`
(the authoritative spec; read it first). Design rationale is in
`docs/tradewinds-design-decisions.md`, the stage plan in `docs/tradewinds-dev-plan.md`.
`docs/PROGRESS.md` records what is done and pitfalls hit; `docs/TESTING.md` is the
manual test plan, ordered by risk (Tier 1 smoke first) - add new checks to the
right tier, not to the end; `docs/TESTING-archive.md` is the old per-stage list,
history only. Update PROGRESS and TESTING as features land.
**`docs/` is git-ignored** (ruled 2026-08-07: internal design docs stay out of
the public repo) — the files live only in this working copy, so never delete
the folder, and don't expect it in a fresh clone.

Load-bearing design rules (from the spec — breaking one is a bug):
trading transacts only against the **virtual hold**; **trader-bought** cargo
leaves the hold only by sale or destruction (player-loaded salvage may be
withdrawn — narrowed 2026-08-03, see `docs/tradewinds-salvage-plan.md`, and the
distinction is a PDC mark, `travel/CargoMark`); everything downstream of the ocean seed is a pure
function of (seed, position) with **no Bukkit imports** (package
`world.bentobox.tradewinds.ocean`), unit-tested headlessly; no End world ever;
interstice re-engage is always free; police mobs never drop loot.

## The boat/hold model (read before touching cargo or boats)

`docs/tradewinds-hold-plan.md` is **normative** here — it wins over the spec on
hold and boat mechanics. `docs/tradewinds-salvage-plan.md` is normative for the
salvage economy, the NBT-aware hold and price discovery — read it before
touching pricing, drift or hold contents, because it deliberately narrows the
one-way-cargo rule below to trader-bought cargo only.

- **The hold belongs to the BOAT, not the player.** One `BoatHold` record
(material, cargo, fuel, expanders, owner, last-seen position, item TTL) is
identified by a PDC id (`tradewinds:boat-id`) stamped on **both** the boat
entity and its item form. `TWPlayerData` only points at `activeBoat` and
`oldBoat`. Cargo therefore exists exactly once, however the avatar travels.
- **Any new route that produces a boat must stamp it** (`BoatService.stamp`).
An unstamped hull has no lore and can never open its hold. This has bitten
three times: vanilla placement (`EntityPlaceEvent`), teleport pickup, and
crafting (the item lands on the **cursor**, not in a slot). `HoldGui`
self-heals one narrow case; do not rely on it.
- **Match boats by identity, never by material.** Two oak boats are not the
same boat.
- **Losing a boat is not abandoning one.** `HoldManager.setActiveBoat` demotes
the previous boat to an unowned OLD BOAT; `clearActiveBoat` just drops the
pointer. Taking a boat also strips its former owner — miss that and the
victim keeps phantom slots and the login path hands the boat back.
- **Cargo is a list of stacks, one per slot** (`BoatHold.cargo`), not
material→amount: a worn bow, a mint bow and a Silk Touch pick are three goods.
Slot arithmetic lives in `travel/CargoStore`; fuel stays material-keyed because
fuel is fungible. **Match cargo with `isSimilar`, never by material.**
- **Money is whole coins.** Buy prices `ceil`, sell prices `floor` — the
direction stops the spread closing (nearest-rounding is exploitable). Never
format money by hand: `economy.Money.format(addon, amount)` renders
"$1,728" — symbol from `economy.currency-symbol`, no cents. (It used to ask
Vault; reversed 2026-08-03 when the server economy printed "27.00 Dollars"
over our whole coins.) The locale never carries a `$` of its own — the symbol
arrives inside the formatted value.

## Environment (verified — do not "upgrade" blindly)

- Paper API `26.2.build.40-alpha` (Java 25 bytecode: build with **JDK 25**,
compile at release 21), BentoBox `3.18.1` from `~/.m2`, test server runs
BentoBox 3.21.1-SNAPSHOT.
- Test server: `/Users/ben/Minecraft/26.2` — has Vault, PlaceholderAPI,
LuckPerms, Multiverse, Border addon, and other gamemodes (AcidIsland,
AOneBlock, Gusher…) — TradeWinds must coexist with all of them.
- `org.bukkit.Sound` is an **interface** now — no `valueOf`; resolve
config-supplied sound names via
`RegistryAccess.registryAccess().getRegistry(RegistryKey.SOUND_EVENT)`.

## Testing quirks (important)

MockBukkit has **no 26.2 release**; tests run against the locally patched jar
`org.mockbukkit.mockbukkit:mockbukkit-v26.1.2:4.113.4-p262-2`, which **ships
inside this repo** (`libs/`, a file-based Maven repository declared in the
pom) so CI and fresh clones build green. It was built by
`~/git/GushBlock/scripts/build_patched_mockbukkit.py` (prereq: unzip the
paper-api jar to `/tmp/paperapi`). To update it: rerun the script, **bump the
`-2` suffix** (a shared CI agent once served a stale same-versioned copy from
its cache - never reuse a version), copy jar+pom into `libs/`, update
`mock-bukkit.version` in the pom.
Two class-level shims are copied into test sources (Adventure 4→5 breakage):
`org/mockbukkit/mockbukkit/adventure/PlainTextComponentProviderImpl` and
`net/kyori/adventure/util/Buildable`. Surefire needs the long `--add-opens`
argLine (already in pom.xml) or MockBukkit reflection dies on Java 25.
Force-init `org.bukkit.Tag.LEAVES` before static-mocking Bukkit (stale-mock
trap). Tests extend `world.bentobox.tradewinds.CommonTestSetup` (adapted from
Gusher/AOneBlock). Never leave stale files in `target/test-classes` when
renaming resources.

More traps, each of which cost a playtest:
- **`ItemStack` meta does not work** under this setup (the item factory is a
bare mock, so `getItemMeta()` returns null). To test PDC behaviour, mock the
ItemStack with a mocked `ItemMeta` and `PersistentDataContainer`.
- **Do not test against a hand-written stand-in for a manager.** `TestHolds`
drives the REAL `HoldManager` over an in-memory `Database` (see
`dataobjects/TestHoldManager`); an earlier fake "passed" rules the production
code did not implement, and five bugs shipped.
- The inherited `world` field in `CommonTestSetup` **shadows the `world.`
package root**, so fully-qualified `world.bentobox...` references fail to
compile inside those tests. Import the simple names.
- `PlayerInteractEvent` at AIR is *born cancelled*: never pair
`ignoreCancelled = true` with RIGHT_CLICK_AIR handling. Check
`useItemInHand() == DENY` instead.
- Bare `yes`/`no`/`on`/`off` are YAML 1.1 **booleans** — never use them as
locale keys. `ResourceYamlTest` fails the build on duplicate keys, because
Bukkit only warns and then silently drops one.
- **`Settings.java` can never hold static constants.** BentoBox's YAML loader
builds a PropertyDescriptor for EVERY declared field; any field without a
getter/setter (a `static final`, say) makes `loadConfigObject()` throw and
the addon boots disabled with null settings (found 2026-08-07 via a Sonar
cleanup). Duplicated string keys in Settings are the price of the loader.
- **BentoBox REPLACES `Map` settings from `config.yml`, it does not merge them**
(`YamlDatabaseHandler.deserializeMap`). A partial map in the shipped config
silently overrides the whole code default — `economy.base-prices` shipped 27
of 112 entries, so ~50 goods were unsellable on every real server while the
unit tests, which read the code default, were perfectly happy. Any `@ConfigEntry`
map must be complete in `config.yml`; `SettingsTest` now fails the build if the
two drift.

## Reference repos (all local)

- `~/git/bentobox` — BentoBox core source.
- `~/git/addon-acidisland` — GameModeAddon anatomy, ocean worlds, nether roof,
the dismount/teleport/re-seat boat pattern.
- `~/git/poseidon` — ocean generator (PerlinOctaveGenerator, sea floor noise,
BiomeProvider, BlockPopulator decoration).
- `~/git/GushBlock` — newest 26.2-era addon: pom, test bootstrap, patched
MockBukkit, `docs/API_VERIFICATION.md` (verified 26.2 API facts).
- `~/git/Boxed` — structure/jigsaw placement patterns (Stage 2).
- `~/git/Border` — border display addon (passable visual border, Stage 3).
- `~/git/bluebook` — origin of the pricing logic now embedded in
`economy.PriceEngine` (recipe-derived base prices).

Follow BentoBox conventions: `Config<Settings>` + `@ConfigEntry`/`@StoreAt`,
`Database<DataObject>` + cache managers, `FlagListener`, `DefaultPlayerCommand`
/`DefaultAdminCommand`, locale keys under `tradewinds.`, every gameplay number
in config from the stage it's introduced — no hardcoded gameplay values.

**All player-facing text lives in the locale** — never build strings or
Components in code, or the game mode cannot be translated. Locale formatting
is MiniMessage (`<red>text</red>`); legacy `&` codes are deprecated.
Never call MiniMessage yourself: use the `User` API, which is locale-aware —
`user.sendMessage(key, vars...)` for chat, and
`user.getTranslationAsComponent(key, vars...)` wherever a Component is needed
(dialogs, boss bars, holograms, item names, inventory titles). The no-variable
call is ambiguous between overloads, so pass `new String[0]`.
Locale strings can also carry `[actionbar]`, `[title]`, `[subtitle]` and
`[sound:...]` markers — BentoBox routes and formats those itself, so prefer
them over calling `sendActionBar`/`playSound` around a message.
84 changes: 84 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1 +1,85 @@
# TradeWinds

A BentoBox game mode of sea trading, smuggling, and piracy: an endless
procedurally generated ocean dotted with NPC trading islands. You start with a
rowing boat — **the boat is your cargo hold** — and get rich buying low and
selling high, honestly or otherwise: smuggling contraband past customs,
hunting bounties, or taking other sailors' ships.

Inspired by TradeWars 2002 and Elite, rebuilt in Minecraft terms.

> Status: in development. Playable end to end (trade, travel, crime, boats);
> player-owned islands are the remaining MVP stage. The data model is not
> stable yet — expect to wipe worlds and databases between builds.

## How it plays

**The ocean is one shareable seed.** Island positions, types, biomes, names,
security bands, tech levels and route costs are all pure functions of it, so
the same seed gives another server the same galaxy. Islands generate lazily as
players push outward, and the sea between them is dotted with wild islets —
free land to mine, farm and build on, with biome-appropriate ruins to find.

**The boat is the hold.** A player has exactly one boat, and it sizes their
cargo: twenty ranks from a two-slot bamboo raft to the 21-slot Pale Oak Chest
Boat, then installable cargo expanders beyond that. The hold is virtual and
server-authoritative — no real container ever holds cargo, and cargo leaves it
only by being sold or destroyed. Fuel lives in its own slots, so fuel and
cargo never compete for the same space.

**Trade reads the map.** Prices come from recipe-derived base values times the
island's type, tech level, security band and its own stock drift, so the best
routes are differentials you find by reading the chart. Margins are richest
where the law is thinnest.

**Travel is a choice.** Rowing is free, slow and lawless. Warping is instant
but burns fuel and can fail, dropping you into the interstice — a hostile
Nether sea — with ghasts inbound and a free way back out.

**Crime pays you into danger.** Contraband sells only at rougher ports.
Customs scan you on arrival; get caught and a patrol launches from the pier,
and you flee, fight or destroy the evidence. Reputation follows you: slip far
enough and police answer, your bounty hangs over your head, and safe markets
close to you.

**Boats can be taken.** A hull left unattended in protected island space is
safe; anywhere else it is fair game, and whoever boards it gets the cargo too.
Lose yours and the chart remembers where you left it.

## Documentation

| Document | What it is |
|---|---|
| [`TRADEWINDS_SPEC.md`](TRADEWINDS_SPEC.md) | The authoritative spec — read first |
| [`tradewinds-hold-plan.md`](tradewinds-hold-plan.md) | Normative detail for the hold, boats and capture rules |
| [`tradewinds-salvage-plan.md`](tradewinds-salvage-plan.md) | Normative plan for the salvage economy, NBT hold and price discovery |
| [`tradewinds-design-decisions.md`](tradewinds-design-decisions.md) | What was decided, why, and what is still open |
| [`tradewinds-dev-plan.md`](tradewinds-dev-plan.md) | The stage plan |
| [`tradewinds-overview.md`](tradewinds-overview.md) | The short pitch, for server admins |
| [`docs/PROGRESS.md`](docs/PROGRESS.md) | What is done, and every pitfall hit on the way |
| [`TESTING.md`](TESTING.md) | Manual test plan, ordered by risk |

## Building

```bash
mvn clean package # jar lands in target/
mvn test # 250 headless tests
```

Build with **JDK 25** (Paper 26.2 ships Java 25 bytecode); the project
compiles at release 21. Requires BentoBox 3.18.1+ on Paper 26.2.

Everything downstream of the galaxy seed lives in
`world.bentobox.tradewinds.galaxy` with **no Bukkit imports**, so the world
generation and pricing maths are unit-tested headlessly.

## Installing

Drop the jar in `plugins/BentoBox/addons/` and restart. Vault is required for
the economy; PlaceholderAPI and the Border addon are optional. TradeWinds
coexists with other BentoBox game modes.

Nearly every number is a config knob: island spacing and density, tech and
band effects, fuel and warp costs, boat ranks and prices, scan chances, police
response, reputation thresholds. The contraband and crime layers can be turned
off entirely for family-friendly servers.
Binary file not shown.
Loading
Loading