feature/v0.36.0-bnstoolkit-0.4.1
Post-review consolidation PR. All four open issues from the parallel code/security/hotkey/NPC audits resolved in one ship. Key user-facing changes: UI - Single keybind: B opens a hub screen with buttons to the 5 sub-screens. - K/J/N/H/M direct shortcuts default to UNBOUND so they no longer compete with the ~100 other mods. Rebindable in vanilla controls menu. - M used to clash with vanilla Social Interactions + FTB Chunks fullscreen map; fully resolved. NPC dialogue + scripting integration - New /bns open <screen> command. Easy NPC dialogue COMMAND actions can now open any bnstoolkit screen on the clicking player. - FTB Quests reward commands, command blocks, and /trigger objectives can all route into bnstoolkit screens via the same command. - config/easy_npc/security.cfg ships with executeAsUserCommandAllowList .ALL=bns so dialogue-triggered /bns commands actually run. Bug fix (this is the load-bearing item) - Bounty board + plot office screens were reading NBT keys that don't exist in KubeJS, so they always showed "no active bounties" and "all plots free" no matter what was actually in the world. Fixed by reading the real per-player keys (bnsBountyPool/Active/Completed) and the server-scope bnsPlots compound via KubeJS' MinecraftServer mixin (reflective, no compileOnly dep on KubeJS). Hardening (no behavior change, defense-in-depth) - Per-player token bucket on C2S packets (10/s sustain, 20 burst). - All STRING_UTF8 codec fields capped at sane sizes (≤80 chars). - Verb whitelist replaced with structured parse + per-verb regex validation + rebuilt command. No prefix-startsWith surprises. - Tier-upgrade in-flight guard closes the concurrent-packet double-spend race window. - Log lines sanitised to prevent control-char injection. Plus the nits caught by review: - Per-player tick counter for HUD push (was a shared static) - VillagerTradeRebalance try/catch + null-cost-A passthrough + round-to-nearest denom split (was floor — ~10% silent price haircut) - SpurHud component cache (was allocating per frame) - BountyBoardScreen dead branch removed Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Brass & Sigil
Self-hosted Minecraft modpack distribution + administration system. Three components, one repo:
brass-and-sigil/
├── launcher/ ← Avalonia desktop client (Windows .NET 8)
│ Auths with Microsoft, syncs the modpack, launches the game.
├── server/ ← brass-sigil-server daemon (Linux .NET 8)
│ Wraps the MC subprocess, exposes the admin web panel,
│ syncs mods, runs backups + BlueMap, handles whitelist.
├── pack/ ← Modpack content
│ ├── pack.lock.json Source of truth for mod versions / URLs / hashes
│ ├── tweaks/ Hand-written data-only tweak source
│ └── overrides/ Build output / hand-placed local files (gitignored)
├── scripts/ ← Build + deploy entry points (run from repo root)
│ ├── Update-Pack.ps1 Refresh pack.lock.json from Modrinth/CurseForge
│ ├── Check-Updates.ps1 Non-mutating "what's new?" report
│ ├── Build-Tweaks.ps1 Compile tweaks/ into pack/overrides/mods/*.jar
│ ├── Build-Pack.ps1 Generate manifest.json from the lockfile
│ └── Deploy-Brass.ps1 One-shot build + deploy everything
└── docs/ ← Operational notes, deploy runbook, schema docs
Quick start
# Pull dependencies, copy and edit the deploy profile
git clone <remote> brass-and-sigil
cd brass-and-sigil
Copy-Item scripts\deploy.config.template.ps1 scripts\deploy.config.ps1
notepad scripts\deploy.config.ps1 # fill in deploy share, SSH host, etc.
# Build + deploy everything in one go
.\scripts\Deploy-Brass.ps1
deploy.config.ps1 is gitignored -- local values never get committed.
Component reference
| Component | What it does | Technology |
|---|---|---|
launcher/ |
Friend-distributed client. Auths with Microsoft via WebView2 + XboxAuthNet, downloads mods, launches Minecraft. Single self-contained .exe published from publish/. |
Avalonia 12 + CmlLib.Core |
server/ |
Daemon running alongside the MC process on Linux. Hosts a Kestrel web panel for admin (cookie-auth, rate-limited), bridges RCON, runs scheduled backups + BlueMap renders, handles whitelist requests. | ASP.NET Core minimal APIs |
pack/ |
Lockfile-driven modpack content. pack.lock.json resolves mod slug → URL+SHA-1; Build-Pack.ps1 walks it and produces manifest.json for the launcher and the server-tool to consume. |
PowerShell tooling |
Workflow
- Bump mod versions:
.\scripts\Update-Pack.ps1(queries Modrinth + manual CurseForge entries). - Sanity-check:
.\scripts\Check-Updates.ps1for a non-mutating availability report. - Edit tweaks under
pack/tweaks/<name>/if you're changing recipes / loot / etc. - Deploy:
.\scripts\Deploy-Brass.ps1-- builds launcher + server, regenerates manifest, mirrors everything to the deploy share, scp's the server binary.
Secrets / config files
| File | Tracked? | Notes |
|---|---|---|
launcher/launcher-config.template.json |
✓ | Empty placeholders, public-safe |
launcher/launcher-config.json |
✗ | Local override; merged into the published exe at build time if present |
server/deploy/server-config.example.json |
✓ | Template; rename to server-config.json on the server with real values |
server/deploy/server-config.json |
✗ | Production config; lives on the server only |
scripts/deploy.config.ps1 |
✗ | Local deploy profile (paths, SSH host, share location) |
License
See LICENSE.
Languages
C#
53.1%
JavaScript
23.9%
PowerShell
12.9%
HTML
5.3%
CSS
2.9%
Other
1.9%