Building a Bot
The package is framework-agnostic, so a chat bot imports the same catalogs and formulas a website does and both answer a player identically. The Run Tracker ships three Discord bots built this way.
Share The Calculation Layer
Parsing, normalization, cost math and run shapes belong in a package both the bot and your UI import. Platform code — embeds, components, modals, collectors — stays in the bot. That keeps one answer per question regardless of where a player asks it.
Interaction Conventions
These apply to any platform built on callbacks carrying opaque ids — Discord, Slack, Telegram, Matrix.
- One router. Every interaction dispatches through a single entry point, with persistent handlers registered against it.
- Component ids get one owner. Build and parse them in a single module and let handlers consume parsed values. An id is a wire format: it is serialized, handed to a remote client, and handed back later — possibly after a redeploy. Registry lookup uses exact or longest-prefix matching.
- Interactions are owned. Wait on a modal by filtering on the component id and the initiating user, so one user's click resolves only their own pending wait.
- Guard tokens before touching state. Callbacks arrive late, twice, and after restarts. Check a session token is present and unexpired first.
- Support every component kind up front. Buttons, all select-menu variants, and modals, even when the current feature uses one.
- Return quietly when the interaction is not yours. Submissions belonging to a command-local ownership flow should exit silently so real failures stay visible in logs.
- Keep diagnostic scripts. Check them into the repo — you will want them during an incident.
Save-driven Features
Run import, progress tracking and account summaries all start from playerInfo.dat.
Decode once and share the parsed root across handlers rather than re-decoding per interaction. Save File Docs →