diff --git a/README.md b/README.md index 32ddd6e..2c43afd 100644 --- a/README.md +++ b/README.md @@ -1,120 +1,226 @@ -# mtga-assistant +
+
+
+ A deck and game tracker for Magic: The Gathering Arena on Linux and Windows. +
-- **Match**, from top to bottom (drag the dividers to resize; sizes are remembered): - - *You · Match · Opponent*: life totals, poison/energy and other player counters, commanders, - emblems, hand/library/graveyard counts, turn timer and timeouts, land drops used/allowed, who - was on the play, plus the match panel (turn, phase, game number, Bo3 score and draw count, - game time). - - *You · Turn · Opponent*: each player's stats for the selected turn and the whole game - (cards drawn, spells cast, lands played, creatures died, life gained/lost, damage, discards, - mills, exiles, counters, tokens, land drops). The two sides mirror each other, with the - whole-game column next to the middle panel, which picks the turn (◀ ▶, or *Live* to follow - the current one). - - *My deck · Opponent · Preview*: remaining library with draw odds, your zones; the opponent's - board, graveyard, exile, cards known to be in their hand or library, and every card seen this - match; hover a card for its [Scryfall](https://scryfall.com) image. -- **History**: stats (win rate overall, last 10/100 games, last 7 days, on the play/draw, average - length and turns) and a sortable list of every finished game: date, event, deck, commanders, - opponent, both decks' colours, who was on the play, result, turns and length. Click a header to - sort, right-click a cell to show only (or hide) games with that value; the stats follow the - filters. Click a game to open it in the Match view ("Back to live" returns). Games from the - previous MTGA session (`Player-prev.log`) are imported on startup. +MTGA Assistant follows MTGA's `Player.log`, as Untapped.gg and other trackers do. It shows your +library with draw odds, everything revealed about your opponent, per-turn stats, and a filterable +history of every game you play. It runs natively on Linux (MTGA through Steam/Proton) and on +Windows (Steam, Epic or the standalone installer). -*⚙ Customize* shows or hides each panel of the Match page (You, Match, Opponent, Turn stats, -My deck, Preview, Opponent's cards) and the details in the player panels. *Customize → Arrange…* -reorders (drag, or ↑/↓) and shows/hides the My deck and Opponent sections and the turn stats. -Your choices are remembered. +## Screenshots + +**Match**: both players, the match, per-turn stats, your deck, a card preview and everything known +about the opponent. + + + +**A past game** opened from History, with "Back to live" to return. + + + +**History**: stats and every finished game; sort by any column. + + + +**Filtered history**: right-click any value to filter; the stats follow the filter. + + + +**Customization**: reorder and show/hide deck sections and turn stats. + + + +## Features + +### Match + +Three rows; drag the dividers to resize them (sizes are remembered). + +- **You · Match · Opponent**: life totals, poison/energy and other player counters, commanders + (with location and commander tax), emblems, hand/library/graveyard/exile counts, turn timer and + timeouts used, land drops used/allowed (e.g. `0/2` with extra land effects), who was on the play, + plus the match panel: turn, phase, game number, Bo3 score, who has been on the draw more, and + game time. +- **You · Turn · Opponent**: each player's stats for the selected turn and the whole game: cards + drawn, spells cast, lands played, creatures died, life gained/lost, damage, discards, mills, + exiles, spells countered, tokens, counters and land drops. The middle panel picks the turn + (◀ ▶, or *Live* to follow the current one). +- **My deck · Preview · Opponent**: + - *My deck*: the remaining library with draw odds, and your hand, stack, battlefield, graveyard, + exile and sideboard. Counts show copies in that zone against copies in the deck (`2/5`). + - *Opponent*: their battlefield, stack, graveyard and exile, cards known to be in their hand or + library (seen going back there, or revealed), and every card seen this match. + - *Preview*: hover a card to see its [Scryfall](https://scryfall.com) image. Clear it with ✕, + a click on the image, or Esc. Card names, mana costs and types come from MTGA's own local card database, so they work offline. +### History + +Every finished game is recorded with its date, event, deck, commanders, opponent, both decks' +colours, who was on the play, the result, turns and length. Above the list are your win rate +overall, for the last 10 and 100 games, for the last 7 days, and on the play and on the draw, +plus average game length and turns. + +- **Sort**: click a column header; click again to reverse. +- **Filter**: right-click a cell to show only (or hide) games with that value, such as a deck, + commander, event, opponent's colours or play/draw. Filters combine, appear as removable chips, + and the stats follow them. +- **Open a game**: click it to view it in the Match page as it ended, including turn-by-turn + stats. *Back to live* returns to the current game. +- Columns can be resized; games from the previous MTGA session (`Player-prev.log`) are imported + on startup. + +### Customization + +- **⚙ Customize**: show or hide each panel of the Match page (You, Match, Opponent, Turn stats, + My deck, Preview, Opponent's cards) and the details in the player panels. The menu stays open + while you tick and untick. +- **Customize → Arrange deck sections and turn stats…**: reorder (drag, or ↑/↓) and show/hide the + My deck and Opponent sections and the turn stats. + +All choices are remembered. + +### Runs in the background + +So that no game is missed, closing the window keeps the app running in the system tray (on +Hyprland, Waybar's tray) and recording history. Quit from the tray menu, *☰ → Quit*, or Ctrl+Q. + +- **Opens when MTGA starts**: the app watches MTGA's log folder using OS file notifications + (inotify on Linux, ReadDirectoryChangesW on Windows) rather than polling. When MTGA launches it + starts a fresh `Player.log`, and the window pops up. This works for Steam, Epic and standalone + installs. +- **One instance**: starting the app again shows the running copy instead of opening a second + one. +- **Start at login**: *☰ → Start at login (in the background)*. The installers can also set this + up. + +Both behaviours can be switched off in the ☰ menu. + ## Requirements -Runs on **Linux** and **Windows**. - -- **Detailed logs enabled** in MTGA: *Options → Account → Detailed Logs (Plugin Support)*. -- MTGA's log, install folder and card database are auto-detected: - - Linux: MTGA through Steam (Proton), found via your Steam library folders. - - Windows: Steam, Epic Games or the standalone Wizards installer. The log is always in +- **Detailed logs enabled in MTGA**: *Options → Account → Detailed Logs (Plugin Support)*. +- **Python 3.12 or newer.** The installers check for it and offer to install it. +- MTGA's log, install folder and card database are found automatically: + - **Linux**: MTGA through Steam (Proton), found via your Steam library folders. + - **Windows**: Steam, Epic Games or the standalone installer. The log is always in `%USERPROFILE%\AppData\LocalLow\Wizards Of The Coast\MTGA\Player.log`. -- To run from source: [uv](https://docs.astral.sh/uv/) (`pacman -S uv` on Arch; - `winget install astral-sh.uv` on Windows). -## Running +## Installation -From source (any OS): +### Linux ```sh -uv run mtga-assistant # follow the live Player.log -uv run mtga-assistant --replay path/to/Player-prev.log --rate 40 # replay a saved log -uv run pytest # tests +./install.sh ``` -On Windows you can instead use the packaged build: unzip `MTGA-Assistant-windows.zip` and run -`MTGA Assistant.exe`. +The installer: -Start it before or after MTGA: on startup it reads the existing log to catch up on a match in -progress, then follows new lines. When MTGA restarts and replaces the log, the tracker resets. +1. Checks for Python 3.12+, offering your distro's install command (pacman, apt, dnf or zypper) + if it's missing. +2. Installs the app and its dependencies into `~/.local/share/mtga-assistant/app`. No root is + needed. +3. Checks that Qt can start, and suggests the missing system packages if it can't. +4. Installs the icon and a launcher, `~/.local/share/applications/mtga-assistant.desktop`, which + starts the app with `--background`. +5. Asks whether to start the app at login, then launches it. -### Linux desktop integration +Run `./install.sh` again after pulling to update. `./install.sh --uninstall` removes the app and +keeps your history and settings, and `--yes` answers every question with yes. -On Wayland the window's app id is `mtga-assistant`. For example, to keep it floating on another -workspace in Hyprland: +### Windows + +1. Download this project (on the repository page: *Download ZIP*) and extract it. +2. Double-click **`install.bat`**. + +The installer checks for Python 3.12+ (offering to install it with winget), installs the +dependencies into a private build folder, builds the app with PyInstaller, and installs it to +`%LOCALAPPDATA%\Programs\MTGA Assistant` with Start Menu and Desktop shortcuts. No admin rights are +needed. It asks whether to start the app at login, then launches it. + +Run `install.bat` again to update after downloading a newer version. `install.bat -Uninstall` +removes the app and keeps your history and settings. + +## Usage + +Start the app before or after MTGA. On startup it reads the existing log to catch up on a match in +progress, then follows new lines. When MTGA restarts, the tracker resets for the new session. + +| Shortcut | Action | +|---|---| +| Ctrl+1 / Ctrl+2 | Match / History | +| Esc | Clear the card preview | +| Ctrl+Q | Quit (closing the window only hides it) | + +Command-line options: `--background` (start hidden), `--log PATH` and `--mtga-dir PATH` (override +auto-detection), `--replay PATH [--rate N]` (replay a saved log, for testing). + +**Hyprland**: the window's app id is `mtga-assistant`. For example, to keep it floating on another +workspace: ``` windowrule = float, class:^(mtga-assistant)$ windowrule = workspace 2, class:^(mtga-assistant)$ ``` -### Building the Windows app - -PyInstaller can't cross-compile, so build on Windows (with uv installed): - -```powershell -powershell -ExecutionPolicy Bypass -File packaging\build_windows.ps1 -``` - -This produces `dist\MTGA Assistant\MTGA Assistant.exe` and `dist\MTGA-Assistant-windows.zip`. -The same spec builds a Linux bundle when run on Linux -(`uv run --group build pyinstaller packaging/mtga-assistant.spec`). After editing -`assets/icon.svg`, regenerate the icons with `uv run python packaging/make_icon.py`. - ## Configuration -Optional `config.toml`: - -| | Config file | History | Image cache | -|---|---|---|---| -| Linux | `~/.config/mtga-assistant/config.toml` | `~/.local/share/mtga-assistant/` | `~/.cache/mtga-assistant/` | -| Windows | `%APPDATA%\mtga-assistant\config.toml` | `%LOCALAPPDATA%\mtga-assistant\` | `%LOCALAPPDATA%\mtga-assistant\Cache\` | +Settings made in the app are saved automatically. An optional `config.toml` overrides +auto-detection and limits: ```toml log_path = "/path/to/Player.log" # override auto-detection mtga_dir = "/path/to/MTGA" # the folder containing MTGA_Data -cache_max_mb = 500 # image cache cap +cache_max_mb = 500 # card image cache cap history_max_mb = 300 # cap for stored game details (summaries are always kept) ``` -Game history is stored in `history.db` (roughly 20–100 KB per game). On Windows the app reads a -private copy of MTGA's card database (kept in the cache folder, about 260 MB) so that MTGA's -updater is never blocked by the app holding the file open. +| | Config file | History | Card image cache | +|---|---|---|---| +| Linux | `~/.config/mtga-assistant/config.toml` | `~/.local/share/mtga-assistant/history.db` | `~/.cache/mtga-assistant/images/` | +| Windows | `%APPDATA%\mtga-assistant\config.toml` | `%LOCALAPPDATA%\mtga-assistant\history.db` | `%LOCALAPPDATA%\mtga-assistant\Cache\images\` | -## Image cache +- **Card images** are downloaded from Scryfall only for cards that actually appear (about + 60–100 KB each). When the cache passes `cache_max_mb`, the least recently viewed images are + deleted. *☰ → Clear image cache* empties it. +- **History** takes roughly 20–100 KB per game. Past `history_max_mb`, the oldest games keep + their row in the list but can no longer be opened. +- **On Windows** the app reads a private copy of MTGA's card database (about 260 MB, in the cache + folder), so MTGA's updater is never blocked by the app holding the file open. -Images are downloaded only for cards that actually appear, at Scryfall's `normal` size (about -60–100 KB each), and stored in `~/.cache/mtga-assistant/images`. When the cache passes -`cache_max_mb`, the least recently viewed images are deleted. *Cache → Clear image cache* empties it. +## Development + +```sh +uv run mtga-assistant # run from the source tree +uv run mtga-assistant --replay path/to/Player-prev.log --rate 40 +uv run pytest # tests +``` + +- **Windows build without installing**: on Windows with [uv](https://docs.astral.sh/uv/), + `powershell -ExecutionPolicy Bypass -File packaging\build_windows.ps1` produces + `dist\MTGA Assistant\MTGA Assistant.exe` and `dist\MTGA-Assistant-windows.zip`. PyInstaller + can't cross-compile, so this must run on Windows. On Linux, the same spec + (`uv run --group build pyinstaller packaging/mtga-assistant.spec`) builds a Linux bundle. +- **Icon**: the app icon comes from `images/mtga-assistant-icon.png`. After changing it, run + `uv run python packaging/make_icon.py` to regenerate the Windows `.ico` and the copy bundled + with the app. ## Known limitations -- MTGA leaves oversized game-state messages out of the log ("Message summarized because one or - more GameStateMessages exceeded the 50 GameObject or 50 Annotation limit"), typically during board - wipes. Some zones can then be stale until they next change. The app detects this and shows a - warning. -- After a library shuffle, a known card's position in the opponent's library is lost. It stays listed - under "Library … known" until it shows up again. If it is drawn without being revealed, it may - stay listed. +- **Gaps in the log**: MTGA leaves oversized game-state messages out of the log ("Message + summarized because one or more GameStateMessages exceeded the 50 GameObject or 50 Annotation + limit"), typically during board wipes. Later messages usually fill the gap in. If some of your + cards stay unaccounted for, the status bar shows "⚠ N of your cards not tracked" and library + odds may be slightly off. +- **Shuffled cards**: after a library shuffle, a known card's position in the opponent's library + is lost. It stays listed under "Library … known" until it shows up again, so if it's drawn + without being revealed it may stay listed. +- **Inferred land drops**: the log doesn't say how many land plays are allowed. They're inferred + from "additional land" effects in play, so conditional effects (e.g. "as long as you control an + Elf") are always counted. diff --git a/images/screenshots/1-matchScreen.jpg b/images/screenshots/1-matchScreen.jpg new file mode 100644 index 0000000..154a418 Binary files /dev/null and b/images/screenshots/1-matchScreen.jpg differ diff --git a/images/screenshots/2-previousMatchScreen.jpg b/images/screenshots/2-previousMatchScreen.jpg new file mode 100644 index 0000000..cbeaa65 Binary files /dev/null and b/images/screenshots/2-previousMatchScreen.jpg differ diff --git a/images/screenshots/3-historyScreen.jpg b/images/screenshots/3-historyScreen.jpg new file mode 100644 index 0000000..30ec57a Binary files /dev/null and b/images/screenshots/3-historyScreen.jpg differ diff --git a/images/screenshots/4-historyScreenFiltered.jpg b/images/screenshots/4-historyScreenFiltered.jpg new file mode 100644 index 0000000..a4434c4 Binary files /dev/null and b/images/screenshots/4-historyScreenFiltered.jpg differ diff --git a/images/screenshots/5-customization.jpg b/images/screenshots/5-customization.jpg new file mode 100644 index 0000000..2a5a81e Binary files /dev/null and b/images/screenshots/5-customization.jpg differ diff --git a/pyproject.toml b/pyproject.toml index 43ba51d..19e0d50 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,7 @@ [project] name = "mtga-assistant" version = "0.1.0" -description = "Native Linux deck and game tracker for MTG Arena, driven by Player.log" +description = "Deck and game tracker for MTG Arena on Linux and Windows, driven by Player.log" readme = "README.md" requires-python = ">=3.12" dependencies = [