🇬🇧 English below · 🇧🇷 Português mais abaixo
Pulls your Deep Rock Galactic stats straight from the raw binary save file, keeps a history in a local SQLite database, and shows everything in an interactive dashboard — kills per enemy species, progress over time, and overclock completion. Captures automatically while you play. Rock and Stone! ⛏️
A project that walks the full arc of a real data job: Extract (reverse-engineering a binary save) → Transform/Load (an ETL into SQLite) → Visualize (a dashboard). The game stores these stats but only shows one at a time, with no history and no charts. This fixes that.
- 🐛 Kills per species — a ranking of the 77 bestiary species, straight from the save.
- 📈 Progress over time — kills, credits, rank and playtime across days.
- ⚙️ Overclock progress — how many you've forged per weapon (e.g.
100/160), the exact list of what's missing, and how many you forged since the previous snapshot. - 🆕 "Since last snapshot" — what grew from one day to the next.
- 📸 Automatic capture — a "watcher" takes a snapshot on its own while you play (mission start / end / game close), no terminal needed.
- 🗂️ Table + CSV export — search by species and download the data.
The ⚙️ Overclocks tab — completion per weapon and exactly what's left to forge.
game save translate bytes store history show it nicely
(XXXXX_Player.sav) -> drg_save_parser.py -> snapshot.py -> dashboard.py
│ │ │ │
│ │ drg_stats.db <──────────────-┘
│ │ (SQLite database) (reads the db)
│ guids.json / ▲
│ all_drg_enemies.json │
└──────────────────────────────────── watcher.py (snapshots on its own while you play)
drg_save_parser.pyreads the binary save (no external dependencies).snapshot.pyuses the parser to take a "snapshot" and store it (one per day).watcher.pywatches the save and calls the snapshot on its own while you play.dashboard.pyreads the database (and the save, for overclocks) and draws the charts.guids.json/all_drg_enemies.jsontranslate the internal codes (GUIDs) into names.
Requirement: Python 3.10+ installed (tick "Add Python to PATH" in the Windows installer).
# 1. Clone the repository
git clone https://github.com/gilas-byte/drg-stats-tracker.git
cd drg-stats-tracker
# 2. Take the first snapshot (finds the save on its own and creates the database)
python snapshot.py
# 3. Open the dashboard
# Windows: double-click "abrir_dashboard.bat"
# Any OS (manual):
pip install streamlit
streamlit run dashboard.py
First run — double-click abrir_dashboard.bat and the panel opens.
Only dashboard.py needs an external library (Streamlit; pandas and altair come with
it). The parser, the snapshot and the watcher run on pure Python.
The save is found automatically on any drive (
find_savereads the Steam registry +libraryfolders.vdf). On the Game Pass/Microsoft Store version, point to the save with theDRG_SAVEenvironment variable or by passing the path as an argument.
So you never snapshot by hand, the watcher (watcher.py) launches alongside the game
via Steam and snapshots on its own (on open, on mission end, on close).
- Run
configurar_steam.bat(double-click) — it builds the line with your PC's path and copies it to the clipboard. - In Steam: DRG → Properties → General → Launch Options → paste with
Ctrl+V. - Click ▶ Play. Done — the history fills up on its own.
Setup — run configurar_steam.bat, then paste into Steam → Launch Options.
The database stays small: if nothing changed, it doesn't write (dedup); and it keeps at most one snapshot per day (updated to the end-of-day state), so the day-to-day comparison stays clean.
Why not a mod.io mod? DRG mods run in a locked Blueprint sandbox (no file, process, or network access). Only native code could escape that, which would be heavy and fragile. So the capture is external (the watcher), not a mod.
When this repository gets new code, updating is one step — and it never touches your
data. No Git needed (only Python, which you already have): the updater downloads the
newest code from GitHub as a ZIP and overlays it. Your database (drg_stats.db), the log
and the .sav files aren't in the repo ZIP, so they're left untouched automatically.
- Windows: double-click
atualizar.bat. - Any OS (manual):
python atualizar.py
The dashboard also checks on its own: when a newer version exists on GitHub, a 🔔 update available notice appears in the sidebar (checked at most once per hour).
Works the same whether you cloned the repo with Git or downloaded the ZIP — the updater doesn't rely on Git at all.
The save is a GVAS file (Unreal Engine's binary format): ~1.4 million raw bytes, no manual. Figuring out what each chunk means was done by hand.
👉 The full explanation, from absolute zero (byte by byte), is in
logica.md — worth a read even if you've never programmed.
Highlights of what was decoded:
- FString (a length-prefixed string) and how to find properties by their exact
encoding, not by substring (so
Leveldoesn't match insideRetiredCharacterLevels). EnemiesKilled— aMapPropertyofGUID (16 bytes) → count, 77 species.- Enemy names were discovered by a JOIN on the kill count (the in-game bestiary × the save).
- Rank and promotions are derived (computed from the class blocks + an XP table), not stored.
- "Missions Completed" (445) ≠ "Games Played" (504) — the former lives in a
MissionStatsSaveblock, summed per class. - Overclocks (
ForgedSchematics) cross-referenced withguids.json→ per-weapon progress.
drg_save_parser.py # reads the binary save (GVAS) -> organized data. Stdlib only.
snapshot.py # takes the "snapshot" and stores it in SQLite (1/day). Finds the save.
watcher.py # watches the save and calls the snapshot while you play.
dashboard.py # Streamlit panel: kills, progress, overclocks, table, CSV.
drg_watcher_launch.bat # Steam launcher (starts the watcher + the game).
configurar_steam.bat # generates the Launch Options line and copies it to the clipboard.
abrir_dashboard.bat # double-click opens the panel (installs Streamlit the first time).
atualizar.py # git-free updater: downloads the newest code from GitHub (ZIP).
atualizar.bat # double-click runs atualizar.py; keeps your data. No Git needed.
guids.json # GUID -> overclock/cosmetic (weapon, name, cost). The "catalog".
all_drg_enemies.json # GUID -> enemy name (the 77 species).
drg_stats.db # the database (generated; not under version control).
media/ # GIFs used in this README.
.streamlit/
└─ config.toml # the dark "cave" theme of the panel.
docs/
├─ logica.md # the reverse-engineering logic explained from scratch.
└─ claude_public.md # the full technical "map" of the project (decisions, gotchas, lessons).
- Cosmetics are still an estimate: vanity unlocks in DRG have several sources and the current count may fall short of the real one. Overclocks, though, are reliable.
- Some enemy names were deduced by elimination; and 4 pairs with identical counts have an
ambiguous pairing (details in
claude_public.md). - The Game Pass/Microsoft Store save is not auto-detected (use
DRG_SAVE).
Python (stdlib: struct, sqlite3, pathlib…) · SQLite · Streamlit · Altair
· pandas. No dependency to read the save — pure Python.
A fan project, unofficial and not affiliated with Ghost Ship Games. "Deep Rock Galactic" and its assets belong to their owners. This project only reads your own save locally (it never modifies the game save). Use at your own risk.
Rock and Stone! ⛏️🍺
Extrai suas estatísticas de Deep Rock Galactic direto do arquivo de save (formato binário cru), guarda um histórico num banco local e mostra tudo num dashboard interativo — com ranking de kills por espécie, evolução no tempo e progresso de overclocks. Captura automática enquanto você joga. Rock and Stone! ⛏️
Um projeto que percorre o arco completo de um trabalho de dados de verdade: Extrair (engenharia reversa de um save binário) → Transformar/Armazenar (ETL num SQLite) → Visualizar (dashboard). O jogo guarda essas estatísticas, mas só mostra uma de cada vez, sem histórico e sem gráfico. Este projeto resolve isso.
- 🐛 Kills por espécie — ranking das 77 espécies do bestiário, do save.
- 📈 Evolução no tempo — kills, créditos, rank e tempo de jogo ao longo dos dias.
- ⚙️ Progresso de overclocks — quantos você forjou de cada arma (ex.:
100/160), a lista exata do que falta e quantos você forjou desde a foto anterior. - 🆕 "Desde a última foto" — o que cresceu de um dia pro outro.
- 📸 Captura automática — um "vigia" tira uma foto sozinho quando você joga (abre a missão / termina / fecha o jogo), sem você abrir terminal nenhum.
- 🗂️ Tabela + export CSV — busca por espécie e download dos dados.
A aba ⚙️ Overclocks — progresso por arma e exatamente o que falta forjar.
save do jogo traduz bytes guarda histórico mostra bonito
(XXXXX_Player.sav) -> drg_save_parser.py -> snapshot.py -> dashboard.py
│ │ │ │
│ │ drg_stats.db <──────────────-┘
│ │ (banco SQLite) (lê o banco)
│ guids.json / ▲
│ all_drg_enemies.json │
└──────────────────────────────────── watcher.py (tira foto sozinho ao jogar)
drg_save_parser.pysabe ler o save binário (sem dependência externa).snapshot.pyusa o parser pra tirar uma "foto" e gravar no banco (uma por dia).watcher.pyvigia o save e chama o snapshot sozinho enquanto você joga.dashboard.pylê o banco (e o save, pros overclocks) e desenha os gráficos.guids.json/all_drg_enemies.jsontraduzem os códigos internos (GUIDs) em nomes.
Pré-requisito: Python 3.10+ instalado (marque "Add Python to PATH" no instalador do Windows).
# 1. Clone o repositório
git clone https://github.com/gilas-byte/drg-stats-tracker.git
cd drg-stats-tracker
# 2. Tire a primeira foto (acha o save sozinho e cria o banco)
python snapshot.py
# 3. Abra o painel
# Windows: duplo clique em "abrir_dashboard.bat"
# Qualquer SO (manual):
pip install streamlit
streamlit run dashboard.py
Primeira vez — duplo clique em abrir_dashboard.bat e o painel abre.
Só o dashboard.py precisa de biblioteca externa (Streamlit; o pandas e o altair vêm
junto). O parser, o snapshot e o watcher rodam com Python puro.
O save é encontrado automaticamente em qualquer drive (o
find_savelê o registro da Steam + olibraryfolders.vdf). Se você usa a versão Game Pass/Microsoft Store, aponte o save com a variável de ambienteDRG_SAVEou passando o caminho como argumento.
Pra não precisar tirar foto na mão, o vigia (watcher.py) sobe junto com o jogo pela
Steam e tira fotos sozinho (na abertura, no fim de missão e ao fechar).
- Rode
configurar_steam.bat(duplo clique) — ele monta a linha com o caminho do seu PC e copia pro clipboard. - Na Steam: DRG → Propriedades → Geral → Opções de Inicialização → cole com
Ctrl+V. - Clique em ▶ Jogar. Pronto — o histórico se enche sozinho.
Setup — rode configurar_steam.bat e cole em Steam → Opções de Inicialização.
O banco não incha: se nada mudou, não grava (dedup); e guarda no máximo uma foto por dia (atualizada pro estado do fim do dia), então o comparativo dia-a-dia fica limpo.
Por que não é um mod do mod.io? Os mods de DRG rodam numa sandbox de Blueprint fechada (sem acesso a arquivos, processos ou rede). Só código nativo escaparia disso, o que seria pesado e frágil. Por isso a captura é externa (o vigia), não um mod.
Quando este repositório recebe código novo, atualizar é um passo só — e nunca mexe nos
seus dados. Não precisa de Git (só de Python, que você já tem): o atualizador baixa o
código novo do GitHub como ZIP e sobrepõe. O banco (drg_stats.db), o log e os .sav não
estão no ZIP do repositório, então ficam intocados automaticamente.
- Windows: duplo clique em
atualizar.bat. - Qualquer SO (manual):
python atualizar.py
O painel também checa sozinho: quando existe versão nova no GitHub, aparece um aviso 🔔 atualização disponível na barra lateral (verificado no máximo uma vez por hora).
Funciona igual se você clonou o repositório com Git ou baixou o ZIP — o atualizador não depende de Git de jeito nenhum.
O save é um arquivo GVAS (formato binário da Unreal Engine): ~1,4 milhão de bytes crus, sem manual. Descobrir o significado de cada pedaço foi feito na mão.
👉 A explicação completa, do zero absoluto (byte por byte), está em
logica.md — vale a leitura mesmo se você nunca programou.
Destaques do que foi decifrado:
- FString (texto com o tamanho na frente) e como achar propriedades pela codificação
exata, não por substring (pra
Levelnão casar dentro deRetiredCharacterLevels). EnemiesKilled— umMapPropertydeGUID (16 bytes) → contagem, 77 espécies.- Os nomes dos bichos foram descobertos por JOIN pela contagem de kills (bestiário do jogo × save).
- Rank e promoções são derivados (calculados dos blocos de classe + tabela de XP), não ficam salvos.
- "Missões concluídas" (445) ≠ "Partidas jogadas" (504) — o primeiro vive num bloco
MissionStatsSave, somado por classe. - Overclocks (
ForgedSchematics) cruzados com oguids.json→ progresso por arma.
drg_save_parser.py # lê o save binário (GVAS) -> dados organizados. Só stdlib.
snapshot.py # tira a "foto" e grava no SQLite (1 por dia). Acha o save sozinho.
watcher.py # vigia o save e chama o snapshot sozinho enquanto você joga.
dashboard.py # painel Streamlit: kills, evolução, overclocks, tabela, CSV.
drg_watcher_launch.bat # lançador pra Steam (sobe o vigia + o jogo).
configurar_steam.bat # gera a linha das Launch Options e copia pro clipboard.
abrir_dashboard.bat # duplo clique abre o painel (instala o Streamlit na 1ª vez).
atualizar.py # atualizador sem git: baixa o código novo do GitHub (ZIP).
atualizar.bat # duplo clique roda o atualizar.py; preserva seus dados. Sem git.
guids.json # GUID -> overclock/cosmético (arma, nome, custo). O "catálogo".
all_drg_enemies.json # GUID -> nome do bicho (as 77 espécies).
drg_stats.db # o banco (gerado; fora do controle de versão).
media/ # GIFs usados neste README.
.streamlit/
└─ config.toml # tema escuro "caverna" do painel.
docs/
├─ logica.md # a lógica da engenharia reversa explicada do zero.
└─ claude_public.md # o "mapa" técnico completo do projeto (decisões, gotchas, aulas).
- Cosméticos ainda são estimativa: o desbloqueio de vanity no DRG tem várias fontes e a contagem atual pode ficar abaixo do real. Overclocks, esse sim, está confiável.
- Alguns nomes de bichos foram deduzidos por eliminação; e 4 pares com contagem idêntica
têm pareamento ambíguo (detalhes no
claude_public.md). - Save da versão Game Pass/Microsoft Store não é auto-detectado (use
DRG_SAVE).
Python (stdlib: struct, sqlite3, pathlib…) · SQLite · Streamlit · Altair
· pandas. Nenhuma dependência pra ler o save — só Python puro.
Projeto de fã, não oficial e sem afiliação com a Ghost Ship Games. "Deep Rock Galactic" e seus ativos pertencem aos seus donos. Este projeto só lê seu próprio save localmente (nunca modifica o save do jogo). Use por sua conta e risco.
Rock and Stone! ⛏️🍺