Usurper Reborn - v0.30.0 "Band of Brothers"
Massive multiplayer expansion with 10 new features: Player Teams, Offline Mail, Player Trading, Cooperative Dungeons, Player Bounties, Auction House, Team Wars, World Boss Events, Castle Siege, and Team Headquarters. Players can form teams, trade items, place bounties, fight world bosses together, siege the castle as a team, and upgrade their team HQ. Also includes server memory optimization (71% smaller binary, ~50% less RAM per session).
Player Teams (Online)
Players can now create and join teams that are visible to other players across sessions. Previously, only NPC teams existed — player-created teams were invisible to anyone else.
How It Works
- Create Team at the Team Corner costs gold (scales with level). Team is registered in a central database so other players can find and join it.
- Join Team by name + password. The system checks player teams first, then falls back to NPC teams.
- Quit Team automatically updates the registry. If all members leave, the team is deleted.
- Team Rankings now shows both player-created teams and NPC teams, merged and sorted by power.
- Team Status shows player members (with online/offline status) alongside NPC members.
- Login Validation: If your team was disbanded while you were offline, you're automatically removed on next login.
Team Name Collision
Team names are checked against both the NPC team list and the player teams database — no duplicates allowed.
Offline Mail (/mail)
A full mailbox system for sending messages to any player, online or offline.
Mailbox UI
Type /mail from any location to open your mailbox:
- Paginated inbox showing sender, date, and message preview
- Unread messages marked with
* - [R]ead # to read a full message
- [S]end to compose and send a new message
- [D]elete # to delete a message
- [N]ext/[P]rev Page for pagination
Enhanced /tell
The /tell command now works for offline players too:
- Validates that the recipient exists before sending
- Shows "Message sent!" for online players, or "(offline — they'll see it next login)" for offline players
- Messages always go through the database, so they're never lost
While You Were Gone
Login summary now shows:
- Unread mail count with "/mail" hint
- Pending trade packages with "/trade" hint
Spam Protection
- Maximum 20 messages per day per sender
- Message length capped at 200 characters
Player Trading (/trade)
An async "package" system for sending items and gold to other players.
How It Works
- Player A opens
/tradeand selects [S]end Package - Picks items from inventory (up to 5) and/or a gold amount
- Items are removed from inventory and gold is deducted immediately (escrowed)
- Package is stored in the database with an optional note
- Recipient gets a notification message
- Recipient opens
/tradeand sees pending packages - [A]ccept to receive items and gold, or [D]ecline to return everything to sender
Trade Menu
Type /trade from any location:
- Incoming: Shows packages waiting for you with sender, contents, and note
- Sent: Shows your outgoing pending packages
- [A]ccept # / [D]ecline # / [C]ancel # / [S]end Package
Safety
- Self-trading blocked
- Maximum 10 pending outgoing packages
- Expired packages (7+ days) auto-return gold to sender
- Declined packages return gold to sender immediately
Cooperative Dungeon Runs
Recruit your teammates' characters as AI-controlled "echoes" that fight alongside you in the dungeon.
How It Works
- At the Team Corner, select [W] Recruit Player Ally (online mode only)
- See a list of players on your team with their level and class
- Select an ally — their character is loaded from the database
- Enter the dungeon — their echo materializes beside you with their real stats, spells, and abilities
- Echoes fight as AI-controlled allies in combat
Echo Rules
- Echoes start at full HP from the player's saved stats
- Echoes DO contribute to the 15% team combat bonus
- Echoes do NOT receive XP (their save data is never modified)
- Echo "death" shows "X's echo dissipates into mist..." — no permanent effect
- Echoes are verified to still be on your team at dungeon entry
- Party size cap: 4 total (companions + NPC teammates + player echoes)
Shared Utility
The PlayerCharacterLoader class is a new shared utility that creates combat-ready Characters from saved player data. Used by the PvP Arena, Cooperative Dungeons, and future Team Wars.
Server Memory Optimization
Comprehensive memory optimization for the AWS t3.micro (1GB RAM) server. Player sessions previously used ~185MB each and the world simulator ~213MB, almost entirely from .NET runtime overhead.
GC Tuning
- Switched from Server GC to Workstation GC — Server GC pre-allocates large heap segments designed for multi-core servers, wasting memory on single-vCPU instances
- Disabled Concurrent GC and RetainVM to reduce background memory overhead
- Set HeapHardLimit to 512MB — forces aggressive garbage collection instead of letting the managed heap grow unbounded
IL Trimming & Dependency Cleanup
- Enabled PublishTrimmed with partial trim mode — removes unused .NET framework code at publish time
- Removed unused NuGet packages:
Newtonsoft.Json,Microsoft.Extensions.DependencyInjection - Publish size reduced from 116MB to 34MB (71% reduction)
- Preserved
System.Text.Jsonreflection codepath required for save/load serialization
Unbounded Collection Caps
- Capped story event log at 500 entries (was 1000), oldest trimmed first
- Capped pending player notifications at 100 (drops oldest when full)
- Capped telemetry event re-queue on failure to prevent infinite buildup
- Capped monarch history at 100 records and royal mail at 50 messages
- Capped recurring duelist cache at 200 entries with LRU eviction
- WorldSimulator emotional cascade rate-limiter now auto-clears every 100 ticks
Results
- Publish size: 116MB → 34MB (71% smaller)
- Expected runtime memory: ~185MB → ~80-120MB per player session
- More headroom for concurrent players on the 1GB server
Player Bounties (/bounty)
Place gold bounties on other players. When someone defeats the target in the PvP Arena, the bounty is automatically collected.
How It Works
- Type
/bountyfrom any location to open the bounty board - [P]lace Bounty: Pick a target player and set a gold amount (minimum 500g). Gold is deducted immediately.
- [M]y Bounties: View bounties you've placed and their status
- Arena Integration: When you defeat a player in PvP, any active bounties on them are automatically claimed and added to your gold
- Bounty collection is announced in the news feed
- Maximum 3 active bounties per player
- 24-hour cooldown: can't place a new bounty on someone you already have an active bounty on
Auction House (/auction)
A public marketplace where players can list items for sale and browse/buy items from other players.
How It Works
- Type
/auctionfrom any location to open the Auction House - [B]rowse Listings: See all active auctions with item name, seller, and price
- [S]ell Item: Select an item from your inventory, set a price, and list it for 48 hours
- [M]y Listings: View your active listings and cancel them if needed
- Buying an item transfers gold to the seller (via
AddGoldToPlayer) and adds the item to your inventory - Expired listings are automatically cleaned up
- Maximum 5 active listings per player
Team Wars
Teams can now challenge each other to organized battles with gold wagers.
How It Works
- At the Team Corner, select [B] Team Battle (War) (online mode only)
- [C]hallenge: Pick an enemy team and wager gold. Your team must have at least 2 members.
- Round-Robin Combat: Each team member fights one opponent in auto-resolved combat based on stats with ±20% randomness
- Winner Takes All: The winning team gets 2x the gold wager
- [H]istory: View past team war results
- 24-hour cooldown between wars for each team pair
- Results and gold changes posted to the news feed
World Boss Events
Massive bosses that all players on the server can fight together. Damage accumulates across sessions until the boss is defeated or expires.
How It Works
- On Main Street, select [7] World Boss (online mode only)
- A world boss is always active — if none exists, one spawns automatically from 8 boss templates (Level 35-80, HP 40K-200K)
- HP Bar: Shows the boss's remaining health as a visual bar
- Attack: Fight the boss for 5 rounds. Your damage is recorded in the database.
- Damage Leaderboard: See which players have dealt the most damage
- When a boss is defeated, all contributors receive gold rewards proportional to their damage
- Bosses expire after 24 hours if not defeated
- Level 10+ required to participate
Castle Siege
Teams can storm the castle together to overthrow the king. A team-based alternative to the solo Throne Challenge.
How It Works
- At the Castle (commoner view), select [B]esiege the Castle (online mode, team required)
- Your full team is loaded from the database for the assault
- Phase 1 — Monster Guards: Your team fights through the king's monster guards together with combined team power
- Phase 2 — Royal Guards: Your team fights through NPC guards. Low-loyalty guards may surrender during a siege.
- Phase 3 — The King: If all guards are defeated, you face the king in single combat as siege leader
- Victory: You leave your team, claim the throne, and become the new ruler
- Failure: Your team retreats, you lose half your HP
- 24-hour cooldown between siege attempts per team
- All siege outcomes posted to the news feed
Team Headquarters
A new team management hub where teams can invest gold in upgrades and manage a shared vault.
How It Works
- At the Team Corner, select [H] Team Headquarters (online mode, team required)
- Facilities: Five upgradeable facilities, each with 10 levels:
- Armory: +2% team attack per level
- Barracks: +5 max team members per level
- Training Grounds: +3% team XP per level
- Vault: +50,000 gold capacity per level
- Infirmary: +5% post-combat healing per level
- Upgrade: Invest gold to upgrade facilities. Cost scales with level.
- Team Vault: Shared gold storage. Deposit and withdraw gold. Capacity depends on Vault upgrade level.
- Upgrade progress persists in the database
Wizard/Immortal System (MUD Administration style)
Seven tiers of administration power, 35+ wizard commands, WizNet communication channel, and full audit logging.
Wizard Hierarchy
| Level | Title | Key Powers |
|---|---|---|
| 0 | Mortal | Normal player |
| 1 | Builder | WizNet chat, /wizwho, /stat, /where, /holylight
|
| 2 | Immortal | /invis, /goto, /godmode, /heal, /restore, /peace, /echo
|
| 3 | Wizard | /summon, /transfer, /snoop, /force, /set, /slay, /freeze, /mute
|
| 4 | Archwizard | /ban, /unban, /kick, /broadcast, /promote, /demote
|
| 5 | God | /shutdown, /reboot, /admin, /wizlog
|
| 6 | Implementor |
Key Features
- WizNet: Wizard-only communication channel. Chat messages, system notifications (login/logout), and action alerts (promotions, kicks, bans).
- Invisibility: Immortal+ can toggle
/invisto hide from/who, room presence lists, and arrival/departure messages. Higher-level wizards can still see lower-level invisible wizards. - Godmode: Immortal+ can toggle
/godmode— HP and Mana are fully restored after every combat (PvE and PvP). Wizards cannot die in combat. - Player Manipulation: Wizard+ can
/setplayer stats (online or offline),/forcecommands,/snoopoutput,/freeze(block all input) and/mute(block chat only). - Promotion Safety: Can only promote up to one level below your own tier. No one can promote to Implementor.
- Audit Trail: Every wizard action logged to
wizard_logtable with wizard name, action, target, details, and timestamp. Viewable via/wizlog. - Freeze/Mute Persistence: Freeze and mute flags persist across sessions via the
wizard_flagsdatabase table. - Bootstrap Mechanism:
--adminCLI flag now writes God-level wizard status to the database at server startup.
Database Changes
wizard_levelcolumn added toplayerstablewizard_logtable for audit trailwizard_flagstable for persistent freeze/mute state
Marketplace / Auction House (Online)
The Marketplace is now accessible in online mode via [J] from Main Street or /auction from any location. Players and NPCs can buy and sell items through a shared SQL-backed auction house.
- Browse Listings: View all active listings with item name, price, seller, and time remaining
- Sell Items: List inventory items for sale with custom pricing. Max 5 active listings per player. Listings expire after 48 hours.
- Buy Items: Purchase items from other players or NPCs. Gold is atomically transferred to the seller (even if offline).
- Sale Notifications: Sellers receive an in-game message when their item sells.
- Cancel Listings: Cancel active listings to get your item back.
- NPC Participation: NPCs list dungeon loot and purchased items at the marketplace. NPCs also browse and buy items they want, creating a living economy.
- Single-player:
[J]opens the original in-memory marketplace (unchanged).
Smarter NPC Behavior
NPCs now make significantly smarter decisions based on past experiences, social bonds, and world state.
Memory-Driven Behavior
- NPCs who were badly defeated in the dungeon now strongly avoid returning (scaled by severity — a near-death experience creates much stronger avoidance than a minor scuffle)
- Positive and negative experiences at specific locations shape future behavior: successful trades make NPCs return to the marketplace; traumatic events make them avoid that location
- All recent memories are now factored in, not just the 5 most recent
Relationship-Driven Movement
- NPCs actively seek out friends — they prefer locations where friends are present and avoid locations where enemies lurk
- When choosing where to wander, married couples and close friends gravitate toward each other
- The Inn becomes a true social hub: friends at the Inn pull other friends there
- Enemies at a location act as a repellent, reducing the chance NPCs will visit
World Event Reactions
- During War: Aggressive and courageous NPCs rush to the dungeon to fight; cautious NPCs hide at home and protect their gold at the bank; Crown faction members rally to the castle
- During Plague: Everyone seeks more healing and temple visits; cautious NPCs strongly avoid the dungeon; sociable NPCs reduce gatherings at the Inn and Love Street to avoid contagion
- During Festivals: Sociable NPCs flock to the Inn to celebrate; marketplace activity increases; dungeon exploration decreases (why fight monsters during a party?)
- Throne Events: Crown faction NPCs rally to the castle; Shadows faction celebrates in the Dark Alley; Faith faction prays at the Temple
Bug Fixes
- Combat tips showing class-specific hints to wrong classes: Ranger's
[V]ranged attackand Barbarian's[G]ragetips could appear for any class. Class-specific tips now only show to the relevant class. - Combat tip wrong key for healing: Tip said
[I]for healing potions but the actual key is[H]. Fixed.
Files Changed
| File | Changes |
|---|---|
Scripts/Core/GameConfig.cs
| Version bump to 0.30.0 "Band of Brothers" |
Scripts/Systems/SqlSaveBackend.cs
| 8 new tables (player_teams, trade_offers, bounties, auction_listings, team_wars, world_bosses, world_boss_damage, castle_sieges, team_upgrades, team_vault); ~50 new backend methods for all features
|
Scripts/Systems/IOnlineSaveBackend.cs
| Data classes: PlayerTeamInfo, TradeOffer, BountyInfo, AuctionListing, TeamWarInfo, WorldBossInfo, WorldBossDamageEntry, CastleSiegeInfo, TeamUpgradeInfo
|
Scripts/Systems/PlayerCharacterLoader.cs
| NEW — shared utility for loading players from DB as AI Characters |
Scripts/Locations/TeamCornerLocation.cs
| Online mode in Create/Join/Quit/Rankings/Status; [W] Recruit Player Ally; [B] Team Battle (War); [H] Team Headquarters with upgrades and vault
|
Scripts/Locations/BaseLocation.cs
| /mail, /trade, /bounty, /auction slash commands with full interactive UI; /auction added to help text
|
Scripts/Locations/ArenaLocation.cs
| Refactored to use shared PlayerCharacterLoader; bounty auto-claim on PvP victory
|
Scripts/Locations/MainStreetLocation.cs
| [7] World Boss menu item; [J] Marketplace re-enabled (routes to Auction House in online mode)
|
Scripts/Locations/CastleLocation.cs
| [B]esiege the Castle team siege with guard combat phases and king challenge; cap monarch history/royal mail
|
Scripts/Locations/DungeonLocation.cs
| RestorePlayerTeammates() — loads player echoes at dungeon entry; cap recurring duelists at 200
|
Scripts/Systems/CombatEngine.cs
| Echo handling: skip XP for echoes, echo death message; class-specific combat tips only shown to relevant class; fixed healing potion tip key |
Scripts/Systems/OnlineChatSystem.cs
| /tell validates recipient exists, shows online/offline status
|
Scripts/Core/GameEngine.cs
| DungeonPartyPlayerNames field; team validation on login; mail/trade counts in While You Were Gone; cap notifications at 100
|
Scripts/Core/Character.cs
| IsEcho property for player echo characters
|
Scripts/Systems/SaveDataStructures.cs
| DungeonPartyPlayerNames in save data
|
Scripts/Systems/SaveSystem.cs
| Serialize/restore DungeonPartyPlayerNames
|
usurper-reloaded.csproj
| GC tuning properties; PublishTrimmed with partial trim mode; removed unused NuGet packages |
runtimeconfig.template.json
| NEW — HeapHardLimit 512MB, Workstation GC config, JSON reflection flag |
Console/Bootstrap/Program.cs
| AppContext.SetSwitch to re-enable JSON reflection at runtime (trimmer override) |
Scripts/Systems/StoryProgressionSystem.cs
| Reduced event log cap from 1000 to 500 |
Scripts/Systems/TelemetrySystem.cs
| Cap re-queued events on flush failure |
Scripts/Systems/WorldSimulator.cs
| Auto-clear cascade rate-limiter every 100 ticks; NPC marketplace uses SQL backend in online mode; enhanced memory-driven behavior with location sentiment; relationship-driven activity weights and movement; world event reactions (war/plague/festival/throne) |
Scripts/Systems/MarketplaceSystem.cs
| EquipOrStoreItem made internal for WorldSimulator NPC purchases
|
Scripts/Systems/WorldSimService.cs
| Passes SqlBackend to WorldSimulator for marketplace operations |
Scripts/Server/WizardLevel.cs
| NEW — WizardLevel enum (Mortal→Implementor) + WizardConstants (titles, colors) |
Scripts/Server/WizNet.cs
| NEW — Wizard-only communication channel (chat, system notifications, action alerts) |
Scripts/Server/WizardCommandSystem.cs
| NEW — 35+ wizard commands across all tiers with command router |
Scripts/Server/PlayerSession.cs
| Wizard state properties, auto-promote Rage, WizNet login/logout, snoop cleanup, freeze/mute flags |
Scripts/Server/SessionContext.cs
| WizardLevel, WizardGodMode, WizardInvisible per-session state |
Scripts/Server/MudServer.cs
| --admin bootstrap writes God-level to DB; removed runtime AdminUsers HashSet
|
Scripts/Server/MudChatSystem.cs
| Wizard command routing before chat; freeze/mute checks; /who shows wizard titles + hides invisible
|
Scripts/Server/RoomRegistry.cs
| Invisible wizard filtering in arrivals/departures/presence lists; wizard titles in room presence |
Scripts/Systems/SqlSaveBackend.cs
| wizard_level column, wizard_log/wizard_flags tables, 7 new query methods
|
Scripts/Systems/CombatEngine.cs
| Wizard godmode: HP/Mana restored after PvE and PvP combat |
Scripts/Core/GameEngine.cs
| Admin console access uses WizardLevel >= God instead of hardcoded username |
MUD Architecture (True Multi-User Dungeon)
The game can now run as a true MUD: a single shared process where all players coexist with instant communication, eliminating the previous one-process-per-SSH-session architecture (~80-120MB per player → one shared process).
How It Works
Start the MUD server:
UsurperReborn --mud-server --db /var/usurper/usurper_online.dbPlayers connect via relay:
# SSH ForceCommand:
UsurperReborn --mud-relay --user "%u" --mud-port 4001Or via web browser (set MUD_MODE=1 in ssh-proxy.js environment).
Key Features
- Single Process: All players share one .NET process. Memory: ~150MB total instead of 120MB per player.
- Session Isolation: Each player gets isolated game state via
AsyncLocal<SessionContext>. AllSomeSystem.Instancecalls resolve to per-session instances without changing ~500 call sites. - Room Presence: "Also here: PlayerX, PlayerY" shown when entering locations. Entry/exit notifications ("PlayerX arrives", "PlayerX leaves toward the Dungeon").
- Instant Chat:
/say(room-scoped),/shout(global),/tell(instant private message),/emote(room-scoped actions). - Combat Visibility: Players in the same room see each other's combat ("PlayerX draws their weapon and attacks Goblin!", "PlayerX defeated the Goblin.").
- In-Process World Sim: World simulator runs as a background task inside the MUD server. No separate
usurper-world.serviceneeded. - Emergency Save: Players are auto-saved on disconnect.
- Web Terminal: Direct TCP mode for web proxy (skip SSH hop, lower latency).
Backward Compatibility
- Single-player mode: Unaffected.
SessionContext.Currentis null, all singletons fall back to static instances. - BBS door mode: Unaffected. Same separate-process-per-BBS behavior.
- Legacy online mode (
--online --stdio): Still works via SSH as before.
Production Hardening
- Session Idle Timeout: Players with no input for 15 minutes are auto-saved and disconnected. Watchdog checks every 60 seconds.
- Admin Commands: Server admins can use
/kick <player>,/shutdown <seconds>,/broadcast <message>, and/adminfor help. Admin status is set via--admin <username>flags on the server command line. - Graceful Shutdown:
/shutdownbroadcasts countdown warnings at decreasing intervals (5m, 2m, 1m, 30s, 10s, 5, 4, 3, 2, 1) before shutting down. - Password Auth for Direct TCP: The AUTH protocol supports
AUTH:username:password:connectionTypefor direct TCP connections (e.g., web proxy in MUD_MODE). Passwords are verified against the SQLite database using PBKDF2. Relay connections (from SSH) remain trusted. - Thread-Safe NPC Access:
NPCSpawnSystem.ActiveNPCsis now protected by aReaderWriterLockSlim. WorldSim writes (add/remove/clear) take write locks; player session reads get cached snapshots. In single-player/BBS mode there's zero overhead (fast-path bypass).
New Command-Line Flags
| Flag | Description |
|---|---|
--mud-server
| Start the TCP game server (MUD mode) |
--mud-relay
| Start thin stdin/stdout ↔ TCP bridge |
--mud-port <port>
| TCP port for MUD server (default: 4001) |
--admin <username>
| Add an admin user (can be repeated) |
MUD Architecture Files
| File | Description |
|---|---|
Scripts/Server/SessionContext.cs
| NEW — AsyncLocal per-session context with all per-player system instances |
Scripts/Server/MudServer.cs
| NEW — TCP listener, connection handler, session lifecycle, idle watchdog, admin commands, graceful shutdown |
Scripts/Server/PlayerSession.cs
| NEW — Per-player session wrapper, system initialization, emergency save, idle tracking, admin flag |
Scripts/Server/RelayClient.cs
| NEW — Thin stdin/stdout ↔ TCP bridge for SSH ForceCommand |
Scripts/Server/RoomRegistry.cs
| NEW — In-memory player location tracking, room-scoped broadcasts |
Scripts/Server/MudChatSystem.cs
| NEW — Instant in-memory chat (/say, /shout, /tell, /emote, /who) + admin commands (/kick, /shutdown, /broadcast) |
Scripts/Systems/StoryProgressionSystem.cs
| Session-aware Instance shim |
Scripts/Systems/CompanionSystem.cs
| Session-aware Instance shim |
Scripts/Systems/*.cs (21+ files)
| Session-aware Instance shim pattern applied to all per-player singletons |
Scripts/UI/TerminalEmulator.cs
| Stream-based I/O constructor for TCP sessions; session-aware Instance |
Scripts/Core/GameEngine.cs
| Session-aware Instance, PendingNotifications, IsIntentionalExit |
Scripts/Systems/LocationManager.cs
| Session-aware Instance; RoomRegistry integration |
Scripts/Locations/BaseLocation.cs
| Room presence display; MUD chat routing; message queue draining |
Scripts/Systems/CombatEngine.cs
| Combat start/end/flee/death room broadcasts |
Scripts/Locations/DungeonLocation.cs
| Dungeon descent room broadcast |
Scripts/Systems/NPCSpawnSystem.cs
| ReaderWriterLockSlim for thread-safe NPC list access; cached snapshot pattern |
Scripts/BBS/DoorMode.cs
| --mud-server, --mud-relay, --mud-port, --admin flags; session-aware GetPlayerName/OnlineUsername |
Console/Bootstrap/Program.cs
| MUD server and relay mode entry points |
web/ssh-proxy.js
| MUD_MODE direct TCP connection option |