forked from sass/tipibot
Document cleanup
This commit is contained in:
@@ -2,37 +2,75 @@
|
||||
|
||||
## File Structure
|
||||
|
||||
The codebase is split into **`core/`** (domain logic), **`commands/`** (Discord slash command handlers), and a thin **`bot.py`** that wires everything together.
|
||||
|
||||
### Top level
|
||||
|
||||
| File | Purpose |
|
||||
|---|---|
|
||||
| `bot.py` | All Discord commands, views (UI components), event handlers, reminder system |
|
||||
| `economy.py` | All economy logic, data model, constants (SHOP, COOLDOWNS, LEVEL_ROLES, etc.) |
|
||||
| `pb_client.py` | Async PocketBase REST client - auth token cache, CRUD on `economy_users` collection |
|
||||
| `bot.py` | Discord client, event handlers (`on_ready`, `on_member_join`, ...), background tasks (presence rotation, daily birthday loop), shared helpers (`_award_exp`, `_maybe_remind`, `_parse_amount`, `_PAUSED`), and `register_*_commands(...)` wiring for every command module |
|
||||
| `strings.py` | **Single source of truth for all user-facing text.** Edit here to change any message. |
|
||||
| `sheets.py` | Google Sheets integration (member sync) |
|
||||
| `member_sync.py` | Birthday/member sync background task |
|
||||
| `config.py` | Environment variables (TOKEN, GUILD_ID, PB_URL, etc.) |
|
||||
| `scripts/migrate_to_pb.py` | One-time utility: migrate `data/economy.json` → PocketBase |
|
||||
|
||||
### `core/` - domain logic, no Discord coupling
|
||||
|
||||
| File | Purpose |
|
||||
|---|---|
|
||||
| `core/economy.py` | All economy business logic (`do_daily`, `do_work`, ...), data model, constants (SHOP, COOLDOWNS, LEVEL_ROLES, EXP_REWARDS, JAIL_DURATION, ...) |
|
||||
| `core/pb_client.py` | Async PocketBase REST client - auth token cache, CRUD on `economy_users` collection |
|
||||
| `core/sheets.py` | Google Sheets integration (member sync) |
|
||||
| `core/member_sync.py` | Birthday/member sync helpers |
|
||||
|
||||
### `commands/` - one slash-command group per file
|
||||
|
||||
Each file exposes a `register_<group>_commands(tree, bot, ...)` function. `bot.py` calls them all once on startup, passing in shared helpers (`coin`, `cd_ts`, `award_exp`, `maybe_remind`, `parse_amount`, ...).
|
||||
|
||||
| File | Commands / Responsibility |
|
||||
|---|---|
|
||||
| `commands/dev_member_commands.py` | `/check`, `/member` (dev profile only) |
|
||||
| `commands/dev_member_runtime.py` | `on_member_join` flow + `birthday_daily` task body |
|
||||
| `commands/economy_income_commands.py` | `/daily`, `/work`, `/beg`, `/crime`, `/rob` |
|
||||
| `commands/economy_games_commands.py` | `/roulette`, `/slots`, `/blackjack`, `/rps` |
|
||||
| `commands/economy_extra_commands.py` | `/heist`, `/jailbreak`, `/reminders`, `/request`, ... |
|
||||
| `commands/economy_fish_commands.py` | `/fish`, `/fishbook`, `/fishsell` |
|
||||
| `commands/economy_profile_commands.py` | `/balance`, `/rank`, `/stats`, `/cooldowns`, `/leaderboard` |
|
||||
| `commands/economy_support_commands.py` | `/shop`, `/buy`, `/give`, `/economysetup` |
|
||||
| `commands/economy_prestige_commands.py` | `/prestige`, `/prestigeshop`, `/prestigebuy` |
|
||||
| `commands/economy_admin_commands.py` | `/admincoins`, `/adminexp`, `/adminitem`, `/adminjail`, `/adminban`, `/adminreset`, `/adminview` |
|
||||
| `commands/ops_admin_commands.py` | `/sync`, `/restart`, `/shutdown`, `/pause`, `/send`, `/status` |
|
||||
| `commands/ops_channel_commands.py` | Channel allowlist commands |
|
||||
| `commands/info_commands.py` | `/patchnotes` and other lightweight info commands |
|
||||
|
||||
### `scripts/`
|
||||
|
||||
| File | Purpose |
|
||||
|---|---|
|
||||
| `scripts/migrate_to_pb.py` | One-time legacy migration: `data/economy.json` → PocketBase. Only relevant if you still have a pre-PB JSON store. |
|
||||
| `scripts/add_stats_fields.py` | Schema migration: adds new fields to the `economy_users` collection. Idempotent. |
|
||||
| `scripts/reset_pb_collections.py` | **Destructive** - deletes and recreates the dev + economy collections. Requires `--confirm`. Use only in dev. |
|
||||
|
||||
---
|
||||
|
||||
## Adding a New Economy Command
|
||||
|
||||
Pick the `commands/economy_*_commands.py` file that matches the new command's category (income, games, profile, ...) and add the handler inside its `register_*_commands` function. If none fit, create a new module and register it from `bot.py`.
|
||||
|
||||
Checklist - do all of these, in order:
|
||||
|
||||
1. **`economy.py`** - add the `do_<cmd>` async function with cooldown check, logic, `_commit`, and `_txn` logging
|
||||
2. **`economy.py`** - add the cooldown to `COOLDOWNS` dict if it has one
|
||||
3. **`economy.py`** - add the EXP reward to `EXP_REWARDS` dict
|
||||
1. **`core/economy.py`** - add the `do_<cmd>` async function with cooldown check, logic, `_commit`, and `_txn` logging
|
||||
2. **`core/economy.py`** - add the cooldown to `COOLDOWNS` dict if it has one
|
||||
3. **`core/economy.py`** - add the EXP reward to `EXP_REWARDS` dict
|
||||
4. **`strings.py` `CMD`** - add the slash command description
|
||||
5. **`strings.py` `OPT`** - add any parameter descriptions
|
||||
6. **`strings.py` `TITLE`** - add embed title(s) for success/fail states
|
||||
7. **`strings.py` `ERR`** - add any error messages (banned, cooldown uses `CD_MSG`, jailed uses `CD_MSG["jailed"]`)
|
||||
8. **`strings.py` `CD_MSG`** - add cooldown message if command has a cooldown
|
||||
9. **`strings.py` `HELP_CATEGORIES["tipibot"]["fields"]`** - add the command to the help embed
|
||||
10. **`bot.py`** - implement the `cmd_<name>` function, handle all `res["reason"]` cases
|
||||
11. **`bot.py`** - call `_maybe_remind` if the command has a cooldown and reminders make sense
|
||||
12. **`bot.py`** - call `_award_exp(interaction, economy.EXP_REWARDS["<cmd>"])` on success
|
||||
10. **`commands/economy_<group>_commands.py`** - inside `register_*_commands`, add `@tree.command(name="<cmd>", ...)` `cmd_<name>`; handle all `res["reason"]` cases
|
||||
11. **`commands/economy_<group>_commands.py`** - call `maybe_remind(user_id, "<cmd>")` if the command has a cooldown and reminders make sense (the helper is passed in via the `register_*` signature)
|
||||
12. **`commands/economy_<group>_commands.py`** - call `await award_exp(interaction, economy.EXP_REWARDS["<cmd>"])` on success
|
||||
13. **`strings.py` `REMINDER_OPTS`** - add a reminder option if the command needs one
|
||||
14. **`bot.py` `_maybe_remind`** - if the command has an item-modified cooldown, add an `elif` branch
|
||||
14. **`bot.py` `_maybe_remind`** - if the command has an item-modified cooldown, add an `elif` branch (this helper still lives in `bot.py` and is shared across all command modules)
|
||||
|
||||
---
|
||||
|
||||
@@ -40,21 +78,21 @@ Checklist - do all of these, in order:
|
||||
|
||||
Checklist:
|
||||
|
||||
1. **`economy.py` `SHOP`** - add the item dict `{name, emoji, cost, description: strings.ITEM_DESCRIPTIONS["key"]}`
|
||||
2. **`economy.py` `SHOP_TIERS`** - add the key to the correct tier list (1/2/3)
|
||||
3. **`economy.py` `SHOP_LEVEL_REQ`** - add minimum level if it is T2 (≥10) or T3 (≥20)
|
||||
1. **`core/economy.py` `SHOP`** - add the item dict `{name, emoji, cost, description: strings.ITEM_DESCRIPTIONS["key"]}`
|
||||
2. **`core/economy.py` `SHOP_TIERS`** - add the key to the correct tier list (1/2/3)
|
||||
3. **`core/economy.py` `SHOP_LEVEL_REQ`** - add minimum level if it is T2 (≥10) or T3 (≥20)
|
||||
4. **`strings.py` `ITEM_DESCRIPTIONS`** - add the item description (Estonian flavour + English effect)
|
||||
5. **`strings.py` `HELP_CATEGORIES["shop"]["fields"]`** - add display entry (sorted by cost)
|
||||
6. If the item modifies a cooldown:
|
||||
- **`economy.py`** - add the `if "item" in user["items"]` branch in the relevant `do_<cmd>` function
|
||||
- **`core/economy.py`** - add the `if "item" in user["items"]` branch in the relevant `do_<cmd>` function
|
||||
- **`bot.py` `_maybe_remind`** - add `elif cmd == "<cmd>" and "<item>" in items:` branch with the new delay
|
||||
- **`bot.py` `cmd_cooldowns`** - add the item annotation to the relevant status line
|
||||
- **`commands/economy_profile_commands.py` `cmd_cooldowns`** - add the item annotation to the relevant status line
|
||||
|
||||
---
|
||||
|
||||
## Adding a New Level Role
|
||||
|
||||
1. **`economy.py` `LEVEL_ROLES`** - add `(min_level, "RoleName")` in descending level order (highest first)
|
||||
1. **`core/economy.py` `LEVEL_ROLES`** - add `(min_level, "RoleName")` in descending level order (highest first)
|
||||
2. **`bot.py` `_ensure_level_role`** - no changes needed (uses `LEVEL_ROLES` dynamically)
|
||||
3. Run **`/economysetup`** in the server to create the role and set its position
|
||||
|
||||
@@ -64,7 +102,7 @@ Checklist:
|
||||
|
||||
1. **`strings.py` `CMD`** - add `"[Admin] ..."` description
|
||||
2. **`strings.py` `HELP_CATEGORIES["admin"]["fields"]`** - add the entry
|
||||
3. **`bot.py`** - add `@app_commands.default_permissions(manage_guild=True)` and `@app_commands.guild_only()`
|
||||
3. **`commands/economy_admin_commands.py`** (or `commands/ops_admin_commands.py` for non-economy ops) - add the handler with `@app_commands.default_permissions(manage_guild=True)` and `@app_commands.guild_only()`
|
||||
|
||||
---
|
||||
|
||||
@@ -72,7 +110,7 @@ Checklist:
|
||||
|
||||
### Storage
|
||||
|
||||
All economy state is stored in **PocketBase** (`economy_users` collection). `pb_client.py` owns all reads/writes. Each `do_*` function in `economy.py` calls `get_user()` → mutates the local dict → calls `_commit()`. `_commit` does a `PATCH` to PocketBase.
|
||||
All economy state is stored in **PocketBase** (`economy_users` collection). `core/pb_client.py` owns all reads/writes. Each `do_*` function in `core/economy.py` calls `get_user()` → mutates the local dict → calls `_commit()`. `_commit` does a `PATCH` to PocketBase.
|
||||
|
||||
### Currency & Income Sources
|
||||
|
||||
@@ -103,8 +141,10 @@ Commands that accept a coin amount (`/give`, `/roulette`, `/rps`, `/slots`, `/bl
|
||||
- `/jailbreak`: 3 dice rolls, need doubles to escape free. On fail - bail = 20-30% of balance, min 350⬡. If balance < 350⬡, player stays jailed until timer.
|
||||
- **Blocked while jailed**: `/work`, `/beg`, `/crime`, `/rob`, `/give` (checked in `do_*` functions via `_is_jailed`)
|
||||
|
||||
### EXP Rewards (from `EXP_REWARDS` in economy.py)
|
||||
EXP is awarded on every successful command use. Level formula: `floor(sqrt(exp / 10))`, so Level 5 = 250 EXP, Level 10 = 1000, Level 20 = 4000, Level 30 = 9000.
|
||||
### EXP Rewards (from `EXP_REWARDS` in `core/economy.py`)
|
||||
EXP is awarded on every successful command use. Level formula: `level = max(1, floor(sqrt(exp / 6)))` (see `get_level` / `exp_for_level`). Thresholds: Level 5 = 150 EXP, Level 10 = 600, Level 20 = 2 400, Level 30 = 5 400.
|
||||
|
||||
Gambling EXP is bet-scaled via `gamble_exp(bet)`; fish EXP is per-species in `FISH` (common 2–3, uncommon 6–7, rare 10, epic 14–15, legendary 25).
|
||||
|
||||
---
|
||||
|
||||
@@ -139,27 +179,30 @@ Role assignment:
|
||||
| T3 | 20 | monitor_360, karikas, gaming_tool |
|
||||
|
||||
Shop display is sorted by cost (ascending) within each tier.
|
||||
The `SHOP_LEVEL_REQ` dict in `economy.py` controls per-item lock thresholds.
|
||||
The `SHOP_LEVEL_REQ` dict in `core/economy.py` controls per-item lock thresholds.
|
||||
|
||||
---
|
||||
|
||||
## strings.py Organisation
|
||||
|
||||
| Section | Dict | Usage in bot.py |
|
||||
Imported as `import strings as S` everywhere. Dicts are read from `bot.py` and from every `commands/*.py` module.
|
||||
|
||||
| Section | Dict | Typical usage |
|
||||
|---|---|---|
|
||||
| Flavour text | `WORK_JOBS`, `BEG_LINES`, `CRIME_WIN`, `CRIME_LOSE` | Randomised descriptions |
|
||||
| Command descriptions | `CMD["key"]` | `@tree.command(description=S.CMD["key"])` |
|
||||
| Parameter descriptions | `OPT["key"]` | `@app_commands.describe(param=S.OPT["key"])` |
|
||||
| Help embed | `HELP_CATEGORIES["cat"]` | `cmd_help` |
|
||||
| Help embed | `HELP_CATEGORIES["cat"]` | `cmd_help` (in `bot.py`) |
|
||||
| Banned message | `MSG_BANNED` | All banned checks |
|
||||
| Maintenance mode | `MSG_MAINTENANCE` | Shown when `_PAUSED=True` in bot.py (toggled by `/pause`) |
|
||||
| Maintenance mode | `MSG_MAINTENANCE` | Shown when `_PAUSED=True` in `bot.py` (toggled by `/pause` in `commands/ops_admin_commands.py`) |
|
||||
| Reminder options | `REMINDER_OPTS` | `RemindersSelect` dropdown |
|
||||
| Slots outcomes | `SLOTS_TIERS["tier"]` → `(title, color)` | `cmd_slots` |
|
||||
| Slots outcomes | `SLOTS_TIERS["tier"]` → `(title, color)` | `cmd_slots` (in `commands/economy_games_commands.py`) |
|
||||
| Embed titles | `TITLE["key"]` | `discord.Embed(title=S.TITLE["key"])` |
|
||||
| Error messages | `ERR["key"]` | `send_message(S.ERR["key"])` - use `.format(**kwargs)` for dynamic parts |
|
||||
| Cooldown messages | `CD_MSG["cmd"].format(ts=_cd_ts(...))` | Cooldown responses |
|
||||
| Shop UI | `SHOP_UI["key"]` | `_shop_embed` |
|
||||
| Item descriptions | `ITEM_DESCRIPTIONS["item_key"]` | `economy.SHOP[key]["description"]` |
|
||||
| Cooldown messages | `CD_MSG["cmd"].format(ts=cd_ts(...))` | Cooldown responses (`cd_ts` helper passed in by `bot.py`) |
|
||||
| Shop UI | `SHOP_UI["key"]` | `_shop_embed` (in `commands/economy_support_commands.py`) |
|
||||
| Item descriptions | `ITEM_DESCRIPTIONS["item_key"]` | `core/economy.py` `SHOP[key]["description"]` |
|
||||
| Patch notes UI | `PATCHNOTES_UI["key"]` | `commands/info_commands.py` (`/patchnotes`) |
|
||||
|
||||
---
|
||||
|
||||
@@ -167,17 +210,18 @@ The `SHOP_LEVEL_REQ` dict in `economy.py` controls per-item lock thresholds.
|
||||
|
||||
| Constant | File | Description |
|
||||
|---|---|---|
|
||||
| `SHOP` | `economy.py` | All shop items (name, emoji, cost, description) |
|
||||
| `SHOP_TIERS` | `economy.py` | Which items are in T1/T2/T3 |
|
||||
| `SHOP_LEVEL_REQ` | `economy.py` | Min level per item |
|
||||
| `COOLDOWNS` | `economy.py` | Base cooldown per command |
|
||||
| `JAIL_DURATION` | `economy.py` | How long jail lasts |
|
||||
| `LEVEL_ROLES` | `economy.py` | `[(min_level, "RoleName"), ...]` highest first |
|
||||
| `ECONOMY_ROLE` | `economy.py` | Name of the base economy participation role |
|
||||
| `EXP_REWARDS` | `economy.py` | EXP per command |
|
||||
| `HOUSE_ID` | `economy.py` | Bot's user ID (house account for /rob) |
|
||||
| `MIN_BAIL` | `economy.py` | Minimum bail payment (350⬡) |
|
||||
| `COIN` | `economy.py` | The coin emoji string |
|
||||
| `SHOP` | `core/economy.py` | All shop items (name, emoji, cost, description) |
|
||||
| `SHOP_TIERS` | `core/economy.py` | Which items are in T1/T2/T3 |
|
||||
| `SHOP_LEVEL_REQ` | `core/economy.py` | Min level per item |
|
||||
| `COOLDOWNS` | `core/economy.py` | Base cooldown per command |
|
||||
| `JAIL_DURATION` | `core/economy.py` | How long jail lasts |
|
||||
| `LEVEL_ROLES` | `core/economy.py` | `[(min_level, "RoleName"), ...]` highest first |
|
||||
| `ECONOMY_ROLE` | `core/economy.py` | Name of the base economy participation role |
|
||||
| `EXP_REWARDS` | `core/economy.py` | EXP per command |
|
||||
| `FISH` | `core/economy.py` | Fish species table (rarity, weight, coins, exp) |
|
||||
| `HOUSE_ID` | `core/economy.py` | Bot's user ID (house account for /rob) |
|
||||
| `MIN_BAIL` | `core/economy.py` | Minimum bail payment (350⬡) |
|
||||
| `COIN` | `core/economy.py` | The coin emoji string |
|
||||
| `_PAUSED` | `bot.py` | In-memory maintenance flag; toggled by `/pause`; blocks all non-admin commands |
|
||||
|
||||
---
|
||||
|
||||
Reference in New Issue
Block a user