Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
0f0fb6f
feat: add COLLECTED parcel status and guard ParcelSendTask against re…
Jakubk15 Jul 3, 2026
2638dec
feat: add CollectedParcel domain and collected_parcels repository
Jakubk15 Jul 3, 2026
f834069
fix: compare return-window expiry temporally, not lexicographically
Jakubk15 Jul 3, 2026
ef1af91
feat: add conditional collect/return status flips and returnable quer…
Jakubk15 Jul 3, 2026
6ddf92e
feat: add return window, fees, attribute-check flags and return notic…
Jakubk15 Jul 3, 2026
827c547
feat: add config-driven item equivalence for parcel returns
Jakubk15 Jul 3, 2026
bee53f5
feat: add multiset return-content validator
Jakubk15 Jul 3, 2026
264d5c3
feat: keep collected parcels for the return window instead of deletin…
Jakubk15 Jul 3, 2026
54596bd
feat: add parcel return service and ParcelReturnEvent
Jakubk15 Jul 3, 2026
f47e28a
fix: keep post-commit return failures away from the refund path
Jakubk15 Jul 3, 2026
ad20fff
feat: purge collected parcels after the return window expires
Jakubk15 Jul 3, 2026
3e45231
feat: add return button, return list GUI and deposit GUI (GH-69)
Jakubk15 Jul 3, 2026
2a9f44f
fix: refuse status changes on COLLECTED parcels (GH-69)
Jakubk15 Jul 4, 2026
9f97f09
fix: contain post-commit failures in ParcelReturnService.execute (GH-69)
Jakubk15 Jul 4, 2026
6d86d46
Add Graphify to CLAUDE.md
Jakubk15 Jul 4, 2026
fb79943
fix: address GH-233 follow-up cleanups from GH-69 review
Jakubk15 Jul 4, 2026
0131680
fix: run Vault economy calls on the primary thread in ParcelReturnSer…
Jakubk15 Jul 4, 2026
df06e9b
Merge branch 'master' into feat/parcel-return-gh-69
Jakubk15 Jul 4, 2026
b9a9e6f
Merge branch 'master' into feat/parcel-return-gh-69
Jakubk15 Jul 14, 2026
87f5841
fix: make parcel returns atomic and thread-safe
Jakubk15 Jul 14, 2026
93ce93f
Add AGENTS.md
Jakubk15 Jul 14, 2026
8c117c2
feat: add configurable parcel return name format
Jakubk15 Jul 14, 2026
7991091
docs: design detailed return mismatch messages
Jakubk15 Jul 14, 2026
c23ac4b
docs: plan detailed return mismatch messages
Jakubk15 Jul 14, 2026
2c8630c
build: expand supported Modrinth game versions
Jakubk15 Jul 14, 2026
18bdf27
refactor: expose return item differences
Jakubk15 Jul 14, 2026
853d0fb
feat: diagnose parcel return mismatches
Jakubk15 Jul 14, 2026
29a66ff
feat: format return mismatch reasons
Jakubk15 Jul 14, 2026
ccc984a
feat: explain parcel return mismatches
Jakubk15 Jul 14, 2026
ce46067
fix: append mismatch details for existing configs
Jakubk15 Jul 14, 2026
287cabb
test: strengthen parcel return diagnostics coverage
Jakubk15 Jul 14, 2026
e17595d
Merge branch 'master' into feat/parcel-return-gh-69
Jakubk15 Jul 15, 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
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,12 @@
run/
out/
build/
.claude/
.codex/
.gemini/
graphify-out/

.DS_Store
[Dd]esktop.ini

!gradle/wrapper/gradle-wrapper.jar
.claude
61 changes: 61 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# AGENTS.md

This file provides guidance to Codex (Codex.ai/code) when working with code in this repository.

## Build & Run Commands

```bash
# Build the plugin JAR (output: build/libs/ParcelLockers v<version>.jar)
./gradlew shadowJar

# Run tests
./gradlew test

# Run a single test class
./gradlew test --tests "com.eternalcode.parcellockers.database.ParcelRepositoryIntegrationTest"

# Start a local Paper server with the plugin loaded (downloads Paper + dependencies automatically)
./gradlew runServer
```

Requires JDK 21+. The `runServer` task uses JetBrains JVM and auto-downloads LuckPerms, VaultUnlocked, and EssentialsX. Uncomment the DiscordSRV line in `build.gradle.kts` to test that integration locally.

## Architecture Overview

ParcelLockers is a Paper plugin (Minecraft 1.21) that lets players transfer items between parcel locker blocks across the world, with optional Discord notifications.

### Entry Point & Wiring

`ParcelLockers.java` (`onEnable`) is the manual DI root — all components are instantiated and wired there in order: config → database → repositories → managers/services → GUIs → commands → event controllers. There is no DI framework; dependencies are passed via constructors.

### Domain Layers

Each domain (`locker`, `parcel`, `content`, `delivery`, `itemstorage`, `user`, `discord`) follows a consistent layered structure:

- **Model** — plain record/class (e.g. `Locker`, `Parcel`, `User`)
- **Repository** — interface + `*OrmLite` implementation backed by H2/PostgreSQL via ORMLite
- **Manager/Service** — business logic, coordinates repository calls; repositories return `CompletableFuture<T>` for all async DB operations
- **Controller** — Bukkit `Listener` handling in-game events (block place/break/interact, player join/quit)

