Files
yusufipk c2a5a2d4d2 Hearthstone deck tracker for Linux, first public version
Reads the game's own Power.log: no screen capture, no image
recognition, no memory reading.

- deck tracking (remaining cards, draw chance, played cards fade in place)
- opponent panel (revealed cards, hand and deck counts)
- decks read from the game's offline cache, matched to the match
- card art in rows, full card on hover
- overlay and window modes, adjustable transparency, tray icon
- English and Turkish interface
- consistency tests over a real log corpus, cross-checked against Zone.log
2026-07-27 22:31:13 +07:00

123 lines
4.0 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Terminalde canlı takip. Arayüzden önce boru hattını doğrulamak için.
Kullanım:
python -m tools.live # oyunun ortasından itibaren takip
python -m tools.live --full # mevcut oturum logunu baştan oku
python -m tools.live --once # tek seferlik anlık durum yazdır
"""
from __future__ import annotations
import sys
import time
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
from core import logdir
from core.state import Game
from core.watcher import Watcher
from data.cards import CardDB
from data.decks import DeckLibrary
CLASS_SHORT = {
"DEATHKNIGHT": "DK",
"DEMONHUNTER": "DH",
"DRUID": "Druid",
"HUNTER": "Hunter",
"MAGE": "Mage",
"PALADIN": "Paladin",
"PRIEST": "Priest",
"ROGUE": "Rogue",
"SHAMAN": "Shaman",
"WARLOCK": "Warlock",
"WARRIOR": "Warrior",
}
def render(game: Game | None, library: DeckLibrary, cards: CardDB) -> str:
if game is None:
return "Maç yok. Oyunda bir maça girildiğinde burası dolacak."
def class_of(player_id):
hero = game.hero_card_id(player_id)
return CLASS_SHORT.get(cards.card_class(hero), cards.card_class(hero) or "?")
lines: list[str] = []
mode = game.meta.get("GameType", "?").removeprefix("GT_")
lines.append(
f"{class_of(game.local_player_id)} vs {class_of(game.opponent_player_id)} "
f"({game.opponent_name}) {mode} tur {game.game_turn}"
+ (f" SONUÇ: {game.result}" if game.result else "")
)
deck = library.match(game)
if deck is not None:
remaining = game.remaining_deck(deck.cards)
total = sum(remaining.values())
lines.append(f"\nDestem: {deck.name} ({total} kart kaldı, oyun sayacı {game.my_deck_count})")
ordered = sorted(
remaining.items(), key=lambda kv: (cards.cost(kv[0]), cards.name(kv[0]))
)
for card_id, count in ordered:
chance = 100.0 * count / total if total else 0.0
lines.append(
f" [{cards.cost(card_id)}] {cards.name(card_id):<28} x{count} %{chance:.0f}"
)
else:
lines.append(f"\nDestem: eşleşmedi ({game.my_deck_count} kart kaldı)")
lines.append(
f"\nRakip: elinde {game.opponent_hand_count}, destesinde {game.opponent_deck_count}"
)
seen: dict[str, int] = {}
for event in game.opponent_events:
if event.card_id:
seen[event.card_id] = seen.get(event.card_id, 0) + 1
for card_id, count in sorted(seen.items(), key=lambda kv: cards.cost(kv[0])):
lines.append(f" [{cards.cost(card_id)}] {cards.name(card_id)}" + (f" x{count}" if count > 1 else ""))
return "\n".join(lines)
def main(argv: list[str]) -> int:
install = logdir.detect()
if install is None:
print("Hearthstone kurulumu bulunamadı.", file=sys.stderr)
return 1
problems = logdir.check_log_config(install.log_config) + logdir.check_client_config(
install.client_config
)
if problems:
print("log yapılandırma uyarıları: " + ", ".join(problems), file=sys.stderr)
cards = CardDB.load()
library = DeckLibrary(cards, install.game_dir).load()
print(f"{len(library.decks)} deste yüklendi: {', '.join(d.name for d in library.decks)}")
watcher = Watcher(install, start_at_end="--full" not in argv)
if "--full" in argv:
# Mevcut oturumu baştan okuyup güncel duruma gel.
for _ in range(200):
if not watcher.poll():
break
if "--once" in argv:
watcher.poll()
print(render(watcher.game, library, cards))
return 0
print("Canlı takip başladı, çıkmak için Ctrl+C.\n")
try:
while True:
if watcher.poll():
print("\033[2J\033[H", end="")
print(render(watcher.game, library, cards))
time.sleep(0.5)
except KeyboardInterrupt:
return 0
if __name__ == "__main__":
raise SystemExit(main(sys.argv[1:]))