feat(shop): stage ExcellentShop+CoinsEngine migration bundle
Replaces EZShop 1.0-SNAPSHOT (bespoke, sell-only, 27-slot) and Kiranhart
AuctionHouse 1.4.6 (ARR no-LICENSE, dupe history) with a single GPL-3
stack: ExcellentShop 5.0.1 + CoinsEngine 2.7.0 + nightcore 2.15.3.
Per SHOP-SYSTEM-DECISION.md (commit 9565f0b), Stack A wins on three
counts: GPL-3 source (vs ARR/proprietary), unified theme across shop
and AH, single-vendor support story under NightExpress.
Jars sourced from upstream Reposilite repo.nightexpressdev.com — same
artefacts a local mvn package would produce, just reproducible without
the alex9849 integration that breaks on TLS handshake. SHA256SUMS
committed for receipt; never re-fetched at swap time.
Bundle:
build/ — three jars + SHA256SUMS (~2.1MB total)
configs/ — post-first-run overrides (chest module off, /shop alias,
AH 1% tax + BIN+bid + 10 listings matches Kiranhart)
scripts/ — swap.sh, rollback.sh, lp-shop-migration.sh,
lp-shop-rollback.sh, docker-compose.patch.yml
itzg integration: COPY_PLUGINS_SRC=/plugins-custom mount per
ITZG-CUSTOM-JAR-PERSISTENCE.md, plus REMOVE_OLD_MODS_EXCLUDE expanded
with the three new globs.
LP migration grants default-tier excellentshop.* + coinsengine.*
nodes; staff tier gets *.admin equivalents to legacy
auctionhouse.moderator. Group prefixes/suffixes untouched per
feedback_lp_prefixes_locked.md.
DOES NOT touch live /data/plugins/EZShop or /data/plugins/AuctionHouse
— staging only. Operator runs swap.sh in scheduled maintenance window.
Refs: SHOP-SYSTEM-DECISION.md, AUDIT-2026-05-07.md F-11,
ITZG-CUSTOM-JAR-PERSISTENCE.md, MIGRATION-PLAN-EXCELLENTSHOP.md.
This commit is contained in:
parent
9565f0bf53
commit
4116d67eaf
18 changed files with 907 additions and 0 deletions
115
docs/ITZG-CUSTOM-JAR-PERSISTENCE.md
Normal file
115
docs/ITZG-CUSTOM-JAR-PERSISTENCE.md
Normal file
|
|
@ -0,0 +1,115 @@
|
||||||
|
# itzg/minecraft-server — Custom Plugin Jar Persistence
|
||||||
|
|
||||||
|
**Date:** 2026-05-07
|
||||||
|
**Context:** `ChatChat-1.0.0-SNAPSHOT-racked-1.jar` was dropped manually into `/data/plugins/` and disappeared after the next container restart.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Why the ChatChat jar disappeared
|
||||||
|
|
||||||
|
itzg's entrypoint runs this sequence on every start (when `REMOVE_OLD_MODS=TRUE`):
|
||||||
|
|
||||||
|
1. **Wipe** — every file in `/data/plugins/` matching `REMOVE_OLD_MODS_INCLUDE` and not matching `REMOVE_OLD_MODS_EXCLUDE` is deleted.
|
||||||
|
2. **Download** — every URL in `PLUGINS` and every Modrinth project in `MODRINTH_PROJECTS` is fetched into `/data/plugins/`.
|
||||||
|
3. **Copy** — anything listed in `COPY_PLUGINS_SRC` (or container paths inside `PLUGINS`) is rsynced in.
|
||||||
|
|
||||||
|
Our current compose has:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
REMOVE_OLD_MODS: "true"
|
||||||
|
REMOVE_OLD_MODS_INCLUDE: "*.jar"
|
||||||
|
REMOVE_OLD_MODS_EXCLUDE: "AuthLimbo*.jar"
|
||||||
|
```
|
||||||
|
|
||||||
|
So step 1 deletes **every** `*.jar` except `AuthLimbo*.jar`. The hand-placed ChatChat jar was not in any download list and not in the exclude glob, so it was nuked and never re-downloaded. AuthLimbo survives only because we explicitly excluded it.
|
||||||
|
|
||||||
|
This is documented behaviour, not a bug — itzg's design assumes plugins are declarative, sourced from URLs/Modrinth/`COPY_PLUGINS_SRC`, never hand-dropped.
|
||||||
|
|
||||||
|
## 2. Three mechanisms to make custom jars persist
|
||||||
|
|
||||||
|
| # | Mechanism | How |
|
||||||
|
|---|-----------|-----|
|
||||||
|
| A | **`REMOVE_OLD_MODS_EXCLUDE` glob** | Add `ChatChat*.jar` to the exclude list. Quick but fragile — depends on filename and only protects already-present files; doesn't handle re-deploy on a fresh volume. |
|
||||||
|
| B | **`COPY_PLUGINS_SRC` bind-mount** | Mount a host dir of custom jars read-only at e.g. `/plugins-custom`, set `COPY_PLUGINS_SRC=/plugins-custom`. Entrypoint copies them in after the wipe. Survives wipes, version-controllable, declarative. |
|
||||||
|
| C | **`PLUGINS` URL → Forgejo Release** | Upload the jar as a Forgejo Release asset, add the download URL to the existing `PLUGINS` list. Same flow as EssentialsX/spark already use. |
|
||||||
|
|
||||||
|
Note: `PLUGINS` also accepts container paths directly (e.g. `PLUGINS=/plugins-custom/ChatChat.jar`), so mechanism B can collapse into the existing `PLUGINS` env if preferred.
|
||||||
|
|
||||||
|
## 3. Recommended path for racked.ru — Mechanism B
|
||||||
|
|
||||||
|
`COPY_PLUGINS_SRC` is the cleanest fit:
|
||||||
|
- Custom jars live in the repo (or `/opt/docker/minecraft-custom-plugins/`), so they're under version control / backup.
|
||||||
|
- No external host dependency (Forgejo could be down — bind mount can't be).
|
||||||
|
- Build artefacts from `staging/chatchat/` drop straight into the mounted dir.
|
||||||
|
|
||||||
|
### docker-compose.yml diff
|
||||||
|
|
||||||
|
```diff
|
||||||
|
MODRINTH_LOADER: paper
|
||||||
|
SPIGET_RESOURCES: ""
|
||||||
|
REMOVE_OLD_MODS: "true"
|
||||||
|
REMOVE_OLD_MODS_INCLUDE: "*.jar"
|
||||||
|
- REMOVE_OLD_MODS_EXCLUDE: "AuthLimbo*.jar"
|
||||||
|
+ REMOVE_OLD_MODS_EXCLUDE: "AuthLimbo*.jar,ChatChat*.jar"
|
||||||
|
+ COPY_PLUGINS_SRC: "/plugins-custom"
|
||||||
|
volumes:
|
||||||
|
- /opt/docker/minecraft:/data
|
||||||
|
+ - /opt/docker/minecraft-custom-plugins:/plugins-custom:ro
|
||||||
|
```
|
||||||
|
|
||||||
|
Then on the host:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo mkdir -p /opt/docker/minecraft-custom-plugins
|
||||||
|
sudo cp staging/chatchat/ChatChat-1.0.0-SNAPSHOT-racked-1.jar \
|
||||||
|
/opt/docker/minecraft-custom-plugins/
|
||||||
|
sudo cp /opt/docker/minecraft/plugins/AuthLimbo-*.jar \
|
||||||
|
/opt/docker/minecraft-custom-plugins/ # optional: source-of-truth
|
||||||
|
sudo chown -R 1000:1000 /opt/docker/minecraft-custom-plugins
|
||||||
|
docker compose up -d --force-recreate mc
|
||||||
|
```
|
||||||
|
|
||||||
|
The `EXCLUDE` line still lists `ChatChat*.jar` so that if the bind mount ever vanishes, an existing copy in `/data/plugins/` isn't wiped — belt and braces.
|
||||||
|
|
||||||
|
## 4. Bonus — Forgejo Release upload procedure (mechanism C)
|
||||||
|
|
||||||
|
If you'd rather host the jar at `git.s8n.ru` (e.g. for cobblestone or a friend's box without the bind mount):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. Tag and push
|
||||||
|
cd staging/chatchat
|
||||||
|
git tag -a chatchat-racked-1 -m "ChatChat racked build 1"
|
||||||
|
git push origin chatchat-racked-1
|
||||||
|
|
||||||
|
# 2. Create release + upload asset (uses Forgejo PAT from ~/.config/veilor-forgejo)
|
||||||
|
TOKEN=$(cat ~/.config/veilor-forgejo/pat)
|
||||||
|
curl -X POST \
|
||||||
|
-H "Authorization: token $TOKEN" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
https://git.s8n.ru/api/v1/repos/s8n/minecraft-server/releases \
|
||||||
|
-d '{"tag_name":"chatchat-racked-1","name":"ChatChat racked-1","draft":false}'
|
||||||
|
|
||||||
|
RELEASE_ID=$(curl -s -H "Authorization: token $TOKEN" \
|
||||||
|
https://git.s8n.ru/api/v1/repos/s8n/minecraft-server/releases/tags/chatchat-racked-1 \
|
||||||
|
| jq -r .id)
|
||||||
|
|
||||||
|
curl -X POST \
|
||||||
|
-H "Authorization: token $TOKEN" \
|
||||||
|
-H "Content-Type: application/java-archive" \
|
||||||
|
--data-binary @ChatChat-1.0.0-SNAPSHOT-racked-1.jar \
|
||||||
|
"https://git.s8n.ru/api/v1/repos/s8n/minecraft-server/releases/$RELEASE_ID/assets?name=ChatChat-1.0.0-SNAPSHOT-racked-1.jar"
|
||||||
|
```
|
||||||
|
|
||||||
|
Then add to compose:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
PLUGINS: |
|
||||||
|
...existing...
|
||||||
|
https://git.s8n.ru/s8n/minecraft-server/releases/download/chatchat-racked-1/ChatChat-1.0.0-SNAPSHOT-racked-1.jar
|
||||||
|
```
|
||||||
|
|
||||||
|
## References
|
||||||
|
|
||||||
|
- itzg docs: https://docker-minecraft-server.readthedocs.io/en/latest/mods-and-plugins/
|
||||||
|
- Source: https://github.com/itzg/docker-minecraft-server/blob/master/docs/mods-and-plugins/index.md
|
||||||
|
- Issue #310 (COPY_PLUGINS_SRC behaviour): https://github.com/itzg/docker-minecraft-server/issues/310
|
||||||
137
docs/MIGRATION-PLAN-EXCELLENTSHOP.md
Normal file
137
docs/MIGRATION-PLAN-EXCELLENTSHOP.md
Normal file
|
|
@ -0,0 +1,137 @@
|
||||||
|
# Migration Plan — EZShop + Kiranhart AH → ExcellentShop unified
|
||||||
|
|
||||||
|
**Date:** 2026-05-08
|
||||||
|
**Author:** s8n
|
||||||
|
**Supersedes:** AUDIT-2026-05-07 F-11; SHOP-SYSTEM-DECISION sec. 6 (now operational)
|
||||||
|
**Staging:** `staging/excellentshop/`
|
||||||
|
**Status:** Ready for operator-scheduled maintenance window.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Summary
|
||||||
|
|
||||||
|
Replace two plugins (EZShop 1.0-SNAPSHOT bespoke + Kiranhart AuctionHouse
|
||||||
|
1.4.6 ARR-no-LICENSE) with one GPL-3 stack:
|
||||||
|
ExcellentShop 5.0.1 + CoinsEngine 2.7.0, both built by NightExpress against
|
||||||
|
nightcore 2.15.3. All three jars are sourced from the upstream Reposilite
|
||||||
|
(`repo.nightexpressdev.com`) — source-of-truth identical to a local
|
||||||
|
`mvn package` from `github.com/nulli0n/ExcellentShop-spigot`, just reproducible
|
||||||
|
without the brittle `alex9849` integration that fails on TLS handshake.
|
||||||
|
|
||||||
|
Both modules share one theme, one perm tree, one update cadence. Chest Shop
|
||||||
|
module is disabled — not a future-of-server commit (QuickShop-Hikari path
|
||||||
|
already documented in SHOP-SYSTEM-DECISION).
|
||||||
|
|
||||||
|
## 2. Pre-flight (not in `swap.sh`, do these first)
|
||||||
|
|
||||||
|
1. **Heads-up window:** post in-game notice via `/pm news` minus 7d, 1d, 1h.
|
||||||
|
"Auction listings will be drained on YYYY-MM-DD HH:MM."
|
||||||
|
2. **Drain Kiranhart AH:** instruct players to claim/cancel listings.
|
||||||
|
Bid-in-progress items revert at the close of the bid window (max 2h,
|
||||||
|
per `bid-auction-duration: 7200`). Manual refund the residue to the
|
||||||
|
listing owner via `/eco give` after the window — record the audit
|
||||||
|
trail in `live-server/migration-2026-05-08-residue.log`.
|
||||||
|
3. **Snapshot live data:** invoke
|
||||||
|
`scripts/restic-backup-playerdata.sh` (already wired for nullstone).
|
||||||
|
Verify the snapshot via `restic snapshots --tag pre-shop-migration`.
|
||||||
|
4. **Verify staged bundle:**
|
||||||
|
```
|
||||||
|
cd staging/excellentshop/build
|
||||||
|
sha256sum *.jar # match the values committed alongside this doc
|
||||||
|
```
|
||||||
|
5. **Confirm operator window:** compose stop → up takes ~3 minutes;
|
||||||
|
ExcellentShop generates ~11 default shops + 400 items on first start
|
||||||
|
(~30s extra). Total expected downtime: 4-6 minutes best case,
|
||||||
|
12 minutes worst case (if itzg downloads stall).
|
||||||
|
|
||||||
|
## 3. Swap procedure
|
||||||
|
|
||||||
|
`scripts/swap.sh` runs as `user@nullstone` and performs:
|
||||||
|
|
||||||
|
| Step | Action |
|
||||||
|
|------|--------|
|
||||||
|
| 1 | `docker compose stop mc` |
|
||||||
|
| 2 | tar legacy `EZShop` + `AuctionHouse` plugin trees + jars to `/opt/docker/minecraft/plugins.tar.bak-<ts>` |
|
||||||
|
| 3 | privileged `rm -rf` of legacy trees and jars (uses `docker run --privileged --userns=host` per `feedback_docker_sudo_bypass`) |
|
||||||
|
| 4 | populate `/opt/docker/minecraft-custom-plugins/` with the three staged jars, chown 1000:1000 |
|
||||||
|
| 5 | replace `docker-compose.yml` with `docker-compose.patch.yml` (adds `COPY_PLUGINS_SRC=/plugins-custom`, the bind mount, and the new `REMOVE_OLD_MODS_EXCLUDE` glob list) — keeps a `.bak-<ts>` |
|
||||||
|
| 6 | `docker compose up -d mc` (first-start config generation runs here) |
|
||||||
|
| 7 | poll `mc-health` for up to 4 minutes |
|
||||||
|
| 8 | `docker cp` the staged config overrides into the now-populated plugin tree, run `excellentshop reload` + `coinsengine reload`, then run `lp-shop-migration.sh` over RCON to grant default-tier perms |
|
||||||
|
|
||||||
|
The compose patch is identical to the existing live compose **except** for
|
||||||
|
the three lines: `PLUGINS` (drops EZShop+AH URLs), `REMOVE_OLD_MODS_EXCLUDE`
|
||||||
|
(adds three new globs), and `COPY_PLUGINS_SRC` + matching volume mount.
|
||||||
|
|
||||||
|
## 4. Smoke test (post-swap, manual)
|
||||||
|
|
||||||
|
Run as a non-staff player and as a staff player:
|
||||||
|
|
||||||
|
- `/shop` → main category menu, 11 shops, GUI renders within 1s.
|
||||||
|
- `/sellall` → sells inventory, `+N coins` chat feedback, `/balance` updates.
|
||||||
|
- `/sellhand` → sells hand stack, hand cleared.
|
||||||
|
- `/ah` → AH GUI opens, list a test item via `/ah list 100`, see it in browse.
|
||||||
|
- `/ah` admin: `/ah admin remove <listing>` works, `/ah admin expire` works.
|
||||||
|
- `/balance`, `/pay`, `/eco` resolve through CoinsEngine via Vault bridge.
|
||||||
|
- Tail logs `docker logs -f minecraft-mc | grep -E 'nightcore|ExcellentShop|CoinsEngine|ERROR|WARN'` for 5 minutes after first player joins.
|
||||||
|
|
||||||
|
If any of the above fail, run `scripts/rollback.sh`.
|
||||||
|
|
||||||
|
## 5. Rollback
|
||||||
|
|
||||||
|
`scripts/rollback.sh` reverses everything: stops the container, removes
|
||||||
|
ExcellentShop+CoinsEngine+nightcore plugin trees and jars, clears the
|
||||||
|
custom-plugins bind dir, restores legacy `EZShop`+`AuctionHouse` from the
|
||||||
|
tar snapshot, restores the previous `docker-compose.yml`, restarts, and
|
||||||
|
runs `lp-shop-rollback.sh` over RCON to restore the legacy perm nodes.
|
||||||
|
|
||||||
|
Rollback total time: ~5 minutes.
|
||||||
|
|
||||||
|
## 6. Risk register
|
||||||
|
|
||||||
|
| # | Risk | Likelihood | Impact | Mitigation |
|
||||||
|
|---|------|-----------|--------|-----------|
|
||||||
|
| R1 | nightcore 2.15.3 incompatible with Purpur 1.21.11 (api-version 1.21 should match) | Low | High | Smoke-test on a throwaway container first; rollback path < 5 min if breakage |
|
||||||
|
| R2 | CoinsEngine 2.7.0 fails Vault bridge (EssentialsX expects Vault) | Medium | High | `Vault_Compatibility.Default: true` set in staged currency YAML; verify `/balance` in smoke step 4 |
|
||||||
|
| R3 | NightExpress reposilite goes dark before next maintenance | Low | Low | Jars are committed to the repo at `staging/excellentshop/build/` with sha256 receipts — never re-fetched at swap time |
|
||||||
|
| R4 | Players keep typing `/auctionhouse` (legacy alias) | Certain | Low | `commands.yml` aliases `[ah, auctionhouse, market]` keep muscle memory |
|
||||||
|
| R5 | EZShop balance migration loss (if EZShop tracked any) | Very Low | Low | EZShop was sell-only with Vault → balances live in EssentialsX, untouched by this swap |
|
||||||
|
| R6 | Live AH listings lost (residual stuck items) | Medium | Medium | Pre-flight step 2 drains, residue refund is documented |
|
||||||
|
| R7 | First-start delay > 4 min healthcheck window (large default catalog generation) | Low | Medium | `start_period: 240s` already set; if exceeded, manual `docker exec mc mc-health` poll |
|
||||||
|
| R8 | Compose typo locks server out of plugins | Low | High | `swap.sh` keeps `docker-compose.yml.bak-<ts>` for trivial revert; rollback restores it |
|
||||||
|
| R9 | `excellentshop.shop.use` not granted to default group → no players can `/shop` | Medium | High | `lp-shop-migration.sh` step 8 grants the full perm tree; verify with `/lp user <name> permission check excellentshop.shop.use` |
|
||||||
|
| R10 | Compose `cap_drop: ALL` strips a cap CoinsEngine needs | Low | Low | If `/data/plugins/CoinsEngine/` write fails, `cap_add: DAC_OVERRIDE` rescue documented in swap.sh comments |
|
||||||
|
|
||||||
|
## 7. Top 3 swap-window risks (operator brief)
|
||||||
|
|
||||||
|
1. **R9 (perm regression)** — if the LP migration RCON call drops mid-script,
|
||||||
|
players see `/shop` work but `/sellall` fail. Mitigation: re-run
|
||||||
|
`lp-shop-migration.sh` idempotently — every line is `permission set <node> true`.
|
||||||
|
2. **R7 (slow first-start)** — first start of a fresh ExcellentShop with the
|
||||||
|
bundled catalog generation takes ~30s extra and might trip the 240s
|
||||||
|
healthcheck on a cold pool. Mitigation: `swap.sh` step 7 polls manually
|
||||||
|
before declaring success.
|
||||||
|
3. **R2 (Vault bridge)** — if `/balance` returns 0 instead of the player's
|
||||||
|
actual balance, the Vault bridge from CoinsEngine is mis-wired. Mitigation:
|
||||||
|
`Vault_Compatibility.Default: true` is in the staged YAML; if still broken,
|
||||||
|
`/eco give <player> <prev-balance>` from the EssentialsX-side dump that
|
||||||
|
`restic-backup-playerdata.sh` already takes.
|
||||||
|
|
||||||
|
## 8. Estimated downtime
|
||||||
|
|
||||||
|
- **Best case:** 4 minutes (compose stop → up + health check, no log churn).
|
||||||
|
- **Typical:** 6 minutes (one extra stall on jar copy or LP RCON timeout).
|
||||||
|
- **Worst case:** 12 minutes (first-start catalog generation slow + manual smoke).
|
||||||
|
|
||||||
|
If the worst case is exceeded, abort and run `rollback.sh` — the data
|
||||||
|
snapshot from pre-flight step 3 is the source of truth.
|
||||||
|
|
||||||
|
## 9. Post-migration
|
||||||
|
|
||||||
|
- Update `AUDIT-2026-05-07.md` F-11: status → Resolved (date 2026-05-08).
|
||||||
|
- Update `docs/COMMANDS.md`: `/shop`, `/ah`, `/sellall`, `/sellhand`,
|
||||||
|
`/balance` all now route through ExcellentShop+CoinsEngine.
|
||||||
|
- Update `SYSTEM.md` plugin table: drop EZShop, drop AuctionHouse 1.4.6,
|
||||||
|
add ExcellentShop 5.0.1, CoinsEngine 2.7.0, nightcore 2.15.3.
|
||||||
|
- Schedule a follow-up audit in 7d to confirm no log spam, no economy
|
||||||
|
drift, no listing exploits.
|
||||||
BIN
staging/excellentshop/build/CoinsEngine-2.7.0.jar
Normal file
BIN
staging/excellentshop/build/CoinsEngine-2.7.0.jar
Normal file
Binary file not shown.
BIN
staging/excellentshop/build/ExcellentShop-5.0.1.jar
Normal file
BIN
staging/excellentshop/build/ExcellentShop-5.0.1.jar
Normal file
Binary file not shown.
3
staging/excellentshop/build/SHA256SUMS
Normal file
3
staging/excellentshop/build/SHA256SUMS
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
cbb18ee42388acd2b1eac58eacba44db6de6b2f8939981e7e6eb106314db31a2 CoinsEngine-2.7.0.jar
|
||||||
|
a91cb85af94b77097eaf14cae0058b7b0a0001df2cc4c9ab8d7f8710bdb1ad1e ExcellentShop-5.0.1.jar
|
||||||
|
b1313e0455c41bc2bad5de962fa80a59ba9ca8a42c6385d7fa3291d7fb0bb803 nightcore-2.15.3.jar
|
||||||
BIN
staging/excellentshop/build/nightcore-2.15.3.jar
Normal file
BIN
staging/excellentshop/build/nightcore-2.15.3.jar
Normal file
Binary file not shown.
40
staging/excellentshop/configs/README.md
Normal file
40
staging/excellentshop/configs/README.md
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
# ExcellentShop / CoinsEngine Configs (Staged)
|
||||||
|
|
||||||
|
This directory holds **post-first-run** configuration overrides for the migration.
|
||||||
|
|
||||||
|
## How it works
|
||||||
|
|
||||||
|
ExcellentShop and CoinsEngine generate their own opinionated default
|
||||||
|
configs the first time the plugin starts. Those defaults are excellent
|
||||||
|
out of the box — 11 themed virtual shops with ~400 vanilla items, sane
|
||||||
|
buy/sell prices, polished GUIs.
|
||||||
|
|
||||||
|
Rather than ship a hand-translated EZShop catalog (which would be a
|
||||||
|
strict regression — EZShop only had ~80 items, sell-only), this
|
||||||
|
migration **adopts the bundled ExcellentShop catalog** and lays down
|
||||||
|
a small set of **operator-tunable overrides** on top.
|
||||||
|
|
||||||
|
The bundled catalog already covers the eight EZShop categories the
|
||||||
|
operator listed: building blocks, colored blocks, food, mob drops,
|
||||||
|
miscellaneous, minerals, redstone, farming, decoration, plus
|
||||||
|
combat/tools and potions.
|
||||||
|
|
||||||
|
## Files in this dir
|
||||||
|
|
||||||
|
- `apply-overrides.sh` — runs after first start, patches the 11 generated shop YAMLs to apply the racked.ru tweaks listed below.
|
||||||
|
- `coinsengine/config.yml` — pre-staged, drops in the single `coin` currency named "coins" (matches the EZShop messages).
|
||||||
|
- `coinsengine/currencies/coin.yml` — currency definition.
|
||||||
|
- `excellentshop/config.yml` — top-level plugin overrides (modules: virtual=on, auction=on, chest=OFF).
|
||||||
|
- `excellentshop/modules/virtual_shop/config.yml` — `/shop` alias, sell-all, sell-hand commands, no rank multiplier (we keep parity with EZShop's flat pricing).
|
||||||
|
- `excellentshop/modules/auction/config.yml` — Kiranhart-equivalent settings: 1% tax, BIN+bid, 10 listings default, 7200s bid duration, 172800s BIN duration.
|
||||||
|
|
||||||
|
## What's NOT staged
|
||||||
|
|
||||||
|
- Per-item prices — bundled defaults are kept. If the operator wants to align specific items to legacy EZShop prices, edit the generated `plugins/ExcellentShop/modules/virtual_shop/shops/<id>/config.yml` files and adjust `sell` / `sellAll` price fields. EZShop legacy table preserved at `legacy-ezshop-prices.yml` for reference.
|
||||||
|
- `legacy-ezshop-prices.yml` — full export of EZShop's `item-prices` map; reference only.
|
||||||
|
|
||||||
|
## Layout reference (54-slot per category from YOU500 ask)
|
||||||
|
|
||||||
|
Bundled shops are 54-slot (6 rows) by default with category icons in the
|
||||||
|
main menu, exactly the layout described in `SHOP-SYSTEM-DECISION.md`.
|
||||||
|
The operator does NOT need to manually configure 54-slot — it's the default.
|
||||||
13
staging/excellentshop/configs/coinsengine/config.yml
Normal file
13
staging/excellentshop/configs/coinsengine/config.yml
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
# CoinsEngine top-level config (racked.ru)
|
||||||
|
# CoinsEngine handles currency for ExcellentShop. We define a single
|
||||||
|
# currency named "coins" (matches EZShop's existing "coins" message tokens).
|
||||||
|
|
||||||
|
General:
|
||||||
|
Save_Interval: 600
|
||||||
|
Currency_Need_Permission: false
|
||||||
|
Format:
|
||||||
|
# Match EZShop legacy: 'Sold for &f%amount% &7coins.'
|
||||||
|
Suffix: " coins"
|
||||||
|
Prefix: ""
|
||||||
|
Decimal_Places: 2
|
||||||
|
Use_Short_Suffixes: true # 1.5K / 2.3M for big numbers in AH listings
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
# Single currency for racked.ru — "coins"
|
||||||
|
# Matches the in-game currency name players already see in EZShop messages.
|
||||||
|
|
||||||
|
Settings:
|
||||||
|
Enabled: true
|
||||||
|
Name: "&fcoins"
|
||||||
|
Symbol: "c"
|
||||||
|
Decimal: false # whole-number coins (vanilla feel)
|
||||||
|
Default_Balance: 0
|
||||||
|
Starting_Balance: 0
|
||||||
|
Max_Balance: -1 # no cap
|
||||||
|
Min_Balance: 0 # no overdraft
|
||||||
|
|
||||||
|
Vault_Compatibility:
|
||||||
|
Default: true # our /eco, /pay, /balance route through CoinsEngine
|
||||||
|
Currency_Name_Singular: coin
|
||||||
|
Currency_Name_Plural: coins
|
||||||
|
|
||||||
|
Commands:
|
||||||
|
# /balance, /pay — keep parity with EssentialsX surface
|
||||||
|
Aliases: [coins]
|
||||||
|
Pay:
|
||||||
|
Enabled: true
|
||||||
|
Tax_Percent: 0.0
|
||||||
19
staging/excellentshop/configs/excellentshop/config.yml
Normal file
19
staging/excellentshop/configs/excellentshop/config.yml
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
# ExcellentShop top-level config (racked.ru post-migration override)
|
||||||
|
# Drop into /data/plugins/ExcellentShop/config.yml AFTER first start has
|
||||||
|
# populated the file, then `/excellentshop reload`.
|
||||||
|
|
||||||
|
General:
|
||||||
|
Auto_Save_Logs: false # we ship our own log rotation via itzg
|
||||||
|
Currency_Need_Permission: false
|
||||||
|
Buy_With_Full_Inventory: false
|
||||||
|
|
||||||
|
Modules:
|
||||||
|
# Disable Chest Shop module — racked.ru does not expose chest shops
|
||||||
|
# (QuickShop-Hikari is the future story; for now /shop + /ah are the
|
||||||
|
# canonical commands per the SHOP-SYSTEM-DECISION).
|
||||||
|
ChestShop:
|
||||||
|
Enabled: false
|
||||||
|
VirtualShop:
|
||||||
|
Enabled: true
|
||||||
|
Auction:
|
||||||
|
Enabled: true
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
# ExcellentShop / Auction House module — racked.ru overrides
|
||||||
|
# Translates the Kiranhart 1.4.6 settings (tax 1%, BIN+bid, 10 listings)
|
||||||
|
# into ExcellentShop AH schema. Apply AFTER first start.
|
||||||
|
|
||||||
|
General:
|
||||||
|
# 1% tax on listing creation — matches Kiranhart 'tax: 0.01'
|
||||||
|
Listing_Tax: 0.01
|
||||||
|
Per_Player_Listing_Limit: 10 # matches Kiranhart 'default-max-auctions'
|
||||||
|
Sold_Notification: true # matches 'sold-message: true'
|
||||||
|
Auto_Collect_Sold: false # matches 'auto-collect: false'
|
||||||
|
Partial_Selling: false # matches 'partial-selling: false'
|
||||||
|
Announce_Listings: true # matches 'auction-announcements: true'
|
||||||
|
|
||||||
|
Commands:
|
||||||
|
# Aliases — keep current /ah and /auctionhouse muscle memory
|
||||||
|
Auction: [ah, auctionhouse, market]
|
||||||
|
Sell: [ahsell, ahlist]
|
||||||
|
|
||||||
|
Listings:
|
||||||
|
# BIN (Buy-It-Now) — matches Kiranhart 'bin-auctions: true'
|
||||||
|
BIN:
|
||||||
|
Enabled: true
|
||||||
|
Default_Duration: 172800 # 48h, matches 'bin-auction-duration'
|
||||||
|
Min_Price: 1 # matches 'min-bin: 1'
|
||||||
|
Max_Price: -1 # matches 'max-bin: -1' (no cap)
|
||||||
|
# Bidding — matches Kiranhart 'bid-auctions: true'
|
||||||
|
Bid:
|
||||||
|
Enabled: true
|
||||||
|
Default_Duration: 7200 # 2h, matches 'bid-auction-duration'
|
||||||
|
Min_Start: 1 # matches 'min-bid: 1'
|
||||||
|
Max_Start: -1 # matches 'max-bid: -1'
|
||||||
|
Last_Bid_Extra_Time: 60 # matches 'last-bid-extra-time'
|
||||||
|
Bid_Increase_Percent: 25 # matches 'bid-increase-percent'
|
||||||
|
|
||||||
|
Permissions:
|
||||||
|
# 'auctionhouse.moderator' under Kiranhart -> 'excellentshop.auction.admin' here
|
||||||
|
# mapped via lp-shop-migration.sh.
|
||||||
|
Admin_Node: excellentshop.auction.admin
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
# ExcellentShop / Virtual Shop module — racked.ru overrides
|
||||||
|
# Apply AFTER first start.
|
||||||
|
|
||||||
|
General:
|
||||||
|
Save_Interval: 600
|
||||||
|
Default_Layout: "default"
|
||||||
|
Main_Menu:
|
||||||
|
Enabled: true
|
||||||
|
Hide_No_Permission_Shops: false
|
||||||
|
Shop_Shortcut:
|
||||||
|
Enabled: true
|
||||||
|
# /shop opens the main category menu (replaces EZShop /shop)
|
||||||
|
Commands: [shop, vshop]
|
||||||
|
Sell_Menu:
|
||||||
|
Enabled: true
|
||||||
|
Commands: [sell]
|
||||||
|
Sell_All:
|
||||||
|
Enabeled: true # sic — typo is in the upstream config schema
|
||||||
|
Commands: [sellall]
|
||||||
|
Sell_Hand:
|
||||||
|
Enabled: true
|
||||||
|
Commands: [sellhand]
|
||||||
|
Sell_Hand_All:
|
||||||
|
Enabled: true
|
||||||
|
Commands: [sellhandall]
|
||||||
|
# No rank multiplier — racked.ru uses flat pricing (LP prefixes are locked,
|
||||||
|
# discounts are out of scope, see feedback_lp_prefixes_locked.md)
|
||||||
|
Sell_Multipliers: {}
|
||||||
|
Disabled_In_Gamemodes: [CREATIVE, SPECTATOR]
|
||||||
|
Disabled_In_Worlds: [auth_limbo, void_lobby]
|
||||||
110
staging/excellentshop/configs/legacy-ezshop-prices.yml
Normal file
110
staging/excellentshop/configs/legacy-ezshop-prices.yml
Normal file
|
|
@ -0,0 +1,110 @@
|
||||||
|
# racked.ru sell-shop
|
||||||
|
# Players /shop, drop items, click sell. Vanilla items only.
|
||||||
|
# Prices balanced for survival economy. Tune as needed.
|
||||||
|
|
||||||
|
item-prices:
|
||||||
|
# mining
|
||||||
|
COBBLESTONE: 1
|
||||||
|
STONE: 2
|
||||||
|
ANDESITE: 1
|
||||||
|
GRANITE: 1
|
||||||
|
DIORITE: 1
|
||||||
|
GRAVEL: 2
|
||||||
|
SAND: 2
|
||||||
|
RED_SAND: 2
|
||||||
|
CLAY_BALL: 3
|
||||||
|
COAL: 4
|
||||||
|
IRON_INGOT: 10
|
||||||
|
COPPER_INGOT: 6
|
||||||
|
GOLD_INGOT: 40
|
||||||
|
DIAMOND: 100
|
||||||
|
EMERALD: 35
|
||||||
|
LAPIS_LAZULI: 5
|
||||||
|
REDSTONE: 3
|
||||||
|
QUARTZ: 6
|
||||||
|
NETHERITE_INGOT: 1000
|
||||||
|
AMETHYST_SHARD: 8
|
||||||
|
GLOWSTONE_DUST: 4
|
||||||
|
OBSIDIAN: 8
|
||||||
|
|
||||||
|
# wood
|
||||||
|
OAK_LOG: 3
|
||||||
|
BIRCH_LOG: 3
|
||||||
|
SPRUCE_LOG: 3
|
||||||
|
JUNGLE_LOG: 3
|
||||||
|
ACACIA_LOG: 3
|
||||||
|
DARK_OAK_LOG: 3
|
||||||
|
MANGROVE_LOG: 4
|
||||||
|
CHERRY_LOG: 4
|
||||||
|
CRIMSON_STEM: 5
|
||||||
|
WARPED_STEM: 5
|
||||||
|
|
||||||
|
# crops
|
||||||
|
WHEAT: 2
|
||||||
|
CARROT: 2
|
||||||
|
POTATO: 2
|
||||||
|
BEETROOT: 2
|
||||||
|
PUMPKIN: 3
|
||||||
|
MELON_SLICE: 1
|
||||||
|
SUGAR_CANE: 2
|
||||||
|
COCOA_BEANS: 3
|
||||||
|
KELP: 1
|
||||||
|
BAMBOO: 1
|
||||||
|
SWEET_BERRIES: 2
|
||||||
|
GLOW_BERRIES: 2
|
||||||
|
|
||||||
|
# food
|
||||||
|
APPLE: 4
|
||||||
|
BREAD: 5
|
||||||
|
GOLDEN_APPLE: 80
|
||||||
|
GOLDEN_CARROT: 12
|
||||||
|
COOKED_BEEF: 5
|
||||||
|
COOKED_PORKCHOP: 5
|
||||||
|
COOKED_CHICKEN: 5
|
||||||
|
COOKED_MUTTON: 5
|
||||||
|
COOKED_RABBIT: 5
|
||||||
|
COOKED_SALMON: 5
|
||||||
|
COOKED_COD: 5
|
||||||
|
COOKIE: 3
|
||||||
|
CAKE: 15
|
||||||
|
HONEY_BOTTLE: 8
|
||||||
|
|
||||||
|
# mob drops
|
||||||
|
ROTTEN_FLESH: 1
|
||||||
|
BONE: 3
|
||||||
|
STRING: 4
|
||||||
|
SPIDER_EYE: 6
|
||||||
|
GUNPOWDER: 8
|
||||||
|
ENDER_PEARL: 25
|
||||||
|
BLAZE_ROD: 18
|
||||||
|
GHAST_TEAR: 30
|
||||||
|
SLIME_BALL: 5
|
||||||
|
MAGMA_CREAM: 10
|
||||||
|
PHANTOM_MEMBRANE: 15
|
||||||
|
SHULKER_SHELL: 100
|
||||||
|
NETHER_STAR: 2000
|
||||||
|
WITHER_ROSE: 50
|
||||||
|
HEART_OF_THE_SEA: 500
|
||||||
|
TOTEM_OF_UNDYING: 600
|
||||||
|
|
||||||
|
# nether
|
||||||
|
NETHERRACK: 1
|
||||||
|
SOUL_SAND: 2
|
||||||
|
SOUL_SOIL: 2
|
||||||
|
GLOWSTONE: 5
|
||||||
|
NETHER_BRICK: 2
|
||||||
|
ANCIENT_DEBRIS: 200
|
||||||
|
|
||||||
|
# ice / snow / misc
|
||||||
|
ICE: 2
|
||||||
|
SNOWBALL: 1
|
||||||
|
MUSHROOM: 2
|
||||||
|
RED_MUSHROOM: 2
|
||||||
|
BROWN_MUSHROOM: 2
|
||||||
|
|
||||||
|
messages:
|
||||||
|
sellSuccess: "&7[&fShop&7] &fSold for &f%amount% &7coins."
|
||||||
|
invalidItems: "&7[&fShop&7] &fNo sellable items."
|
||||||
|
guiTitle: "Shop"
|
||||||
|
itemLore1: "&fSell"
|
||||||
|
itemLore2: "&7Click to sell your items."
|
||||||
116
staging/excellentshop/scripts/docker-compose.patch.yml
Normal file
116
staging/excellentshop/scripts/docker-compose.patch.yml
Normal file
|
|
@ -0,0 +1,116 @@
|
||||||
|
services:
|
||||||
|
mc:
|
||||||
|
image: itzg/minecraft-server:latest
|
||||||
|
container_name: minecraft-mc
|
||||||
|
environment:
|
||||||
|
EULA: "TRUE"
|
||||||
|
# TYPE=CUSTOM bypasses itzg's auto-loader detection; honors MODRINTH_LOADER override
|
||||||
|
TYPE: CUSTOM
|
||||||
|
CUSTOM_SERVER: "https://api.purpurmc.org/v2/purpur/1.21.11/latest/download"
|
||||||
|
VERSION: "1.21.11"
|
||||||
|
|
||||||
|
# H3 (2026-05-07): Xmx lowered 16384M -> 14336M to leave ~3.5G headroom
|
||||||
|
# for off-heap (Netty buffers, native mmaps, plugin metadata) inside the
|
||||||
|
# 18G container limit. See AUDIT-2026-05-07.md F-05.
|
||||||
|
MEMORY_SIZE: "14G"
|
||||||
|
JVM_OPTS: "-Xms8192M -Xmx14336M"
|
||||||
|
|
||||||
|
DIFFICULTY: hard
|
||||||
|
GAMEMODE: survival
|
||||||
|
HARDCORE: "false"
|
||||||
|
MAX_PLAYERS: "69"
|
||||||
|
VIEW_DISTANCE: 20
|
||||||
|
SIMULATION_DISTANCE: 10
|
||||||
|
ONLINE_MODE: "false"
|
||||||
|
SPAWN_PROTECTION: 0
|
||||||
|
MOTD: "racked.ru — experience the game the way it should have always been"
|
||||||
|
|
||||||
|
USE_AIKAR_FLAGS: "true"
|
||||||
|
MAX_TICK_TIME: "-1"
|
||||||
|
|
||||||
|
ENABLE_RCON: "true"
|
||||||
|
RCON_PASSWORD: "*redacted*"
|
||||||
|
|
||||||
|
TZ: "Europe/London"
|
||||||
|
ENABLE_ROLLING_LOGS: "true"
|
||||||
|
|
||||||
|
UID: "1000"
|
||||||
|
GID: "1000"
|
||||||
|
|
||||||
|
# Modrinth auto-DL — TYPE=CUSTOM lets MODRINTH_LOADER=paper actually work
|
||||||
|
MODRINTH_PROJECTS: |
|
||||||
|
luckperms
|
||||||
|
placeholderapi
|
||||||
|
fastasyncworldedit
|
||||||
|
simple-voice-chat
|
||||||
|
minimotd
|
||||||
|
skinsrestorer
|
||||||
|
vaultunlocked
|
||||||
|
proantitab
|
||||||
|
voidworldgenerator
|
||||||
|
homestead-plugin
|
||||||
|
# EssentialsX + spark not on Modrinth as paper jars — direct GH/CI URLs.
|
||||||
|
# ExcellentShop/CoinsEngine/nightcore are mounted via COPY_PLUGINS_SRC,
|
||||||
|
# not URL'd here, so they survive even if NightExpress's reposilite goes
|
||||||
|
# dark.
|
||||||
|
PLUGINS: |
|
||||||
|
https://github.com/EssentialsX/Essentials/releases/download/2.21.2/EssentialsX-2.21.2.jar
|
||||||
|
https://ci.lucko.me/job/spark/lastSuccessfulBuild/artifact/spark-bukkit/build/libs/spark-1.10.172-bukkit.jar
|
||||||
|
https://github.com/HaHaWTH/AuthMeReReloaded/releases/download/b49/AuthMe-5.6.0-FORK-Universal.jar
|
||||||
|
https://github.com/dmulloy2/ProtocolLib/releases/download/dev-build/ProtocolLib.jar
|
||||||
|
https://github.com/VoidemLIVE/Help-Command-Plugin/releases/download/v2.9.2/HelpCommand-2.9.2.jar
|
||||||
|
https://cdn.modrinth.com/data/Lu3KuzdV/versions/HD2IvrxS/CoreProtect-CE-23.1.jar
|
||||||
|
https://cdn.modrinth.com/data/gG7VFbG0/versions/uWACk3HR/TAB%20v6.0.1.jar
|
||||||
|
MODRINTH_DOWNLOAD_DEPENDENCIES: none
|
||||||
|
MODRINTH_PROJECTS_DEFAULT_VERSION_TYPE: release
|
||||||
|
MODRINTH_LOADER: paper
|
||||||
|
SPIGET_RESOURCES: ""
|
||||||
|
REMOVE_OLD_MODS: "true"
|
||||||
|
REMOVE_OLD_MODS_INCLUDE: "*.jar"
|
||||||
|
# Custom-built jars survive the wipe via this exclude list.
|
||||||
|
# ExcellentShop, CoinsEngine, nightcore arrive via COPY_PLUGINS_SRC bind.
|
||||||
|
REMOVE_OLD_MODS_EXCLUDE: "AuthLimbo*.jar,ExcellentShop*.jar,CoinsEngine*.jar,nightcore*.jar"
|
||||||
|
COPY_PLUGINS_SRC: "/plugins-custom"
|
||||||
|
volumes:
|
||||||
|
- /opt/docker/minecraft:/data
|
||||||
|
- /opt/docker/minecraft-custom-plugins:/plugins-custom:ro
|
||||||
|
ports:
|
||||||
|
- "25565:25565/tcp"
|
||||||
|
- "25575:25575/tcp"
|
||||||
|
networks:
|
||||||
|
- proxy
|
||||||
|
restart: unless-stopped
|
||||||
|
# H2 (2026-05-07): Container hardening per AUDIT-2026-05-07.md F-06.
|
||||||
|
# Drop the default Docker capability set (CAP_NET_RAW, CAP_SYS_CHROOT, ...)
|
||||||
|
# which the JVM/Paper does not need. Re-add only the minimum needed by
|
||||||
|
# itzg's entrypoint chown/gosu flow. DAC_OVERRIDE intentionally omitted —
|
||||||
|
# add back only if entrypoint fails. NOT applied live until next restart.
|
||||||
|
cap_drop:
|
||||||
|
- ALL
|
||||||
|
cap_add:
|
||||||
|
- CHOWN
|
||||||
|
- SETUID
|
||||||
|
- SETGID
|
||||||
|
- FOWNER
|
||||||
|
security_opt:
|
||||||
|
- no-new-privileges:true
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "mc-health"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 3
|
||||||
|
start_period: 240s
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: 18G
|
||||||
|
cpus: '6'
|
||||||
|
pids: 4096
|
||||||
|
reservations:
|
||||||
|
memory: 8G
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=false"
|
||||||
|
|
||||||
|
networks:
|
||||||
|
proxy:
|
||||||
|
external: true
|
||||||
62
staging/excellentshop/scripts/lp-shop-migration.sh
Executable file
62
staging/excellentshop/scripts/lp-shop-migration.sh
Executable file
|
|
@ -0,0 +1,62 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# lp-shop-migration.sh — grant ExcellentShop + CoinsEngine perms to default group
|
||||||
|
#
|
||||||
|
# Adds the default-tier permissions players need to /shop, /sellall, /ah-list,
|
||||||
|
# and /ah-bid. Mirrors the perm surface that EZShop + Kiranhart AH gave for free.
|
||||||
|
#
|
||||||
|
# DOES NOT touch group prefixes/suffixes — those are operator-managed
|
||||||
|
# (feedback_lp_prefixes_locked.md). Only `permission set` calls.
|
||||||
|
#
|
||||||
|
# Run via:
|
||||||
|
# ssh user@192.168.0.100 'docker exec -i minecraft-mc \
|
||||||
|
# bash -s' < lp-shop-migration.sh
|
||||||
|
# or copy this into the container and run there.
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
LP="rcon-cli lp"
|
||||||
|
|
||||||
|
run() {
|
||||||
|
echo "+ $*" >&2
|
||||||
|
$LP "$@" >/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
# ---- ExcellentShop (Virtual Shop module) ----
|
||||||
|
run group default permission set excellentshop.shop.use true
|
||||||
|
run group default permission set excellentshop.shop.buy.virtual true
|
||||||
|
run group default permission set excellentshop.shop.sell.virtual true
|
||||||
|
run group default permission set excellentshop.shop.sellall true
|
||||||
|
run group default permission set excellentshop.shop.sellhand true
|
||||||
|
run group default permission set excellentshop.shop.sellhandall true
|
||||||
|
|
||||||
|
# ---- ExcellentShop (Auction House module) ----
|
||||||
|
run group default permission set excellentshop.auction.use true
|
||||||
|
run group default permission set excellentshop.auction.list true
|
||||||
|
run group default permission set excellentshop.auction.bid true
|
||||||
|
run group default permission set excellentshop.auction.buy true
|
||||||
|
run group default permission set excellentshop.auction.cancel true
|
||||||
|
run group default permission set excellentshop.auction.expire.collect true
|
||||||
|
run group default permission set excellentshop.auction.sold.collect true
|
||||||
|
|
||||||
|
# ---- CoinsEngine ----
|
||||||
|
run group default permission set coinsengine.balance true
|
||||||
|
run group default permission set coinsengine.pay true
|
||||||
|
run group default permission set coinsengine.top true
|
||||||
|
|
||||||
|
# ---- Operator/admin tier ----
|
||||||
|
# The 'staff' group inherits these for moderation parity with the old
|
||||||
|
# Kiranhart 'auctionhouse.moderator' node.
|
||||||
|
run group staff permission set excellentshop.auction.admin true
|
||||||
|
run group staff permission set excellentshop.shop.admin true
|
||||||
|
run group staff permission set coinsengine.admin true
|
||||||
|
|
||||||
|
# ---- Revoke legacy nodes (cleanup) ----
|
||||||
|
# These map to EZShop / Kiranhart and become dead weight after the swap.
|
||||||
|
# Wrapped in `|| true` because they may not exist on a fresh perms tree.
|
||||||
|
$LP group default permission unset ezshop.use 2>/dev/null || true
|
||||||
|
$LP group default permission unset auctionhouse.use 2>/dev/null || true
|
||||||
|
$LP group default permission unset auctionhouse.list 2>/dev/null || true
|
||||||
|
$LP group default permission unset auctionhouse.bid 2>/dev/null || true
|
||||||
|
$LP group staff permission unset auctionhouse.moderator 2>/dev/null || true
|
||||||
|
|
||||||
|
echo "lp-shop-migration: done."
|
||||||
47
staging/excellentshop/scripts/lp-shop-rollback.sh
Executable file
47
staging/excellentshop/scripts/lp-shop-rollback.sh
Executable file
|
|
@ -0,0 +1,47 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# lp-shop-rollback.sh — reverse lp-shop-migration.sh
|
||||||
|
# Re-grants the legacy EZShop + Kiranhart perms and clears ExcellentShop nodes.
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
LP="rcon-cli lp"
|
||||||
|
|
||||||
|
run() {
|
||||||
|
echo "+ $*" >&2
|
||||||
|
$LP "$@" >/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
# ---- Re-grant legacy ----
|
||||||
|
run group default permission set ezshop.use true
|
||||||
|
run group default permission set auctionhouse.use true
|
||||||
|
run group default permission set auctionhouse.list true
|
||||||
|
run group default permission set auctionhouse.bid true
|
||||||
|
run group staff permission set auctionhouse.moderator true
|
||||||
|
|
||||||
|
# ---- Drop ExcellentShop nodes ----
|
||||||
|
for node in \
|
||||||
|
excellentshop.shop.use \
|
||||||
|
excellentshop.shop.buy.virtual \
|
||||||
|
excellentshop.shop.sell.virtual \
|
||||||
|
excellentshop.shop.sellall \
|
||||||
|
excellentshop.shop.sellhand \
|
||||||
|
excellentshop.shop.sellhandall \
|
||||||
|
excellentshop.auction.use \
|
||||||
|
excellentshop.auction.list \
|
||||||
|
excellentshop.auction.bid \
|
||||||
|
excellentshop.auction.buy \
|
||||||
|
excellentshop.auction.cancel \
|
||||||
|
excellentshop.auction.expire.collect \
|
||||||
|
excellentshop.auction.sold.collect \
|
||||||
|
coinsengine.balance \
|
||||||
|
coinsengine.pay \
|
||||||
|
coinsengine.top
|
||||||
|
do
|
||||||
|
$LP group default permission unset "$node" 2>/dev/null || true
|
||||||
|
done
|
||||||
|
|
||||||
|
for node in excellentshop.auction.admin excellentshop.shop.admin coinsengine.admin; do
|
||||||
|
$LP group staff permission unset "$node" 2>/dev/null || true
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "lp-shop-rollback: done."
|
||||||
59
staging/excellentshop/scripts/rollback.sh
Executable file
59
staging/excellentshop/scripts/rollback.sh
Executable file
|
|
@ -0,0 +1,59 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# rollback.sh — reverse swap.sh: restore EZShop + Kiranhart, drop ExcellentShop
|
||||||
|
# OPERATOR-ONLY. Run if smoke-test fails after swap.sh.
|
||||||
|
# Restores the most-recent plugins.tar.bak-* snapshot left by swap.sh.
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
COMPOSE_DIR=/opt/docker/minecraft
|
||||||
|
CUSTOM_PLUGIN_DIR=/opt/docker/minecraft-custom-plugins
|
||||||
|
STAGING_DIR=$(cd "$(dirname "$0")/.." && pwd)
|
||||||
|
|
||||||
|
log() { printf '\033[1;33m[rollback %s]\033[0m %s\n' "$(date +%H:%M:%S)" "$*"; }
|
||||||
|
die() { printf '\033[1;31m[rollback FAIL]\033[0m %s\n' "$*" >&2; exit 1; }
|
||||||
|
|
||||||
|
LATEST_BAK=$(sudo ls -1t /opt/docker/minecraft/plugins.tar.bak-* 2>/dev/null | head -1)
|
||||||
|
[[ -n "$LATEST_BAK" ]] || die "no plugins.tar.bak-* snapshot found in /opt/docker/minecraft/"
|
||||||
|
log "using snapshot: $LATEST_BAK"
|
||||||
|
|
||||||
|
log "1/6: stopping minecraft-mc ..."
|
||||||
|
sudo docker compose -f "$COMPOSE_DIR/docker-compose.yml" stop mc
|
||||||
|
|
||||||
|
log "2/6: removing ExcellentShop + CoinsEngine + nightcore ..."
|
||||||
|
sudo docker run --rm --privileged --userns=host \
|
||||||
|
-v /opt/docker/minecraft:/data \
|
||||||
|
docker.io/library/alpine:3 \
|
||||||
|
sh -c "rm -rf /data/plugins/ExcellentShop /data/plugins/ExcellentShop-*.jar \
|
||||||
|
/data/plugins/CoinsEngine /data/plugins/CoinsEngine-*.jar \
|
||||||
|
/data/plugins/nightcore /data/plugins/nightcore-*.jar"
|
||||||
|
|
||||||
|
log "3/6: clearing custom-plugins bind dir ..."
|
||||||
|
sudo rm -f "$CUSTOM_PLUGIN_DIR/ExcellentShop-"*.jar \
|
||||||
|
"$CUSTOM_PLUGIN_DIR/CoinsEngine-"*.jar \
|
||||||
|
"$CUSTOM_PLUGIN_DIR/nightcore-"*.jar
|
||||||
|
|
||||||
|
log "4/6: restoring legacy EZShop + AuctionHouse from $LATEST_BAK ..."
|
||||||
|
sudo docker run --rm --privileged --userns=host \
|
||||||
|
-v /opt/docker/minecraft:/data \
|
||||||
|
docker.io/library/alpine:3 \
|
||||||
|
sh -c "tar -xzf $(basename "$LATEST_BAK") -C /data && cd /data && ls plugins/EZShop plugins/AuctionHouse"
|
||||||
|
|
||||||
|
log "5/6: reverting compose (restore most-recent .bak) ..."
|
||||||
|
LATEST_COMPOSE_BAK=$(ls -1t "$COMPOSE_DIR/docker-compose.yml.bak-"* 2>/dev/null | head -1)
|
||||||
|
if [[ -n "$LATEST_COMPOSE_BAK" ]]; then
|
||||||
|
cp "$LATEST_COMPOSE_BAK" "$COMPOSE_DIR/docker-compose.yml"
|
||||||
|
log " restored compose: $LATEST_COMPOSE_BAK"
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "6/6: starting minecraft-mc + reverse-LP migration ..."
|
||||||
|
sudo docker compose -f "$COMPOSE_DIR/docker-compose.yml" up -d mc
|
||||||
|
|
||||||
|
deadline=$(( $(date +%s) + 240 ))
|
||||||
|
until sudo docker exec minecraft-mc mc-health 2>/dev/null; do
|
||||||
|
[[ $(date +%s) -gt $deadline ]] && die "server did not come healthy in 4 minutes"
|
||||||
|
sleep 5
|
||||||
|
done
|
||||||
|
|
||||||
|
sudo docker exec -i minecraft-mc bash -s < "$STAGING_DIR/scripts/lp-shop-rollback.sh"
|
||||||
|
|
||||||
|
log "DONE. Verify /shop and /ah are back to legacy behaviour."
|
||||||
94
staging/excellentshop/scripts/swap.sh
Executable file
94
staging/excellentshop/scripts/swap.sh
Executable file
|
|
@ -0,0 +1,94 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# swap.sh — racked.ru EZShop+Kiranhart -> ExcellentShop+CoinsEngine swap
|
||||||
|
#
|
||||||
|
# OPERATOR-ONLY. Run on nullstone (192.168.0.100) as `user`.
|
||||||
|
# This script DOES restart the minecraft container. Schedule a 30-minute
|
||||||
|
# maintenance window before invoking.
|
||||||
|
#
|
||||||
|
# Pre-flight (manual, before this script):
|
||||||
|
# 1. Announce 1-week then 1-day then 1-hour heads-up via /pm news.
|
||||||
|
# 2. Drain or expire all active Kiranhart AH listings (refund stuck items).
|
||||||
|
# 3. Snapshot /opt/docker/minecraft via restic (see scripts/restic-backup-playerdata.sh).
|
||||||
|
# 4. Confirm the staged jars are present and checksums match the bundle on disk.
|
||||||
|
#
|
||||||
|
# Post-flight (manual, after this script):
|
||||||
|
# 1. /shop -- verify the main category menu opens, 11 shops visible.
|
||||||
|
# 2. /ah -- verify auction house opens, listing flow works (test admin item).
|
||||||
|
# 3. /sellall -- run with a test stack, verify CoinsEngine balance updated.
|
||||||
|
# 4. /balance -- verify EssentialsX/Vault still resolves through CoinsEngine.
|
||||||
|
# 5. Smoke-test a non-staff player join: shop perms, listing perms.
|
||||||
|
# 6. Tail logs for `nightcore` and `excellentshop` errors for ~5 minutes.
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
COMPOSE_DIR=/opt/docker/minecraft
|
||||||
|
PLUGIN_DIR=/opt/docker/minecraft/plugins
|
||||||
|
CUSTOM_PLUGIN_DIR=/opt/docker/minecraft-custom-plugins
|
||||||
|
STAGING_DIR=$(cd "$(dirname "$0")/.." && pwd)
|
||||||
|
TS=$(date +%Y%m%d-%H%M%S)
|
||||||
|
|
||||||
|
log() { printf '\033[1;36m[swap %s]\033[0m %s\n' "$(date +%H:%M:%S)" "$*"; }
|
||||||
|
die() { printf '\033[1;31m[swap FAIL]\033[0m %s\n' "$*" >&2; exit 1; }
|
||||||
|
|
||||||
|
[[ -d "$STAGING_DIR/build" ]] || die "staging build dir missing: $STAGING_DIR/build"
|
||||||
|
for j in ExcellentShop-5.0.1.jar CoinsEngine-2.7.0.jar nightcore-2.15.3.jar; do
|
||||||
|
[[ -f "$STAGING_DIR/build/$j" ]] || die "missing jar: $j"
|
||||||
|
done
|
||||||
|
|
||||||
|
log "1/8: stopping minecraft-mc..."
|
||||||
|
sudo docker compose -f "$COMPOSE_DIR/docker-compose.yml" stop mc
|
||||||
|
|
||||||
|
log "2/8: backing up old plugin tree to /opt/docker/minecraft.bak-$TS ..."
|
||||||
|
sudo docker run --rm --privileged --userns=host \
|
||||||
|
-v /opt/docker/minecraft:/data \
|
||||||
|
docker.io/library/alpine:3 \
|
||||||
|
sh -c "tar -czf /data/plugins.tar.bak-$TS -C /data plugins/EZShop plugins/EZShop-1.0-SNAPSHOT.jar plugins/AuctionHouse plugins/AuctionHouse-1.4.6.jar 2>/dev/null || true"
|
||||||
|
|
||||||
|
log "3/8: removing legacy EZShop + AuctionHouse ..."
|
||||||
|
sudo docker run --rm --privileged --userns=host \
|
||||||
|
-v /opt/docker/minecraft:/data \
|
||||||
|
docker.io/library/alpine:3 \
|
||||||
|
sh -c "rm -rf /data/plugins/EZShop /data/plugins/EZShop-*.jar /data/plugins/AuctionHouse /data/plugins/AuctionHouse-*.jar"
|
||||||
|
|
||||||
|
log "4/8: ensuring custom-plugins bind dir exists ..."
|
||||||
|
sudo mkdir -p "$CUSTOM_PLUGIN_DIR"
|
||||||
|
sudo cp "$STAGING_DIR/build/"*.jar "$CUSTOM_PLUGIN_DIR/"
|
||||||
|
sudo chown -R 1000:1000 "$CUSTOM_PLUGIN_DIR"
|
||||||
|
ls -la "$CUSTOM_PLUGIN_DIR"
|
||||||
|
|
||||||
|
log "5/8: applying compose patch (custom plugins bind + EXCLUDE list) ..."
|
||||||
|
if ! grep -q "minecraft-custom-plugins" "$COMPOSE_DIR/docker-compose.yml"; then
|
||||||
|
cp "$COMPOSE_DIR/docker-compose.yml" "$COMPOSE_DIR/docker-compose.yml.bak-$TS"
|
||||||
|
sudo cp "$STAGING_DIR/scripts/docker-compose.patch.yml" "$COMPOSE_DIR/docker-compose.yml"
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "6/8: starting minecraft-mc (first start will create configs) ..."
|
||||||
|
sudo docker compose -f "$COMPOSE_DIR/docker-compose.yml" up -d mc
|
||||||
|
|
||||||
|
log "7/8: waiting for server to be healthy (max 4 min) ..."
|
||||||
|
deadline=$(( $(date +%s) + 240 ))
|
||||||
|
until sudo docker exec minecraft-mc mc-health 2>/dev/null; do
|
||||||
|
[[ $(date +%s) -gt $deadline ]] && die "server did not come healthy in 4 minutes"
|
||||||
|
sleep 5
|
||||||
|
done
|
||||||
|
|
||||||
|
log "8/8: applying staged config overrides + LP perms ..."
|
||||||
|
# copy staged configs into the now-populated plugin tree
|
||||||
|
sudo docker cp "$STAGING_DIR/configs/excellentshop/config.yml" minecraft-mc:/data/plugins/ExcellentShop/config.yml
|
||||||
|
sudo docker cp "$STAGING_DIR/configs/excellentshop/modules/virtual_shop/config.yml" minecraft-mc:/data/plugins/ExcellentShop/modules/virtual_shop/config.yml
|
||||||
|
sudo docker cp "$STAGING_DIR/configs/excellentshop/modules/auction/config.yml" minecraft-mc:/data/plugins/ExcellentShop/modules/auction/config.yml
|
||||||
|
sudo docker cp "$STAGING_DIR/configs/coinsengine/config.yml" minecraft-mc:/data/plugins/CoinsEngine/config.yml
|
||||||
|
sudo docker cp "$STAGING_DIR/configs/coinsengine/currencies/coin.yml" minecraft-mc:/data/plugins/CoinsEngine/currencies/coin.yml
|
||||||
|
sudo docker exec minecraft-mc rcon-cli excellentshop reload || true
|
||||||
|
sudo docker exec minecraft-mc rcon-cli coinsengine reload || true
|
||||||
|
|
||||||
|
# LP perms migration
|
||||||
|
sudo docker exec -i minecraft-mc bash -s < "$STAGING_DIR/scripts/lp-shop-migration.sh"
|
||||||
|
|
||||||
|
log "DONE. Verify in-game now:"
|
||||||
|
log " /shop <- main category menu"
|
||||||
|
log " /ah <- auction house"
|
||||||
|
log " /sellall <- bulk sell"
|
||||||
|
log " /balance <- CoinsEngine via Vault"
|
||||||
|
log ""
|
||||||
|
log "If anything is broken, run: $STAGING_DIR/scripts/rollback.sh"
|
||||||
Loading…
Reference in a new issue