### Key Components

| Component | Purpose |
|---|---|
| `DatabaseManager` | Manages HikariCP connection pool; supports H2 (default, embedded) and PostgreSQL |
| `ConfigService` + okaeri-configs | Loads `config.yml` and `messages.yml` via YAML; `PluginConfig` and `MessageConfig` are the config POJOs |
| `NoticeService` + multification | Sends MiniMessage-formatted notices to players; all user-facing text goes through `MessageConfig` |
| `ParcelDispatchService` | Orchestrates sending a parcel: validates, charges economy (Vault), schedules `ParcelSendTask` |
| `ParcelSendTask` | Runs async after a configurable delay; marks parcel DELIVERED and fires the deliver notification event |
| `GuiManager` + triumph-gui | Factory for all inventory GUIs; `LockerGui` and `MainGui` are the two root GUI entry points |
| `DiscordProviderPicker` | Selects between Discord4J (standalone bot) and DiscordSRV (delegation) at startup based on detected plugins |
| `LockerPlaceController` | Uses Paper's Dialog API (unstable) to prompt for a locker description when a player places the locker item |

### Optional Integrations

- **DiscordSRV** — when present, account linking and DM notifications are delegated to it; otherwise, the plugin manages its own Discord bot via Discord4J
- **Nexo** — when present, custom item blocks can be used as locker blocks (`NexoIntegration.placeBlock`); guarded by `isPluginEnabled("Nexo")` checks
- **Vault** — required; used to charge players an economy fee when sending parcels

### Testing

Tests live in `src/test/java/`. Integration tests (e.g. `LockerRepositoryIntegrationTest`) extend `IntegrationTestSpec` and use Testcontainers (MySQL) to test repository implementations against a real database. `ParcelPageTest` is a unit test with no container dependency.
10 changes: 10 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,13 @@ Each domain (`locker`, `parcel`, `content`, `delivery`, `itemstorage`, `user`, `
### Testing

Tests live in `src/test/java/`. Integration tests (e.g. `LockerRepositoryIntegrationTest`) extend `IntegrationTestSpec` and use Testcontainers (MySQL) to test repository implementations against a real database. `ParcelPageTest` is a unit test with no container dependency.

## graphify

This project has a knowledge graph at graphify-out/ with god nodes, community structure, and cross-file relationships.

Rules:
- For codebase questions, first run `graphify query "<question>"` when graphify-out/graph.json exists. Use `graphify path "<A>" "<B>"` for relationships and `graphify explain "<concept>"` for focused concepts. These return a scoped subgraph, usually much smaller than GRAPH_REPORT.md or raw grep output.
- If graphify-out/wiki/index.md exists, use it for broad navigation instead of raw source browsing.
- Read graphify-out/GRAPH_REPORT.md only for broad architecture review or when query/path/explain do not surface enough context.
- After modifying code, run `graphify update .` to keep the graph current (AST-only, no API cost).
11 changes: 10 additions & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,17 @@ dependencies {

testImplementation("org.testcontainers:junit-jupiter:${Versions.TESTCONTAINERS}")
testImplementation("org.testcontainers:mysql:${Versions.TESTCONTAINERS}")
testImplementation("com.zaxxer:HikariCP:${Versions.HIKARICP}")
testImplementation("com.j256.ormlite:ormlite-jdbc:${Versions.ORMLITE}")
testImplementation("com.h2database:h2:${Versions.H2}")
testImplementation("mysql:mysql-connector-java:${Versions.MYSQL_CONNECTOR}")
testImplementation("de.eldoria.jacksonbukkit:paper:${Versions.JACKSON_BUKKIT}")
testImplementation("com.eternalcode:eternalcode-commons-adventure:${Versions.ETERNALCODE_COMMONS}")
testImplementation("com.eternalcode:eternalcode-commons-bukkit:${Versions.ETERNALCODE_COMMONS}")
testImplementation("com.eternalcode:eternalcode-commons-shared:${Versions.ETERNALCODE_COMMONS}")
testImplementation("com.eternalcode:multification-bukkit:${Versions.MULTIFICATION}")
testImplementation("com.github.MilkBowl:VaultAPI:${Versions.VAULT_API}")
testImplementation("dev.triumphteam:triumph-gui-paper:${Versions.TRIUMPH_GUI}")

testImplementation("io.papermc.paper:paper-api:${Versions.PAPER_API}")
testImplementation("eu.okaeri:okaeri-configs-yaml-bukkit:${Versions.OKAERI_CONFIGS}")
Expand Down Expand Up @@ -145,7 +154,7 @@ modrinth {
versionNumber.set(project.version.toString())
versionType.set(getVersionType(project.version.toString()))
uploadFile.set(tasks.shadowJar)
gameVersions.addAll("1.21.11")
gameVersions.addAll("1.21.11", "26.1", "26.1.1", "26.1.2", "26.2")
loaders.addAll("paper", "purpur")
syncBodyFrom = rootProject.file("README.md").readText()
}
Expand Down
Loading
Loading