Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9eb8f540c4 | |||
| 367056e2ba | |||
| 25107efcf1 | |||
| 56e6006424 | |||
| a0aee440c3 | |||
| 4ca2f17d9d | |||
| 121ae4c603 | |||
| 107622fc6d | |||
| 95b0d1564d | |||
| 0c591faf14 | |||
| 63e9185bf8 |
@@ -0,0 +1,622 @@
|
|||||||
|
# bnstoolkit — Architecture & Perk Specification
|
||||||
|
|
||||||
|
> Status: design draft (v0.1). Not yet implemented.
|
||||||
|
> Owner: matt
|
||||||
|
> Last updated: 2026-06-06
|
||||||
|
|
||||||
|
`bnstoolkit` is the custom companion mod for the Brass and Sigil economy
|
||||||
|
system. It provides the UI layer (GUI screens, HUD), the FTB Chunks
|
||||||
|
map mixins for spawn plot integration, and the data models the economy
|
||||||
|
needs. All gameplay logic (bounty rotation, state machine, villager
|
||||||
|
trades, Numismatics integration, etc.) lives in KubeJS and is called
|
||||||
|
into by the mod via network packets.
|
||||||
|
|
||||||
|
This doc is the source of truth for the mod design. It must be
|
||||||
|
reviewed before any Java is written.
|
||||||
|
|
||||||
|
See also: [`economy-system.md`](./economy-system.md) for the gameplay
|
||||||
|
side of the design.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Purpose & scope
|
||||||
|
|
||||||
|
### In scope
|
||||||
|
|
||||||
|
- GUI screens built on FTB Library's UI framework (matches FTB Quests / FTB Chunks visual language)
|
||||||
|
- Mixins into FTB Chunks' map UI for spawn-plot cost overlay, hover tooltips, and click-to-purchase popups
|
||||||
|
- Custom HUD render layer for quest progress (replaces stacked vanilla bossbars)
|
||||||
|
- Data persistence for plot ownership (server-side, saved with world)
|
||||||
|
- Network packets for client↔server state sync
|
||||||
|
- Admin commands: `/bnstoolkit reload`, debugging commands
|
||||||
|
- Config-driven tier perks (`tiers.json`) and plot definitions (`plots.json`)
|
||||||
|
|
||||||
|
### Out of scope
|
||||||
|
|
||||||
|
- Bounty quest engine (lives in KubeJS)
|
||||||
|
- Villager trade rebalance (lives in KubeJS)
|
||||||
|
- Numismatics direct integration (lives in KubeJS — mod calls KubeJS commands to debit/credit)
|
||||||
|
- FTB Quests integration (FTB Quests handles its own UI for the progression campaign)
|
||||||
|
- FTB Ranks admin (FTB Ranks handles permissions directly; mod just reads them)
|
||||||
|
- **Sethome / `/back` / fast-travel features** — explicitly removed. The pack uses **Waystones** as the only travel mechanic. Restrictive travel is a design feature for a Create Aeronautics pack: airships, trains, and vehicles are the intended way to cover distance.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. High-level architecture
|
||||||
|
|
||||||
|
```
|
||||||
|
┌──────────────────────┐
|
||||||
|
│ Player (client) │
|
||||||
|
└──────────┬───────────┘
|
||||||
|
│ keybind / NPC click / chunk click
|
||||||
|
▼
|
||||||
|
┌───────────────────────────────────┐
|
||||||
|
│ bnstoolkit (client) │
|
||||||
|
│ • FTB Library UI screens │
|
||||||
|
│ • FTB Chunks map mixin │
|
||||||
|
│ • Quest progress HUD │
|
||||||
|
└───────────────┬───────────────────┘
|
||||||
|
│ network packets
|
||||||
|
▼
|
||||||
|
┌───────────────────────────────────┐
|
||||||
|
│ bnstoolkit (server) │
|
||||||
|
│ • Plot ownership data │
|
||||||
|
│ • Sethome data │
|
||||||
|
│ • Network packet handlers │
|
||||||
|
│ • /bnstoolkit reload command │
|
||||||
|
└─────┬───────────────────────┬─────┘
|
||||||
|
│ │
|
||||||
|
reads │ │ calls KubeJS commands /
|
||||||
|
FTB Ranks / │ │ fires events for KubeJS
|
||||||
|
FTB Chunks / │ │ to react to
|
||||||
|
Numismatics ▼ ▼
|
||||||
|
┌───────────────┐ ┌──────────────────────┐
|
||||||
|
│ FTB / NeoForge │ │ KubeJS scripts │
|
||||||
|
│ stack │ │ • Bounty engine │
|
||||||
|
└───────────────┘ │ • Quest state │
|
||||||
|
│ • Numismatics calls │
|
||||||
|
│ • Villager trades │
|
||||||
|
│ • Tier promotion │
|
||||||
|
└──────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
Key invariant: **the mod owns UI + plot data + sethomes. KubeJS owns
|
||||||
|
gameplay logic.** They communicate via network packets and KubeJS
|
||||||
|
commands. The mod never directly mutates Numismatics balances or quest
|
||||||
|
state — it asks KubeJS to do that via commands.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Package layout
|
||||||
|
|
||||||
|
```
|
||||||
|
bnstoolkit/
|
||||||
|
├── build.gradle NeoForge 1.21.1 + FTB Library dep
|
||||||
|
├── src/main/java/uk/sijbers/bnstoolkit/
|
||||||
|
│ ├── BnsToolkit.java Mod entry, lifecycle
|
||||||
|
│ ├── client/
|
||||||
|
│ │ ├── ClientEvents.java Keybinds, client setup
|
||||||
|
│ │ ├── screen/
|
||||||
|
│ │ │ ├── QuestLogScreen.java
|
||||||
|
│ │ │ ├── BountyBoardScreen.java
|
||||||
|
│ │ │ ├── TierUpgradeScreen.java
|
||||||
|
│ │ │ ├── PlotPurchaseScreen.java
|
||||||
|
│ │ │ ├── ShopBrowserScreen.java
|
||||||
|
│ │ │ └── widgets/ (subclass FTB Library widgets)
|
||||||
|
│ │ ├── hud/
|
||||||
|
│ │ │ └── QuestProgressHud.java IGuiOverlay
|
||||||
|
│ │ └── mixin/
|
||||||
|
│ │ ├── ChunkScreenPanelMixin.java
|
||||||
|
│ │ └── ChunkButtonMixin.java
|
||||||
|
│ ├── server/
|
||||||
|
│ │ ├── command/
|
||||||
|
│ │ │ └── BnsToolkitCommand.java /bnstoolkit reload, debug
|
||||||
|
│ │ ├── data/
|
||||||
|
│ │ │ ├── PlotRegistry.java loads plots.json
|
||||||
|
│ │ │ └── PlotOwnership.java SavedData, plot owner UUIDs
|
||||||
|
│ │ ├── event/
|
||||||
|
│ │ │ ├── PlayerJoinHandler.java tier-based join broadcast
|
||||||
|
│ │ │ └── ChatColourHandler.java tier-based chat name colouring
|
||||||
|
│ │ └── net/
|
||||||
|
│ │ └── (packet implementations — see §6)
|
||||||
|
│ ├── common/
|
||||||
|
│ │ ├── data/
|
||||||
|
│ │ │ ├── TierConfig.java loads tiers.json
|
||||||
|
│ │ │ ├── BountyDef.java DTO mirrored from KubeJS
|
||||||
|
│ │ │ ├── QuestStateView.java snapshot for UI display
|
||||||
|
│ │ │ └── PlotDef.java plot definition (region, price)
|
||||||
|
│ │ └── net/
|
||||||
|
│ │ └── BnsPacket.java network channel + payload base
|
||||||
|
│ └── resources/
|
||||||
|
│ ├── META-INF/neoforge.mods.toml
|
||||||
|
│ ├── bnstoolkit.mixins.json
|
||||||
|
│ └── assets/bnstoolkit/lang/en_us.json
|
||||||
|
└── src/main/resources/
|
||||||
|
└── data-config/ packed defaults, copied on first run
|
||||||
|
├── tiers.json
|
||||||
|
└── plots.json
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Screen specifications
|
||||||
|
|
||||||
|
All screens extend FTB Library's `BaseScreen`. They share a common
|
||||||
|
header (player name, current tier, spur balance) so navigation feels
|
||||||
|
consistent.
|
||||||
|
|
||||||
|
### 4.1 Quest Log
|
||||||
|
|
||||||
|
**Opened by:** keybind (default Q+B?) or right-clicking a Quest Log
|
||||||
|
block placed at any guild building.
|
||||||
|
|
||||||
|
**Layout:** three tabs across the top — Active / Available / Completed.
|
||||||
|
|
||||||
|
- **Active tab:** list of currently-accepted bounties with progress
|
||||||
|
bars. Each row clickable; click expands a detail panel with
|
||||||
|
description, source guild, reward, and a `Cancel quest` button.
|
||||||
|
Cancel triggers a confirmation modal warning about cooldown.
|
||||||
|
- **Available tab:** list of bounties currently offered (rotated daily
|
||||||
|
by the KubeJS engine). Each row shows the bounty source, reward,
|
||||||
|
cooldown remaining (if any). Click → detail panel with `Accept` button.
|
||||||
|
- **Completed tab:** historical log of completed bounties this week,
|
||||||
|
for satisfaction value. No interaction beyond viewing.
|
||||||
|
|
||||||
|
**Network calls:**
|
||||||
|
- On open: client requests current quest state from server (`S2CQuestSnapshot`)
|
||||||
|
- On accept/cancel click: `C2SAcceptBounty(id)` / `C2SCancelQuest(id)`
|
||||||
|
|
||||||
|
### 4.2 Bounty Board
|
||||||
|
|
||||||
|
**Opened by:** right-clicking the Adventurer's Guild Quartermaster
|
||||||
|
NPC (Easy NPC dialog action runs `/bnstoolkit openboard adventurers_guild`)
|
||||||
|
OR clicking an in-world `bnstoolkit:bounty_board` block.
|
||||||
|
|
||||||
|
**Layout:** poster-board style — the day's available bounties as
|
||||||
|
visual "cards" laid out in a grid, each with mob icon, name,
|
||||||
|
description, reward, accept button. Friendly to non-tech users.
|
||||||
|
|
||||||
|
**Network calls:**
|
||||||
|
- On open: `S2CBountyBoardSnapshot(guild_id)` returns today's bounty list
|
||||||
|
- On accept: same `C2SAcceptBounty(id)` as Quest Log
|
||||||
|
|
||||||
|
### 4.3 Tier Upgrade Screen
|
||||||
|
|
||||||
|
**Opened by:** right-clicking the Civic Office Magistrate NPC.
|
||||||
|
|
||||||
|
**Layout:** full ladder shown as a vertical or horizontal track. Your
|
||||||
|
current tier highlighted (glowing badge). Next tier shows cost +
|
||||||
|
delta perks (e.g. "+50 chunks, +1 plot slot, +2 sethomes, +1 bounty,
|
||||||
|
-2% shop fee, chat colour: yellow"). Big `Upgrade to <Tier>` button
|
||||||
|
at the bottom, greyed out if you don't have the spurs.
|
||||||
|
|
||||||
|
Hovering any future tier shows its full perk list in a side panel.
|
||||||
|
|
||||||
|
**Network calls:**
|
||||||
|
- On open: `S2CTierSnapshot` returns current tier + balance
|
||||||
|
- On upgrade click: `C2SRequestTierUpgrade` → server verifies balance,
|
||||||
|
calls KubeJS `/bnstoolkit_internal upgrade_rank <uuid>` which
|
||||||
|
charges spurs and runs `ftbranks add <player> <tier>`
|
||||||
|
|
||||||
|
### 4.4 Plot Purchase Popup
|
||||||
|
|
||||||
|
**Opened by:** clicking an unowned plot region in the FTB Chunks map
|
||||||
|
UI (via the mod's mixin into `ChunkScreenPanel`).
|
||||||
|
|
||||||
|
**Layout:** modal overlay on top of the FTB Chunks map. Shows: plot
|
||||||
|
ID, plot type (standard/premium), region size in chunks, owner (none),
|
||||||
|
price. Your current spur balance. Your remaining plot slots (e.g.
|
||||||
|
"2 of 3 used"). `Purchase` and `Cancel` buttons. If you're at your
|
||||||
|
slot cap or don't have enough spurs, `Purchase` is greyed out with
|
||||||
|
the reason shown.
|
||||||
|
|
||||||
|
**Network calls:**
|
||||||
|
- On purchase: `C2SBuyPlot(plot_id)` → server checks slot capacity,
|
||||||
|
asks KubeJS to charge spurs, on success records ownership in
|
||||||
|
`PlotOwnership` SavedData.
|
||||||
|
|
||||||
|
### 4.5 Shop Browser
|
||||||
|
|
||||||
|
**Opened by:** right-clicking the Bazaar Master NPC at the Merchant's
|
||||||
|
Bazaar (provides a curated view of all currently-listed shop blocks
|
||||||
|
+ NPC sell shop).
|
||||||
|
|
||||||
|
**Layout:** searchable item list with current prices, sort by
|
||||||
|
category. Click an item to see who's selling it / where the shop
|
||||||
|
block is located. The NPC sell shop (diamonds, netherite etc.) shows
|
||||||
|
as a special "Official Bazaar" category with fixed prices and the
|
||||||
|
current diminishing-return multiplier per item.
|
||||||
|
|
||||||
|
**Note:** individual Numismatics shop blocks keep their native UI
|
||||||
|
when right-clicked — this Bazaar Master is the *curated central
|
||||||
|
view*, not a replacement for shop block interaction.
|
||||||
|
|
||||||
|
**Network calls:**
|
||||||
|
- On open: `S2CShopBrowserSnapshot` (asks KubeJS for current listings)
|
||||||
|
- Selecting an item → `S2CShopItemDetail(item_id)` for full info
|
||||||
|
|
||||||
|
### 4.6 Quest Progress HUD
|
||||||
|
|
||||||
|
**Render layer:** `IGuiOverlay`, drawn over the vanilla HUD.
|
||||||
|
|
||||||
|
**Layout:** small panel in top-right (configurable position) showing
|
||||||
|
each active quest as a row — quest name + progress bar + N/M numeric.
|
||||||
|
Fades on inactive (no progress in last 30s) so it doesn't visually
|
||||||
|
clutter when you're not actively bounty-hunting. Re-appears the
|
||||||
|
moment any quest progresses.
|
||||||
|
|
||||||
|
**State source:** KubeJS pushes updates via `S2CHudQuestUpdate` packet
|
||||||
|
when any quest's progress changes (debounced to once per second
|
||||||
|
maximum per quest). The HUD reads from a client-side cache.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Mixin targets
|
||||||
|
|
||||||
|
Minimal — we don't fork FTB Chunks, we inject only what we need.
|
||||||
|
|
||||||
|
| Target | Method | Purpose | Mixin file |
|
||||||
|
|---|---|---|---|
|
||||||
|
| `ChunkScreenPanel` | `drawBackground` (TAIL) | Overlay drawing — cost preview for the currently-hovered or selected chunk, "Your plot slots: N of M" text in a corner | `ChunkScreenPanelMixin.java` |
|
||||||
|
| `ChunkScreenPanel$ChunkButton` | `addMouseOverText` (TAIL) | Append "Cost: N spurs" or "Plot: <name>" to the per-chunk hover tooltip | `ChunkButtonMixin.java` |
|
||||||
|
| `ChunkScreenPanel$ChunkButton` | `onClicked` (HEAD, with cancellation if applicable) | If the clicked chunk is a plot region, open `PlotPurchaseScreen` instead of triggering a regular claim | `ChunkButtonMixin.java` |
|
||||||
|
|
||||||
|
That's it. Three injection points across two mixin files. No
|
||||||
|
modification of FTB Library, FTB Quests, FTB Ranks, or FTB Teams.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. Network packet contract
|
||||||
|
|
||||||
|
NeoForge `PayloadRegistrar`. All packets versioned via a single
|
||||||
|
`PROTOCOL_VERSION` constant; bump on schema change.
|
||||||
|
|
||||||
|
### Server → Client
|
||||||
|
|
||||||
|
| Packet | Payload | When sent |
|
||||||
|
|---|---|---|
|
||||||
|
| `S2CQuestSnapshot` | `List<QuestStateView>` | On Quest Log open, on any quest-state change |
|
||||||
|
| `S2CBountyBoardSnapshot` | `List<BountyDef>` (5-10 entries) | On Bounty Board open |
|
||||||
|
| `S2CTierSnapshot` | `(currentTier, balance, perksByTier)` | On Tier Upgrade Screen open |
|
||||||
|
| `S2CShopBrowserSnapshot` | `List<ShopListing>` | On Shop Browser open |
|
||||||
|
| `S2CHudQuestUpdate` | `(questId, progress, target)` | On quest progress (debounced 1s) |
|
||||||
|
| `S2CPlotPurchaseResult` | `(success, message)` | After `C2SBuyPlot` resolves |
|
||||||
|
| `S2CTierUpgradeResult` | `(success, message)` | After `C2SRequestTierUpgrade` resolves |
|
||||||
|
|
||||||
|
### Client → Server
|
||||||
|
|
||||||
|
| Packet | Payload | What server does |
|
||||||
|
|---|---|---|
|
||||||
|
| `C2SAcceptBounty` | `questId` | Call `/bnstoolkit_internal accept_bounty <uuid> <questId>` (KubeJS) |
|
||||||
|
| `C2SCancelQuest` | `questId` | Call `/bnstoolkit_internal cancel_quest <uuid> <questId>` (KubeJS) |
|
||||||
|
| `C2SBuyPlot` | `plotId` | Verify slot capacity, ask KubeJS to debit spurs, record ownership |
|
||||||
|
| `C2SRequestTierUpgrade` | (none — server knows player) | Verify balance, ask KubeJS to debit + promote |
|
||||||
|
| `C2SOpenBoard` | `guildId` (optional context) | Reply with appropriate snapshot |
|
||||||
|
|
||||||
|
All C2S packets include the player implicitly (NeoForge passes
|
||||||
|
the `ServerPlayer` in the handler).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. Data persistence
|
||||||
|
|
||||||
|
| Data | Storage | Lifetime |
|
||||||
|
|---|---|---|
|
||||||
|
| Plot ownership | `bnstoolkit:plots` — vanilla NeoForge `SavedData` attached to overworld | Persists with world. Authoritative source. |
|
||||||
|
| Quest state | KubeJS-managed JSON at `world/data/bns_economy/quests/<uuid>.json` | Not the mod's concern — the mod only reads via packets |
|
||||||
|
| Tier configuration | `config/bnstoolkit/tiers.json` (hot-reloadable) | Until edited |
|
||||||
|
| Plot definitions | `config/bnstoolkit/plots.json` (hot-reloadable via `/bnstoolkit reload`) | Until edited |
|
||||||
|
|
||||||
|
Plot ownership is server-authoritative. Clients only get views via
|
||||||
|
packets — they never write to these stores directly.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. Configuration files
|
||||||
|
|
||||||
|
### `config/bnstoolkit/tiers.json`
|
||||||
|
|
||||||
|
Defines the 13-tier ladder. Hot-reloadable.
|
||||||
|
|
||||||
|
```json5
|
||||||
|
{
|
||||||
|
"tiers": [
|
||||||
|
{
|
||||||
|
"id": "peasant",
|
||||||
|
"displayName": "Peasant",
|
||||||
|
"cost": 0,
|
||||||
|
"perks": {
|
||||||
|
"wildernessChunks": 9,
|
||||||
|
"plotSlots": 0,
|
||||||
|
"dailyBountySlots": 3,
|
||||||
|
"shopFeeDiscount": 0,
|
||||||
|
"chatColour": "grey",
|
||||||
|
"joinBroadcast": "none"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/* ... 12 more tiers ... */
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### `config/bnstoolkit/plots.json`
|
||||||
|
|
||||||
|
Defines spawn plot regions. Each plot has a unique ID, region bounds
|
||||||
|
(chunk coordinates), type (standard/premium), and price.
|
||||||
|
|
||||||
|
```json5
|
||||||
|
{
|
||||||
|
"plots": [
|
||||||
|
{
|
||||||
|
"id": "bazaar_stall_01",
|
||||||
|
"displayName": "Bazaar Stall 1",
|
||||||
|
"type": "standard",
|
||||||
|
"price": 2000,
|
||||||
|
"chunks": [[10, 20], [10, 21]], // chunk coords, inclusive
|
||||||
|
"world": "minecraft:overworld"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "bazaar_corner_premium",
|
||||||
|
"displayName": "Premium Corner Plot",
|
||||||
|
"type": "premium",
|
||||||
|
"price": 5000,
|
||||||
|
"chunks": [[15, 25], [15, 26], [16, 25], [16, 26]],
|
||||||
|
"world": "minecraft:overworld"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 9. KubeJS integration surface
|
||||||
|
|
||||||
|
The mod calls into KubeJS via custom commands registered by KubeJS
|
||||||
|
(`ServerEvents.commandRegistry`). All have the `bnstoolkit_internal`
|
||||||
|
prefix to mark them as not-for-player-use:
|
||||||
|
|
||||||
|
| Command | Purpose |
|
||||||
|
|---|---|
|
||||||
|
| `/bnstoolkit_internal accept_bounty <uuid> <questId>` | Mark quest as ACTIVE in KubeJS state |
|
||||||
|
| `/bnstoolkit_internal cancel_quest <uuid> <questId>` | Cancel quest, apply cooldown |
|
||||||
|
| `/bnstoolkit_internal complete_quest <uuid> <questId>` | Mark quest READY (for testing/manual) |
|
||||||
|
| `/bnstoolkit_internal turn_in_quest <uuid> <questId>` | Pay reward via Numismatics |
|
||||||
|
| `/bnstoolkit_internal debit <uuid> <amount> <reason>` | Charge spurs (used by plot purchase, tier upgrade) |
|
||||||
|
| `/bnstoolkit_internal credit <uuid> <amount> <reason>` | Pay spurs |
|
||||||
|
| `/bnstoolkit_internal upgrade_rank <uuid> <tierId>` | Promote via FTB Ranks |
|
||||||
|
| `/bnstoolkit_internal get_balance <uuid>` | Returns current spur balance (used for screen header) |
|
||||||
|
|
||||||
|
All commands return a JSON result via the command output that the
|
||||||
|
mod parses. KubeJS handles the actual Numismatics + FTB Ranks calls
|
||||||
|
(it already has the `Java.loadClass` helpers from the economy KubeJS
|
||||||
|
scripts).
|
||||||
|
|
||||||
|
KubeJS in turn pushes events to the mod via custom payload packets
|
||||||
|
when quest state changes (so the HUD can update without polling).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 10. Build & release
|
||||||
|
|
||||||
|
- **Repo:** new private Gitea repo `minecraft/bnstoolkit` (separate
|
||||||
|
from the modpack repo for clean release-versioning, but mirrored
|
||||||
|
to the modpack's `pack/overrides/mods/` on each release)
|
||||||
|
- **Build:** standard NeoForge 1.21.1 ModDevGradle template
|
||||||
|
- **Dependencies:** Architectury API (provided), FTB Library
|
||||||
|
(provided), Numismatics (compileOnly), FTB Chunks (compileOnly)
|
||||||
|
- **CI:** Gitea Actions runs `./gradlew build` on push to main,
|
||||||
|
uploads the jar as a release artifact
|
||||||
|
- **Modpack integration:** the modpack's bump-version flow includes
|
||||||
|
pulling the latest bnstoolkit release jar and updating
|
||||||
|
`pack.lock.json` / manifest like any other mod
|
||||||
|
- **Versioning:** semantic — `1.0.0` for V1 ship, `1.x.y` for
|
||||||
|
patches, `2.0.0` if we ever change the network protocol or data
|
||||||
|
format
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 11. Perk specifications (detailed)
|
||||||
|
|
||||||
|
Every perk listed in the 13-tier ladder, expanded with mechanics,
|
||||||
|
implementation, and edge cases.
|
||||||
|
|
||||||
|
### 11.1 Wilderness chunks
|
||||||
|
|
||||||
|
**What it does:** caps how many wilderness chunks (outside spawn)
|
||||||
|
a player can claim via the FTB Chunks map. Claiming within the cap
|
||||||
|
is free; over the cap is refused with an in-game message.
|
||||||
|
|
||||||
|
**Implementation:** FTB Ranks permission node
|
||||||
|
`ftbchunks.max_claimed_chunks` set per rank in the FTB Ranks config
|
||||||
|
(written by the mod on first launch from `tiers.json`). FTB Chunks
|
||||||
|
reads this permission natively — no mod-side enforcement needed.
|
||||||
|
|
||||||
|
**Edge case:** if a player downgrades (which they can't normally,
|
||||||
|
but might happen via op command), they keep already-claimed chunks
|
||||||
|
over the new cap, but can't claim more until they free some.
|
||||||
|
|
||||||
|
### 11.2 Plot slots
|
||||||
|
|
||||||
|
**What it does:** caps how many spawn plots (predefined regions at
|
||||||
|
spawn, see `plots.json`) a player can own concurrently. Independent
|
||||||
|
of wilderness chunks.
|
||||||
|
|
||||||
|
**Implementation:** stored in `PlotOwnership` SavedData. On purchase,
|
||||||
|
mod checks `playerOwnedPlots.size() < tier.plotSlots`. If at cap,
|
||||||
|
the Plot Purchase Popup shows the slot count and disables the
|
||||||
|
`Purchase` button.
|
||||||
|
|
||||||
|
**Releasing a plot:** players can sell their plot back via a "Release"
|
||||||
|
button in the plot-detail screen (opens when they click their own
|
||||||
|
plot in the map). Releases the slot. Refund: 50% of purchase price.
|
||||||
|
|
||||||
|
### 11.3 Daily bounty slots
|
||||||
|
|
||||||
|
**What it does:** how many bounties a player can have ACTIVE
|
||||||
|
simultaneously. Once the slot is freed (by completion or cancel),
|
||||||
|
the player can accept another from any guild board.
|
||||||
|
|
||||||
|
**Implementation:** enforced in KubeJS bounty engine. The mod's
|
||||||
|
Bounty Board and Quest Log screens read the slot count via packet
|
||||||
|
and grey out the Accept button when at cap.
|
||||||
|
|
||||||
|
**Edge case:** a quest in READY state still counts against your
|
||||||
|
active slots until you turn it in. This is intentional — pushes
|
||||||
|
players to actually visit the NPC to claim.
|
||||||
|
|
||||||
|
### 11.4 Shop fee discount
|
||||||
|
|
||||||
|
**What it does:** reduces the "merchant cut" deducted when you sell
|
||||||
|
items at the Bazaar's NPC sell shop. The Bazaar charges a base 25%
|
||||||
|
fee on all sales; your tier provides a discount that reduces this
|
||||||
|
toward zero.
|
||||||
|
|
||||||
|
**Worked example:** you sell a diamond worth 10 spurs at the Bazaar.
|
||||||
|
- Peasant (0% discount): 25% fee → you receive 7.5 spurs (rounded
|
||||||
|
down to 7).
|
||||||
|
- Knight (-5% discount): 20% fee → 8 spurs.
|
||||||
|
- Sovereign (-25% discount): 0% fee → full 10 spurs.
|
||||||
|
|
||||||
|
**Implementation:** KubeJS sell-shop handler reads the seller's tier
|
||||||
|
and computes effective payout. Rounded down to nearest integer.
|
||||||
|
|
||||||
|
**Edge case:** player-to-player Numismatics shop blocks do NOT
|
||||||
|
apply this fee — those are direct peer transactions, no Bazaar
|
||||||
|
middleman. The fee only applies to the official Bazaar sell shop.
|
||||||
|
|
||||||
|
### 11.5 Chat colour
|
||||||
|
|
||||||
|
**What it does:** the player's name in chat appears in this colour,
|
||||||
|
visible to everyone. Visual rank marker.
|
||||||
|
|
||||||
|
**Implementation:** KubeJS `PlayerEvents.chat` event modifies the
|
||||||
|
chat component for the player's display name based on their tier
|
||||||
|
permission (read from FTB Ranks). The mod also colours the player's
|
||||||
|
nameplate above their head (via a small client packet on tier change
|
||||||
|
that other clients use to set the display name colour locally).
|
||||||
|
|
||||||
|
**Colour ladder:**
|
||||||
|
- 1-2 Peasant/Farmer: grey
|
||||||
|
- 3 Citizen: white
|
||||||
|
- 4 Merchant: yellow
|
||||||
|
- 5 Knight: green
|
||||||
|
- 6 Baron: cyan
|
||||||
|
- 7 Viscount: blue
|
||||||
|
- 8 Earl: purple
|
||||||
|
- 9 Marquess: gold
|
||||||
|
- 10 Duke: orange
|
||||||
|
- 11 Archduke: red
|
||||||
|
- 12 Grand Duke: bright red
|
||||||
|
- 13 Sovereign: rainbow (animated via colour-cycling text component)
|
||||||
|
|
||||||
|
**Edge case:** the Founder cosmetic `[Founder]` prefix sits before
|
||||||
|
the coloured name, in a distinct colour (probably bright yellow or
|
||||||
|
white-bold). Sovereign + Founder is visually busy but acceptable —
|
||||||
|
only one player on the server will have both.
|
||||||
|
|
||||||
|
### 11.6 Join broadcast
|
||||||
|
|
||||||
|
**What it does:** when the player logs in, this controls what message
|
||||||
|
goes to everyone else on the server.
|
||||||
|
|
||||||
|
**Levels:**
|
||||||
|
|
||||||
|
- **none:** standard vanilla `<player> joined the game`.
|
||||||
|
- **simple:** rank-prefixed message in their chat colour. Example:
|
||||||
|
```
|
||||||
|
[Knight] Matt has logged in.
|
||||||
|
```
|
||||||
|
- **fancy:** multi-line, with a separator. Example:
|
||||||
|
```
|
||||||
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
|
[Viscount] Matt has arrived
|
||||||
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
|
```
|
||||||
|
- **epic:** multi-line, with a sound effect (e.g. trumpet fanfare,
|
||||||
|
configurable per-tier). Larger ASCII separator. Possibly an ASCII
|
||||||
|
art banner of the rank.
|
||||||
|
- **epic + particles:** as epic, plus a 5-second particle effect at
|
||||||
|
the player's spawn location (firework spark, end-rod sparkle, etc.)
|
||||||
|
for everyone nearby to see.
|
||||||
|
- **epic + spectacular:** as epic + particles, plus a server-wide
|
||||||
|
effect — actionbar message visible to everyone, brief light-up of
|
||||||
|
the sky if Sovereign joins.
|
||||||
|
|
||||||
|
**Implementation:** KubeJS `PlayerEvents.loggedIn` reads tier and
|
||||||
|
dispatches the appropriate message. Particle/sound effects are
|
||||||
|
server-side commands (`/particle`, `/playsound`).
|
||||||
|
|
||||||
|
### 11.7 Future perk dimensions (not in V1, but easy to add later)
|
||||||
|
|
||||||
|
Architecture supports adding new perk columns in `tiers.json`
|
||||||
|
without code changes (the schema is open-ended). Candidates for
|
||||||
|
later expansion:
|
||||||
|
|
||||||
|
- **Waystone slot cap** — limit how many waystones a player can place
|
||||||
|
and/or own. Starter waystone is granted; higher tiers unlock 2nd,
|
||||||
|
3rd, etc. Cleanest in-theme perk for a Create Aeronautics pack
|
||||||
|
where restrictive travel is intentional.
|
||||||
|
- **Waystone XP cost reduction** — vanilla Waystones charges XP per
|
||||||
|
teleport. Tier-based discount on this cost (or eventual exemption
|
||||||
|
for Sovereign).
|
||||||
|
- **Particle trail** — high tiers leave a visible particle wake when
|
||||||
|
walking
|
||||||
|
- **Custom join sound** — different sound effect per tier on login
|
||||||
|
- **Custom title prefix** — text added before chat name beyond the
|
||||||
|
colour (e.g. `⚔ Knight Matt`)
|
||||||
|
- **Priority bounty access** — higher tiers see a larger pool of
|
||||||
|
daily bounties to pick from
|
||||||
|
- **Tier-gated vendor stock** — specific Numismatics shops only
|
||||||
|
visible to Baron+ etc.
|
||||||
|
- **Daily login bonus** — small spur reward for logging in, scaling
|
||||||
|
by tier
|
||||||
|
- **Death keep-inventory chance** — RNG % to keep inventory on death
|
||||||
|
(controversial, gate carefully)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 12. Open implementation questions
|
||||||
|
|
||||||
|
These can be deferred until they become blocking, but worth flagging:
|
||||||
|
|
||||||
|
1. **Sovereign tier rainbow chat name** — Minecraft text components
|
||||||
|
don't natively support gradient text. Implementation options:
|
||||||
|
(a) cycle through colours character by character, or (b) animate
|
||||||
|
via packet on a tick interval. Choose during Phase 0c scaffolding.
|
||||||
|
2. **Plot release refund percentage** — proposed 50%. Tune via
|
||||||
|
playtest.
|
||||||
|
3. **Sethome cooldown values per tier** — proposed scaling from 60s
|
||||||
|
(low tiers) to 5s (Sovereign). Confirm in `tiers.json` schema.
|
||||||
|
4. **`/back` interaction with dimension changes** — does dying in
|
||||||
|
the End and `/back`ing return you to the End or to overworld?
|
||||||
|
Default: returns to wherever you died including the dimension.
|
||||||
|
5. **Founder cosmetic prefix colour** — bright yellow? Bold white?
|
||||||
|
Animated? Settle during implementation.
|
||||||
|
6. **Sovereign spectacular join effect** — exact effects need design
|
||||||
|
pass (sky flash? Server-wide actionbar text?). Tune in
|
||||||
|
`tiers.json`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 13. Implementation phases (mod-specific)
|
||||||
|
|
||||||
|
Aligned with the economy doc's Phase 0c (mod scaffolding):
|
||||||
|
|
||||||
|
| Mod phase | Deliverable |
|
||||||
|
|---|---|
|
||||||
|
| **M0** | Gradle project, mod metadata, FTB Library dep wired, network channel registered, empty placeholder for each screen class. Builds + loads cleanly into the running pack. |
|
||||||
|
| **M1** | Tier system: TierConfig loads from `tiers.json`, `TierUpgradeScreen` works, perks applied via FTB Ranks promotion command. Founder cosmetic prefix. Chat colour. Join broadcast at all tiers. |
|
||||||
|
| **M2** | Plot system: `PlotRegistry` + `PlotOwnership`, FTB Chunks mixins, `PlotPurchaseScreen`. KubeJS integration for spur debit. |
|
||||||
|
| **M3** | Quest UI: `QuestLogScreen`, `BountyBoardScreen`, `QuestProgressHud`. Network packets between KubeJS bounty engine and the mod. |
|
||||||
|
| **M4** | Shop browser: `ShopBrowserScreen`. |
|
||||||
|
| **M5** | Polish — animations, sound effects, particle effects for high tiers, theming pass on all screens. |
|
||||||
|
|
||||||
|
Each phase is independently shippable as a `1.x.0` release of the
|
||||||
|
mod jar.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## See also
|
||||||
|
|
||||||
|
- [`economy-system.md`](./economy-system.md) — gameplay-side design (currency, quest mechanics, villager rebalance, etc.)
|
||||||
|
- `MEMORY.md` entries — KubeJS Rhino gotchas, defaultconfigs pattern
|
||||||
+286
-38
@@ -1,6 +1,6 @@
|
|||||||
# Brass and Sigil — Economy & Quest System Design
|
# Brass and Sigil — Economy & Quest System Design
|
||||||
|
|
||||||
> Status: design draft (v0.1). Not yet implemented.
|
> Status: 13-tier ladder locked (v0.4). Architecture + UI confirmed in v0.3.
|
||||||
> Owner: matt
|
> Owner: matt
|
||||||
> Last updated: 2026-06-06
|
> Last updated: 2026-06-06
|
||||||
|
|
||||||
@@ -56,7 +56,7 @@ Each guild is a destination. The guild's NPC is both the **entry point** (accept
|
|||||||
|---|---|---|
|
|---|---|---|
|
||||||
| **Adventurer's Guild** | Combat & exploration | Bounty board (daily mob hunts), boss-kill quests, dungeon-delve quests (future) |
|
| **Adventurer's Guild** | Combat & exploration | Bounty board (daily mob hunts), boss-kill quests, dungeon-delve quests (future) |
|
||||||
| **Merchant's Bazaar** | Trade & raw-mat economy | Numismatics sell shop, dynamic exchange counter, player-driven job board |
|
| **Merchant's Bazaar** | Trade & raw-mat economy | Numismatics sell shop, dynamic exchange counter, player-driven job board |
|
||||||
| **Civic Office** | Land & status | Plot claim office, tier upgrades, sethome/warp services |
|
| **Civic Office** | Land & status | Tier upgrade screen, spawn plot registry (purchase / view your plots), sethome/warp services. NOTE: regular wilderness chunk claiming uses the FTB Chunks map and is tier-allocated, not paid per chunk — see §4. |
|
||||||
| **Library / Academy** | Knowledge & magic | FTB Quests anchor NPC, Ars Nouveau themed quests, lore terminals |
|
| **Library / Academy** | Knowledge & magic | FTB Quests anchor NPC, Ars Nouveau themed quests, lore terminals |
|
||||||
| **Tavern** | Social & onboarding | First-time newbie quests, casual NPCs, food/buff vendor |
|
| **Tavern** | Social & onboarding | First-time newbie quests, casual NPCs, food/buff vendor |
|
||||||
| **Foundry / Workshop** | Crafting & commissions | Create-themed contracts, crafting orders, raw-material market |
|
| **Foundry / Workshop** | Crafting & commissions | Create-themed contracts, crafting orders, raw-material market |
|
||||||
@@ -73,7 +73,68 @@ Both pay into the same wallet. Players run the campaign at their pace and the da
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 4. Quest & bounty flow (universal pattern)
|
## 4. Tier system & spawn plots
|
||||||
|
|
||||||
|
Two distinct land/status systems that often get conflated. Keeping them clean:
|
||||||
|
|
||||||
|
### 4a. Civic tier ladder
|
||||||
|
|
||||||
|
Every player has a Civic rank. Higher rank unlocks perks. Players spend spurs at the Civic Office NPC to upgrade. Powered by FTB Ranks under the hood (permission nodes drive what each rank unlocks).
|
||||||
|
|
||||||
|
The ladder is intentionally long (13 tiers) so endgame ranks feel rare and aspirational. Top tiers represent months of dedicated play; Sovereign is "you've finished the game."
|
||||||
|
|
||||||
|
| # | Title | Cost to reach | Wilderness chunks | Plot slots | Daily bounties | Shop fee | Chat colour | Join broadcast |
|
||||||
|
|---|---|---|---|---|---|---|---|---|
|
||||||
|
| 1 | **Peasant** | free (starter) | 9 | 0 | 3 | 0% | grey | — |
|
||||||
|
| 2 | **Farmer** | 200 | 18 | 0 | 3 | 0% | grey | — |
|
||||||
|
| 3 | **Citizen** | 750 | 35 | 1 | 3 | 0% | white | — |
|
||||||
|
| 4 | **Merchant** | 2,500 | 60 | 1 | 4 | -2% | yellow | — |
|
||||||
|
| 5 | **Knight** | 6,500 | 100 | 2 | 4 | -5% | green | simple |
|
||||||
|
| 6 | **Baron** | 15,000 | 150 | 2 | 5 | -7% | cyan | simple |
|
||||||
|
| 7 | **Viscount** | 35,000 | 220 | 3 | 5 | -9% | blue | fancy |
|
||||||
|
| 8 | **Earl** | 75,000 | 300 | 3 | 6 | -11% | purple | fancy |
|
||||||
|
| 9 | **Marquess** | 150,000 | 400 | 4 | 6 | -13% | gold | fancy |
|
||||||
|
| 10 | **Duke** | 300,000 | 525 | 5 | 7 | -15% | orange | epic |
|
||||||
|
| 11 | **Archduke** | 700,000 | 700 | 6 | 7 | -17% | red | epic |
|
||||||
|
| 12 | **Grand Duke** | 1,500,000 | 900 | 7 | 8 | -19% | bright red | epic + particles |
|
||||||
|
| 13 | **Sovereign** | 10,000,000 | 1,500 | 10 | 10 | -25% | rainbow | epic + spectacular |
|
||||||
|
|
||||||
|
**Travel philosophy:** this is a Create Aeronautics pack — the journey is the point. We deliberately do **not** give players sethomes, `/back`, or other instant-teleport conveniences. The intended travel system is **Waystones** (mod already in pack):
|
||||||
|
|
||||||
|
- Players get **one waystone** at the start of the game. It anchors their base.
|
||||||
|
- They can teleport between spawn ↔ their own waystone(s).
|
||||||
|
- Beyond that, real travel means building airships, trains, vehicles — the actual gameplay.
|
||||||
|
|
||||||
|
This is restrictive by design. We can layer **waystone-related perks** into the tier ladder in a later revision (e.g. "tier N unlocks 2nd waystone slot", or "tier M reduces waystone XP cost"). For V1 the ladder stays as above and travel pressure remains intentionally high.
|
||||||
|
|
||||||
|
**Notable shape choices:**
|
||||||
|
|
||||||
|
- **Knight (tier 5)** is the gentry threshold — first colored chat (green), first join broadcast, meaningful jump in plot slots
|
||||||
|
- **Duke → Archduke jump** is the late-game wall (300k → 700k, ~2.3×) — Archduke is the start of "I've really committed to this server" territory
|
||||||
|
- **Sovereign is dramatic** — 6.7× the Grand Duke cost. Real "finished the game" status. -25% shop fee is a step-change leap; spectacular join effects.
|
||||||
|
|
||||||
|
Numbers are first-pass calibration. The full perk table lives in a single JSON (`config/bnstoolkit/tiers.json`) that's hot-reloadable via `/bnstoolkit reload`. Easy to tune any column without code changes.
|
||||||
|
|
||||||
|
### 4a.1 Founder flag (admin cosmetic)
|
||||||
|
|
||||||
|
The server owner / admin has a permanent **`[Founder]`** cosmetic prefix in chat that sits alongside their normal rank. It carries no gameplay perks — it's just visible identification so friends know who runs the server. The Founder still grinds the regular tier ladder like everyone else (good for playtesting balance + sharing the experience). Op commands are the actual admin tool; the Founder tag is purely visual.
|
||||||
|
|
||||||
|
**Wilderness claims:** at every tier above Peasant, you get a flat allowance of N chunks you can claim anywhere outside spawn via the FTB Chunks map. Claiming is **free** within your allowance, refused above. No per-chunk pricing. Driven by FTB Ranks → FTB Chunks permission nodes (`ftbchunks.max_claimed_chunks`).
|
||||||
|
|
||||||
|
### 4b. Spawn plots
|
||||||
|
|
||||||
|
Spawn plots are a **separate system** from wilderness claims.
|
||||||
|
|
||||||
|
- **Pre-defined regions** at spawn — single chunks or small fixed clusters — designated by admins as "plots." Visible as fenced/bordered areas on the spawn map.
|
||||||
|
- **Purchased with spurs** at additional cost per plot (separate from tier upgrade cost). Indicative pricing: standard plot ~2,000 spurs, premium (corner / prime location) ~5,000 spurs.
|
||||||
|
- **Primary use:** shops. Players set up Numismatics shop blocks on their plots and sell to other players. Residence is allowed but secondary.
|
||||||
|
- **Slot-limited by tier:** your civic rank determines how many spawn plots you can own simultaneously (column above). Hit the limit, you can't buy another until you upgrade or release a plot.
|
||||||
|
- **Purchase happens inside the FTB Chunks map UI** — clicking a plot region in the map opens a confirmation screen (provided by our custom mod's mixin) showing cost + your remaining slots. Same UI you use for wilderness claims, integrated.
|
||||||
|
- **Plot data lives in the custom mod** (`bnstoolkit:plots`), not in FTB Chunks. Plots are a separate ownership system that uses the FTB Chunks map as its visual surface.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Quest & bounty flow (universal pattern)
|
||||||
|
|
||||||
**Core principle:** for any guild, the player **accepts** work from an NPC, **completes** it in the world, then **returns** to that NPC to **turn it in** and claim the reward. No instant payouts. This:
|
**Core principle:** for any guild, the player **accepts** work from an NPC, **completes** it in the world, then **returns** to that NPC to **turn it in** and claim the reward. No instant payouts. This:
|
||||||
|
|
||||||
@@ -120,12 +181,104 @@ The same accept → complete → return pattern works for every guild:
|
|||||||
| **Library** | "Recover this lost tome" | find the book in a structure | NPC pays + grants reputation |
|
| **Library** | "Recover this lost tome" | find the book in a structure | NPC pays + grants reputation |
|
||||||
| **Foundry** | "Craft 10 Andesite Casings" | craft them | NPC pays commission |
|
| **Foundry** | "Craft 10 Andesite Casings" | craft them | NPC pays commission |
|
||||||
|
|
||||||
### KubeJS implementation sketch
|
### Player-facing UI (locked)
|
||||||
|
|
||||||
- **State storage:** per-player JSON in `world/data/bns_quests/<uuid>.json`, written via KubeJS persistent-data hooks.
|
Polished, integrated, no chat commands to memorise. All player interaction happens through GUIs and NPC dialogue. Custom companion mod (working name `bnstoolkit`) provides the screens; FTB Library's UI framework is the visual basis so our screens match FTB Quests, FTB Chunks, and FTB Teams natively.
|
||||||
- **Event tracking:** standard KubeJS event handlers (`EntityEvents.death`, `ItemEvents.pickedUp`, `BlockEvents.broken`) read the player's active quests and increment.
|
|
||||||
- **Dialog branching:** Easy NPC dialog with conditions that call KubeJS to check quest state and route the dialog appropriately.
|
| Surface | Implementation |
|
||||||
- **Reward delivery:** call Numismatics' wallet API to deposit spurs.
|
|---|---|
|
||||||
|
| **Quest Log screen** | Custom mod screen. Tabs: Active / Available / Completed. Click a quest to inspect, cancel from the detail panel. Opened via keybind or by clicking a Quest Log block at any guild. |
|
||||||
|
| **Bounty Board screen** | Custom mod screen, opened by right-clicking the Adventurer's Guild Quartermaster NPC OR clicking the in-world Bounty Board block. Lists today's available daily bounties with descriptions, rewards, and "Accept" buttons. |
|
||||||
|
| **Tier upgrade screen** | Custom mod screen, opened at the Civic Office NPC. Visual ladder, your current tier highlighted, next-tier cost, perks unlocked at each rank, big Upgrade button. |
|
||||||
|
| **Plot purchase popup** | Custom mod mixin into the FTB Chunks map UI. Hover a plot region → cost + slots tooltip. Click → confirmation popup. Owned plots also clickable to see plot info. |
|
||||||
|
| **Shop browser** | Numismatics shop blocks render their existing inventory UI by default; optional richer browser screen for the central Merchant's Bazaar inventory. |
|
||||||
|
| **Quest progress HUD** | Custom mod render layer — styled HUD element showing active quest names + progress bars. NOT stacked vanilla bossbars. |
|
||||||
|
| **NPC dialogue + buttons** | Easy NPC handles all NPC interactions: accept/turn-in, info, tutorials, "click for details" buttons. Players learn the system through NPC dialogue, not by reading docs. |
|
||||||
|
|
||||||
|
### Why custom mod, on FTB Library's UI framework
|
||||||
|
|
||||||
|
- **Visual consistency:** FTB Quests, FTB Chunks, FTB Teams all use FTB Library's widget framework. Our screens built on the same framework will look and feel like part of the same product.
|
||||||
|
- **Already a pack dependency:** no new mod added just for the UI layer.
|
||||||
|
- **Mixin compatibility:** our spawn plot mixin into the FTB Chunks map operates on FTB Library widgets natively — no translation layer between vanilla MC widgets and FTB Library widgets.
|
||||||
|
- **Less boilerplate than vanilla MC Screen API:** Panel, BlockButton, IconButton, Tooltip, TextField widgets already exist and behave consistently with how players already know FTB UIs to work.
|
||||||
|
- **Forking FTB is off the table:** FTB mods are "All Rights Reserved" — depending on FTB Library as a library is fine (that's what libraries are for), forking FTB Quests or FTB Chunks for redistribution is not legally clean. Custom mod alongside the FTB stack is the correct architecture.
|
||||||
|
|
||||||
|
### Why NOT FTB Quests for daily bounties
|
||||||
|
|
||||||
|
FTB Quests stays for **long-form progression** (Phase 5+), not for daily bounties. Source review confirms:
|
||||||
|
|
||||||
|
- No abandon/cancel event (Ctrl+Shift+R reset fires no event we can hook)
|
||||||
|
- Cooldown is per-team, not per-player
|
||||||
|
- Visibility is per-team, not per-player — rotating "5 of 20 daily" doesn't fit cleanly
|
||||||
|
|
||||||
|
For long-form progression where one-shot rewards + team scope are fine, FTB Quests is great. Our custom bounty engine handles the daily/repeatable pattern with its own UI.
|
||||||
|
|
||||||
|
### Quest slot limit
|
||||||
|
|
||||||
|
Players have a **maximum of 3 active quests at a time.** This is the friction that makes cancel meaningful:
|
||||||
|
|
||||||
|
- Forces players to pick which quests they actually want — no "accept all 5, see what's easiest, cancel the rest" RNG-shopping.
|
||||||
|
- Keeps the state files small.
|
||||||
|
- Makes ready-to-turn-in queues meaningful (you can hold 3 unrewarded quests in your back pocket).
|
||||||
|
|
||||||
|
A quest moving to READY frees the slot for accepting a new one even before turn-in.
|
||||||
|
|
||||||
|
### KubeJS implementation — locked specifics
|
||||||
|
|
||||||
|
- **State storage:** per-player JSON in `world/data/bns_quests/<uuid>.json`. Schema:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"active": [
|
||||||
|
{
|
||||||
|
"id": "advg_plunderer_10",
|
||||||
|
"acceptedAt": 1717684800,
|
||||||
|
"progress": 7,
|
||||||
|
"target": 10,
|
||||||
|
"rewardSpurs": 50,
|
||||||
|
"source": "adventurers_guild",
|
||||||
|
"bossbarId": "bns:quest_advg_plunderer_10_<uuid>"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"completed": {
|
||||||
|
"advg_plunderer_10": { "cooldownUntil": 1717771200, "completions": 3 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- **Event tracking:** KubeJS event handlers (`EntityEvents.death`, `ItemEvents.pickedUp`, `BlockEvents.broken`) read the player's active quests and increment progress + update bossbar value.
|
||||||
|
|
||||||
|
- **Bossbar lifecycle:** on quest accept, KubeJS creates a unique per-player bossbar via `server.runCommandSilent('bossbar add <id> <name>')`, assigns it to that player only, updates `value` and `max` on progress. On turn-in or cancel: `bossbar remove`.
|
||||||
|
|
||||||
|
- **Numismatics integration (direct Java access — no events shipped, no KubeJS bindings):**
|
||||||
|
```js
|
||||||
|
const Numismatics = Java.loadClass('dev.ithundxr.createnumismatics.Numismatics');
|
||||||
|
const ReasonHolder = Java.loadClass('dev.ithundxr.createnumismatics.content.backend.ReasonHolder');
|
||||||
|
|
||||||
|
const acct = Numismatics.BANK.getAccount(player); // ServerPlayer
|
||||||
|
const balance = acct.getBalance(); // int (spurs)
|
||||||
|
acct.deposit(50); // pay quest reward
|
||||||
|
const ok = acct.deduct(100, ReasonHolder.empty()); // returns false if broke
|
||||||
|
Numismatics.BANK.markBankDirty(); // force persistence
|
||||||
|
```
|
||||||
|
|
||||||
|
- **Dialog branching:** Easy NPC dialog branches on scoreboard objective `bns.quest.<npc_tag>` that KubeJS mirrors quest state into. Dialog `Command` action triggers `/bns_quest accept <id> <npc_tag>` which routes to KubeJS.
|
||||||
|
|
||||||
|
- **Commands:** registered via `ServerEvents.commandRegistry` in KubeJS. Scoped to the player who runs them. The custom `/bns_quest` namespace handles NPC-triggered actions; `/quests` is the player-facing tracker.
|
||||||
|
|
||||||
|
- **FTB Chunks claim cost (Phase 2):** requires `FTB XMod Compat` mod. Then:
|
||||||
|
```js
|
||||||
|
FTBChunksEvents.before('claim', event => {
|
||||||
|
const player = event.source.player;
|
||||||
|
const acct = Numismatics.BANK.getAccount(player);
|
||||||
|
const cost = computeClaimCost(player);
|
||||||
|
if (acct.getBalance() < cost) {
|
||||||
|
event.setResult(ClaimResult.YOU_DO_NOT_HAVE_ENOUGH_SPURS); // custom enum value
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
acct.deduct(cost, ReasonHolder.empty());
|
||||||
|
});
|
||||||
|
```
|
||||||
|
**Note:** the `.before` may fire twice (sim + real). Guard with idempotent state, or do balance check in `.before` and deduct in `.after('claim')`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -193,18 +346,46 @@ The same accept → complete → return pattern works for every guild:
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 8. Mod stack (we have what we need)
|
## 8. Mod stack (locked)
|
||||||
|
|
||||||
| Need | Mod | Status |
|
### Already in pack
|
||||||
|
| Need | Mod | Version |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| Currency + wallets + shop blocks | Numismatics | ✅ In pack |
|
| Currency + wallets + shop blocks | Numismatics | 1.0.20 |
|
||||||
| NPC quest-givers + dialog | Easy NPC | ✅ In pack |
|
| NPC dialog presentation | Easy NPC | 6.16.x (6.17.0 available, minor bump) |
|
||||||
| Quest engine (progression) | FTB Quests | ⏳ Planned, not added |
|
| Plot claims | FTB Chunks | 2101.1.14 |
|
||||||
| Plot claims | FTB Chunks | ✅ In pack |
|
| Team management | FTB Teams | 2101.1.9 |
|
||||||
| Tier system | FTB Ranks | ❓ Not in pack — add when we get to tiers |
|
| Core library | FTB Library | 2101.1.31 |
|
||||||
| Glue & quest state | KubeJS | ✅ In pack |
|
| Cross-mod compat | Architectury API | 13.0.8 |
|
||||||
|
| Glue, commands, state | KubeJS | 2101.7.2 |
|
||||||
|
|
||||||
**Not adding:** CustomNPCs (Easy NPC covers it), Citizens (Bukkit-only), PMMO (out of scope), generic "quest giver" mods (FTB Quests + KubeJS do it).
|
### Adding in Phase 0a (mod-additions PR — blocks everything else)
|
||||||
|
| Mod | Version | Reason |
|
||||||
|
|---|---|---|
|
||||||
|
| **FTB Quests** | 2101.1.25 | Progression quest UI (Phase 5+) |
|
||||||
|
| **FTB XMod Compat** | latest 1.21.1 NeoForge | KubeJS hooks for FTB Chunks claim events + FTB Quests events |
|
||||||
|
| **FTB Ranks** | 2101.1.3 | Tier system. CurseForge only, no Modrinth listing. |
|
||||||
|
|
||||||
|
### Building our own (custom companion mod)
|
||||||
|
|
||||||
|
**`bnstoolkit`** (working name) — a small companion mod in our own repo. Confirmed locked-in.
|
||||||
|
|
||||||
|
- Provides all custom GUI screens (Quest Log, Bounty Board, Tier upgrade, Shop browser)
|
||||||
|
- Provides the FTB Chunks map mixins (spawn plot cost overlay, hover tooltip, purchase popup)
|
||||||
|
- Provides custom quest-progress HUD render layer
|
||||||
|
- Provides the `bnstoolkit:plots` data storage + ownership permissions
|
||||||
|
- Provides network packets for client↔server state sync
|
||||||
|
- Provides the `/bnstoolkit reload` admin command for hot-reloading tier config
|
||||||
|
- Built on FTB Library UI framework for visual consistency
|
||||||
|
- KubeJS handles all gameplay logic (bounty rotation, state machine, villager trades, Numismatics integration) — the mod is purely the UI + integration layer
|
||||||
|
|
||||||
|
Estimated scope: ~2-3k LOC, single-developer week of focused work. Bounded.
|
||||||
|
|
||||||
|
### Explicitly NOT adding
|
||||||
|
- CustomNPCs (Easy NPC covers it)
|
||||||
|
- Citizens (Bukkit-only)
|
||||||
|
- PMMO / skill mods (out of scope)
|
||||||
|
- Generic "quest giver" mods (FTB Quests + our KubeJS bounty engine cover it)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -212,17 +393,19 @@ The same accept → complete → return pattern works for every guild:
|
|||||||
|
|
||||||
Each phase is independently shippable. Earlier phases unlock value without depending on later ones.
|
Each phase is independently shippable. Earlier phases unlock value without depending on later ones.
|
||||||
|
|
||||||
| Phase | Deliverable | Why this order |
|
| Phase | Deliverable | Spawn build required? |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| **0** | Spawn skeleton built — 7 guild buildings placed (rough). | Locations have to exist before NPCs can stand in them. |
|
| **0a** | **Mod additions PR:** FTB Quests + FTB XMod Compat + FTB Ranks (+ minor Easy NPC bump). New pack version. | No |
|
||||||
| **1** | **Merchant's Bazaar V1:** Numismatics sell shop (fixed prices, no DR yet) for diamonds & netherite. | Cheapest to ship, immediate economy unlock. |
|
| **0b** | Spawn skeleton — 7 guild building blockouts (rough). **User does in-game when time permits.** Non-blocking. | Yes (user) |
|
||||||
| **2** | **Civic Office V1:** Plot claim cost via KubeJS `/ftbchunks claim` override. | Real money sink. Tests FTB Chunks integration depth. |
|
| **0c** | **`bnstoolkit` companion mod — scaffolding pass.** Mod project set up, FTB Library UI dependency wired, network packet plumbing, build/release scripts. No screens yet. | No |
|
||||||
| **3** | **Adventurer's Guild V1:** Bounty board engine. 5 daily quests, accept→complete→return flow. | The biggest gameplay feature. Validates the universal quest pattern. |
|
| **1** | **Sell shop:** Numismatics shop blocks for diamonds (10 spurs) + netherite ingots (100 spurs). Lifetime-sale tracker for diminishing returns. KubeJS only, no mod work needed. | No |
|
||||||
| **4** | **Villager rebalance:** strip vanilla, ship the spur-priced trade table. | Closes the exploit. Big JSON pass. |
|
| **2** | **Tier upgrade flow:** FTB Ranks integrated + KubeJS `/tier upgrade` command. **`bnstoolkit` Tier upgrade screen** wired to Civic Office NPC. Tier perks driven by `tiers.json`. | No |
|
||||||
| **5** | **Library / Academy:** FTB Quests anchor + first chapter of progression quests. | Long-form content begins. |
|
| **3** | **Spawn plot system:** plot region registry in `bnstoolkit`, ownership tracking, FTB Chunks map mixin (cost overlay + purchase popup). | No |
|
||||||
| **6** | **Civic Office V2:** FTB Ranks integration + tier upgrades. | Endgame money sink. |
|
| **4** | **Bounty engine:** state machine, KubeJS-rotated dailies, `bnstoolkit` Bounty Board screen + Quest Log screen + Quest progress HUD. NPC dialog hooks via Easy NPC. 3-slot cap. | No (NPC layer activates once spawn is built) |
|
||||||
| **7** | **Dynamic exchange rates** (Bazaar V2). | Most engineering, biggest anti-farm payoff, ship last. |
|
| **5** | **Villager rebalance:** strip vanilla, ship spur-priced trade table via `ServerEvents.villagerTrades`. | No |
|
||||||
| **8+** | Foundry, Tavern, deeper Library quests, dungeons-with-Lootr. | Beyond V1. |
|
| **6** | **Progression quest line:** FTB Quests anchor + first chapter. KubeJS rewards dispense spurs via Numismatics API. | No (anchor NPC at Library once spawn exists) |
|
||||||
|
| **7** | **Dynamic exchange rates:** global supply-pool pricing for raw mats. | No |
|
||||||
|
| **8+** | Lootr dungeons, Foundry crafting commissions, deeper FTB Quests chapters, player-vs-player bounties (if wanted). | TBD |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -239,24 +422,89 @@ Each phase is independently shippable. Earlier phases unlock value without depen
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 11. Open decisions
|
## 11. Decisions made
|
||||||
|
|
||||||
These need an actual call before implementation:
|
Resolved before implementation:
|
||||||
|
|
||||||
1. **Keep emeralds as a secondary collectible?** Or fully retire them now that villagers don't use them?
|
| Question | Decision |
|
||||||
2. **Sethomes / warps as paid services?** Or free baseline?
|
|---|---|
|
||||||
3. **PvP bounties** (players posting bounties on other players)? Probably no for V1, revisit later.
|
| Quest UI for bounties | **Custom mod with FTB Library UI widgets** — proper GUI screens, no chat commands |
|
||||||
4. **Lootr** — add for shared dungeon loot, or skip until structured dungeons exist?
|
| Quest UI for progression | FTB Quests |
|
||||||
5. **Daily quest count** — start with 5? 8? Refresh window — true daily (00:00 UTC) or per-player 24h?
|
| Plot purchase UI | Custom mod mixin into FTB Chunks map — hover preview, click-to-buy popup |
|
||||||
|
| Tier upgrade UI | Custom mod screen at Civic Office NPC |
|
||||||
|
| State storage | KubeJS-managed per-player JSON for quest state; mod-managed for plot ownership |
|
||||||
|
| Numismatics access | Direct Java via `Java.loadClass` from KubeJS; via API directly from the mod |
|
||||||
|
| Wilderness chunk allowance | Tier-driven via FTB Ranks permission nodes — no per-chunk pricing |
|
||||||
|
| Spawn plots | Predefined regions, slot-limited by tier, individually purchased with spurs |
|
||||||
|
| Tier ladder | Civic (13 tiers): Peasant → Farmer → Citizen → Merchant → Knight → Baron → Viscount → Earl → Marquess → Duke → Archduke → Grand Duke → Sovereign |
|
||||||
|
| Founder flag | Admin/owner has `[Founder]` cosmetic prefix in chat, grinds the regular ladder otherwise |
|
||||||
|
| Tier perks | JSON-configured (`config/bnstoolkit/tiers.json`), hot-reloadable |
|
||||||
|
| Custom mod | Confirmed. Built on FTB Library UI framework. Working name `bnstoolkit`. |
|
||||||
|
| Sethomes / warps | Tier-allocated count (not paid per use) |
|
||||||
|
| Daily quest count | Tier-driven (3 at Peasant, up to 6 at Sovereign), refresh per-player 24h after last accept |
|
||||||
|
| Emeralds | Retired as currency, retain as a trade material for villager-redirect trades |
|
||||||
|
| Fork FTB | Not needed — depend on FTB Library as a UI lib, FTB Chunks/Quests stay unmodified, integration via mixins + KubeJS hooks |
|
||||||
|
|
||||||
|
### Still to decide (non-blocking — pick during implementation)
|
||||||
|
|
||||||
|
- **PvP bounties** — out of scope for V1, revisit after V1 ships
|
||||||
|
- **Lootr** — add only when structured dungeons exist (Phase 8+)
|
||||||
|
- **Default-rank starting permissions** — finalised when FTB Ranks config is written
|
||||||
|
- **Spawn plot pricing** — first-pass numbers (2,000 standard / 5,000 premium), tune in playtest
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 12. Implementation notes
|
## 12. Implementation notes
|
||||||
|
|
||||||
- Document each phase's KubeJS scripts under `pack/overrides/kubejs/server_scripts/economy/<phase>.js`
|
### KubeJS scripts (gameplay logic)
|
||||||
- State data under `world/data/bns_economy/` — readable JSON, easy to debug
|
Organised under `pack/overrides/kubejs/server_scripts/economy/`:
|
||||||
- All NPC dialog trees authored in Easy NPC's editor, exported as preset JSONs into `pack/overrides/world/datapacks/bns-fuel/data/easy_npc/`
|
|
||||||
- Trade table for villager rebalance lives in a single `villager_trades.js` so one file is the source of truth
|
- `01_numismatics_api.js` — Java.loadClass wrapper helpers (balance / deposit / deduct)
|
||||||
|
- `02_quest_state.js` — load/save `world/data/bns_economy/quests/<uuid>.json`
|
||||||
|
- `03_commands.js` — admin commands (`/tier upgrade`, `/bnstoolkit reload`, debug)
|
||||||
|
- `04_bounty_engine.js` — daily rotation, state machine, KubeJS↔mod packet handlers
|
||||||
|
- `05_sell_shop.js` — Numismatics shop tracking + diminishing returns
|
||||||
|
- `06_villager_trades.js` — Phase 5 `ServerEvents.villagerTrades` rebalance
|
||||||
|
- `07_tier_perks.js` — FTB Ranks promote/demote, perk application
|
||||||
|
- `99_dynamic_exchange.js` — Phase 7 supply-priced market
|
||||||
|
|
||||||
|
### Custom mod codebase
|
||||||
|
Repo: separate (or sub-tree of main repo, TBD).
|
||||||
|
Modid: `bnstoolkit` (working name).
|
||||||
|
Package layout:
|
||||||
|
|
||||||
|
```
|
||||||
|
bnstoolkit/
|
||||||
|
├── client/
|
||||||
|
│ ├── screen/ QuestLog, BountyBoard, Shop, Tier, PlotConfirm (FTB Library subclasses)
|
||||||
|
│ ├── mixin/ ChunkScreenPanel (cost overlay + plot button), ChunkButton (hover tooltip)
|
||||||
|
│ ├── hud/ QuestProgressHud (custom render)
|
||||||
|
│ └── ClientEvents keybind reg, screen reg, mixin loader
|
||||||
|
├── server/
|
||||||
|
│ ├── packet/ OpenScreen, UpgradeRank, BuyPlot, ClaimBounty, etc.
|
||||||
|
│ ├── command/ /bnstoolkit reload (config refresh)
|
||||||
|
│ └── data/ PlotRegistry, PlotOwnership (saved with world data)
|
||||||
|
├── common/
|
||||||
|
│ ├── data/ TierConfig (JSON-loaded), BountyDefinition, QuestState mirror
|
||||||
|
│ └── BnsToolkit.java mod entry
|
||||||
|
└── config-defaults/
|
||||||
|
├── tiers.json copied to config/bnstoolkit/tiers.json on first run
|
||||||
|
└── plots.json spawn plot region definitions
|
||||||
|
```
|
||||||
|
|
||||||
|
Architecture doc (`docs/bnstoolkit-architecture.md`) covers package layout, screen UX sketches, network packet contract, mixin targets, KubeJS↔mod integration surface — to be written before mod work begins.
|
||||||
|
|
||||||
|
### State data
|
||||||
|
- Quest state: `world/data/bns_economy/quests/<uuid>.json`. Readable JSON, easy to debug.
|
||||||
|
- Plot ownership: persisted with world via the mod's `SavedData` (vanilla NeoForge persistence). Authoritative source of truth.
|
||||||
|
- Tier config: `config/bnstoolkit/tiers.json` shipped from `pack/overrides/defaultconfigs/bnstoolkit/tiers.json`. Hot-reloadable.
|
||||||
|
- Plot definitions: `config/bnstoolkit/plots.json` shipped similarly. Defines plot region bounds, type (standard/premium), prices.
|
||||||
|
|
||||||
|
### NPC dialog
|
||||||
|
Authored in Easy NPC's in-game editor, exported as preset JSONs into `pack/overrides/world/datapacks/bns-fuel/data/easy_npc/`. Dialog `Command` actions call `/bnstoolkit <verb> ...` which routes to either the mod (for screen-opening) or KubeJS (for state changes).
|
||||||
|
|
||||||
|
### Villager rebalance
|
||||||
|
Single source file `06_villager_trades.js`. Each profession × tier has its own block. One file = one diff per balance pass.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
+35
-2
@@ -1,13 +1,13 @@
|
|||||||
{
|
{
|
||||||
"$schema": "Brass-and-Sigil pack.lock.json - generated, do not edit by hand unless you know what you are doing",
|
"$schema": "Brass-and-Sigil pack.lock.json - generated, do not edit by hand unless you know what you are doing",
|
||||||
"name": "Brass and Sigil",
|
"name": "Brass and Sigil",
|
||||||
"version": "0.31.2",
|
"version": "0.32.0",
|
||||||
"minecraft": "1.21.1",
|
"minecraft": "1.21.1",
|
||||||
"loader": {
|
"loader": {
|
||||||
"type": "neoforge",
|
"type": "neoforge",
|
||||||
"version": "21.1.228"
|
"version": "21.1.228"
|
||||||
},
|
},
|
||||||
"lockedAt": "2026-06-01T19:47:31Z",
|
"lockedAt": "2026-06-06T23:21:32Z",
|
||||||
"mods": [
|
"mods": [
|
||||||
{
|
{
|
||||||
"source": "modrinth",
|
"source": "modrinth",
|
||||||
@@ -1097,6 +1097,39 @@
|
|||||||
"sha1": "4d81055810e07a94b68d16ab20ec298ad0d597a0",
|
"sha1": "4d81055810e07a94b68d16ab20ec298ad0d597a0",
|
||||||
"size": 29865,
|
"size": 29865,
|
||||||
"side": "both"
|
"side": "both"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": "curseforge",
|
||||||
|
"slug": "ftb-quests",
|
||||||
|
"fileId": "8195575",
|
||||||
|
"version": "2101.1.25",
|
||||||
|
"path": "mods/ftb-quests-neoforge-2101.1.25.jar",
|
||||||
|
"url": "https://mediafilez.forgecdn.net/files/8195/575/ftb-quests-neoforge-2101.1.25.jar",
|
||||||
|
"sha1": "c51f43029930cce87e86366b6629a27e4876a03d",
|
||||||
|
"size": 1469336,
|
||||||
|
"side": "both"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": "curseforge",
|
||||||
|
"slug": "ftb-xmod-compat",
|
||||||
|
"fileId": "7715134",
|
||||||
|
"version": "21.1.8",
|
||||||
|
"path": "mods/ftb-xmod-compat-neoforge-21.1.8.jar",
|
||||||
|
"url": "https://mediafilez.forgecdn.net/files/7715/134/ftb-xmod-compat-neoforge-21.1.8.jar",
|
||||||
|
"sha1": "0c25fc1a43c99eaa68c883dc77e3ebf4539629e6",
|
||||||
|
"size": 141328,
|
||||||
|
"side": "both"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": "curseforge",
|
||||||
|
"slug": "ftb-ranks",
|
||||||
|
"fileId": "6431744",
|
||||||
|
"version": "2101.1.3",
|
||||||
|
"path": "mods/ftb-ranks-neoforge-2101.1.3.jar",
|
||||||
|
"url": "https://mediafilez.forgecdn.net/files/6431/744/ftb-ranks-neoforge-2101.1.3.jar",
|
||||||
|
"sha1": "07fdfa3a75c3481770ce0118090a347d89e3a560",
|
||||||
|
"size": 88382,
|
||||||
|
"side": "both"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"defaultServer": {
|
"defaultServer": {
|
||||||
|
|||||||
Reference in New Issue
Block a user