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