|
| 1 | +This repository is a small Discord bot that fetches Old School RuneScape Grand Exchange prices |
| 2 | +and computes simple profit estimates for herb farming and fish cooking. The instructions below |
| 3 | +give concise, practical guidance so an AI coding assistant can be immediately productive. |
| 4 | + |
| 5 | +Core architecture (big picture) |
| 6 | +- Entrypoint: `run.py` — async main that loads command extensions and starts the bot. |
| 7 | +- Bot shell: `bot/bot.py` — defines `MyBot` and global setup (prefix, intents, sync). |
| 8 | +- Commands: `bot/commands/*.py` — each command is a Cog using discord.py app_commands; examples: |
| 9 | + - `bot/commands/herb_profit.py` (interactive form + uses `bot.utils.calculations`) |
| 10 | + - `bot/commands/fish_profit.py` (uses `bot.utils.api`, formats results via `discord.ui.View`) |
| 11 | +- Utilities: `bot/utils/*.py` — API fetching (`api.py`), calculation & domain logic (`calculations.py`), helpers (`helpers.py`). |
| 12 | +- Data: `data/items.py` — canonical mapping of item ids (seed_id, herb_id, raw/cooked ids) used by commands. |
| 13 | +- Config: `config/config.yaml` + `config/settings.py` — load headers, intents, debug flag and BOT_PREFIX. |
| 14 | + |
| 15 | +Why things are structured this way |
| 16 | +- Commands are implemented as Cogs and loaded as extensions to keep the bot core minimal and make new features pluggable. |
| 17 | +- Price fetching is centralized in `bot/utils/api.py` so commands use a single source of truth for price shape (the wiki API returns dicts keyed by item id strings). |
| 18 | +- Calculation logic is intentionally separated to `calculations.py` so it can be reused/tested independently from Discord I/O. |
| 19 | + |
| 20 | +Developer workflows and commands |
| 21 | +- Run locally (requires Python and `.env` with `DISCORD_BOT_TOKEN`): |
| 22 | + - Install deps: `pip install -r requirements.txt` |
| 23 | + - Start: `python run.py` (this calls `bot.setup_hook()` and starts the bot) |
| 24 | +- Docker: `docker-compose up --build` (project includes Dockerfile / docker-compose.yml) |
| 25 | +- Configuration: edit `config/config.yaml` for `HEADERS`, `bot_prefix`, `intents`, `debug`. |
| 26 | +- Debugging: set `debug: true` in `config/config.yaml` — code prints intermediate price and calculation values (see `calculations.py` and `herb_profit.py`). |
| 27 | + |
| 28 | +Project-specific conventions & patterns |
| 29 | +- Price dict shape: API returns data keyed by item id strings. Commands convert ints to strings before lookup, e.g. `prices[str(item_id)]["high"]` or `"avgHighPrice"` for 1h averages. |
| 30 | +- Price type selection: commands accept `price_type` choices (`latest` => `high`, `1h` => `avgHighPrice`) — follow this mapping when adding features. |
| 31 | +- Views & formatting: interactive responses use `discord.ui.View` with a select menu to choose output format (`markdown` or `embed`). Keep UI code in the command module and call shared calc functions. |
| 32 | +- Tests: minimal tests exist under `tests/` (currently a placeholder). Keep calculation logic pure and add unit tests for functions in `bot/utils/calculations.py` and `bot/utils/helpers.py`. |
| 33 | + |
| 34 | +Integration points & external dependencies |
| 35 | +- External API: https://prices.runescape.wiki/api/v1/osrs/latest and `/1h`. `bot/utils/api.py` sets `HEADERS` from `config/config.yaml` to satisfy the wiki's user-agent requirement. |
| 36 | +- Environment: `DISCORD_BOT_TOKEN` must be present in `.env` for local runs or in the container environment for Docker. |
| 37 | +- Libraries: `discord.py`, `requests`, `pandas` (used for tabular formatting in commands), `python-dotenv`, `pyyaml`. |
| 38 | + |
| 39 | +Concrete examples & actionable tips for code edits |
| 40 | +- Adding a new command: create `bot/commands/<name>.py`, implement a Cog with an `@app_commands.command`, call shared functions in `bot/utils/*`, and add an async `setup(bot)` that adds the cog. |
| 41 | +- Fetch prices once per command invocation: call `fetch_latest_prices()` or `fetch_1h_prices()` in the command handler and pass the resulting dict (not individual ids) into calculation helpers. |
| 42 | +- Respect price_key mapping: use `price_key = "high"` for `latest`, `price_key = "avgHighPrice"` for `1h` and access prices as `prices[str(item_id)][price_key]`. |
| 43 | +- Avoid network in unit tests: mock `bot.utils.api.fetch_latest_prices()` and `fetch_1h_prices()`; test `calculate_custom_profit()` purely with synthetic price dicts. |
| 44 | + |
| 45 | +Files to inspect first when debugging or extending |
| 46 | +- `run.py`, `bot/bot.py`, `bot/commands/herb_profit.py`, `bot/commands/fish_profit.py`, `bot/utils/api.py`, `bot/utils/calculations.py`, `data/items.py`, `config/config.yaml`. |
| 47 | + |
| 48 | +When in doubt, preserve these invariants |
| 49 | +- Price data passed around should remain the original API data shape (dict keyed by id strings). |
| 50 | +- Calculation helpers must not perform I/O; keep side-effects (sending messages, creating views) inside command modules. |
| 51 | + |
| 52 | +If anything here is unclear or you want examples for a specific change (new command, test, or CI step), tell me which area to expand. |
0 commit comments