Skip to content

Releases: DSargent21/ClashGo

ClashGO v0.5.0-beta

Choose a tag to compare

@github-actions github-actions released this 16 Sep 21:27

Added

  • Deploy budget — the deploy phase is now wall-clock bounded
    (internal/attack/attack.go). StartDeployBudget arms a deadline
    (~2× the longest legitimately-observed full deployment) and every
    reconcile / sweep / verify loop consults DeployBudgetExhausted()
    between rounds. Observed live before this: a spent Earthquake card whose
    cooldown icon never reads "empty" kept the sweep re-firing taps for
    ~2 minutes after the battle had ended. Leftover slots are now reported
    as undeployed so the attack report shows the partial failure instead of
    a phantom success.
  • end_at_percent per-strategy auto-end (pkg/strategy/yaml_parser.go,
    internal/attack/attack.go) — a strategy can declare the destruction
    percentage at which the win is already secured (e.g. valk_spam.yaml
    ends at 50%). In threshold mode the stall timer is deliberately disabled
    below the threshold so a stall can never abandon the win early, and the
    battle only ends when the red End Battle button is actually on screen.
  • Battle-outcome correctness (internal/attack/attack.go):
    LastDestructionPercent latches the highest destruction read during the
    battle (monotonic, so a transient 0 as the overlay renders can't win),
    ThDestroyed latches the golden "Town Hall destroyed" banner from an
    optional stall_config.th_banner_zone, and StarsFromOutcome scores
    stars from the outcome (≥50% = 1★, TH = +1★, 100% = 3★) when the result
    panel's OCR fails. ResetBattleOutcome clears both at the top of
    WaitForBattleEndCtx — live, battle 1's garbage 381% read was still
    latched when battle 2's result was parsed, turning a 32% defeat into
    "3 stars".
  • StateConnectionLost + StateConfirmExit (internal/game/types.go,
    internal/game/classifier.go, internal/bot/bot.go) — the disconnect
    dialog (TRY AGAIN / RETURN HOME) was misread as StateBattleEnd, so the
    bot tapped result-screen coordinates forever (live: 18:26 boot → 18:28
    ReturnHome fallback → 18:33 restart loop). TRY AGAIN reconnects in
    place; the quit-confirm dialog is dismissed with CANCEL.
  • Saved-army slot selection (cmd/internal/bot/bot.go,
    pkg/strategy/yaml_parser.go) — strategies declare army_slot and
    selectArmySlot clicks that recipe card in the army list (measured
    geometry: first card at ref-y 227, ~54px stacking). valk_spam.yaml
    targets the 4th recipe.
  • Inter-attack cooldown (min_seconds_between_attacks, default 30s)
    — without it the bot re-attacked ~8s after every Return Home with
    whatever the camps held (live: three near-identical defeats in under
    four minutes).
  • BlueStacks adbd wedge workaround (internal/adb/transport.go,
    internal/adb/shellpipe.go). In the wedged state adbd answers every
    bare command with FAIL "closed" while compound commands
    (getprop x; <cmd>) run normally. shellWedgeFallback rewrites the
    service string, stripPrefixLine drops the extra output line, and the
    exec-service path falls back to shell: (with a 16→12-byte screencap
    header normalizer) — the wedge survives adb kill-server, so this is
    the only durable fix at the transport layer.
  • screenSize recovery ladder (internal/bot/bootorchestrator.go) —
    a failed wm size now escalates retry-transport → adb kill-server +
    start-server between attempts instead of burning the budget against the
    same wedged socket.
  • Phase-level deploy offset propagation (internal/attack/deploy_planner.go,
    pkg/strategy/yaml_parser.go) — a phase pin like offset: 130 # Deeper in for EQs now applies to every unit in the phase (per-unit offset
    still wins).
  • Post-deploy spell reconciliation (internal/attack/spell_deployer.go)
    Amount: "All" resolves to the card's live OCR count (11 rage on one
    card, 4 EQs on another) instead of a hardcoded 5, and
    VerifyAndReconcile re-reads the slot afterwards and re-fires the
    difference. A no-progress stop (two identical positive reads) and a
    zero-OCR-streak bound stop a spent card from eating taps forever.
  • cmd/wedge_probe — standalone live harness for the adbd-wedge
    detection + compound-command fallback.
  • Test coverage for every new decision pathdeploy_budget_test.go,
    battle_end_test.go (destruction → stars, trophy/star pixel anchors,
    defeat fixtures), spell_deployer_test.go (tap-level assertions + formula
    geometry), slot_manager_test.go (duplicate manual-label hijack),
    testharness_test.go, bootorchestrator_test.go (wm-size fallback),
    classifier_stuck_test.go, formula_test.go, yaml_parser_test.go, plus
    Python strategy-contract tests (tests/test_spell_placement.py,
    tests/test_valk_strategy.py) wired into make test.

Changed

  • Loot OCR is content-located, not slot-located
    (internal/game/loot.go) — loot rows are found by detecting bright,
    low-saturation connected components (the white/gold digits) inside a
    generous search zone and grouping them into horizontal text lines, so the
    reading no longer depends on fixed HUD geometry. Digit ROIs get relaxed
    padding for narrow columns (the League Bonus gold was read 10× low when
    the right edge clipped the trailing digit), and implausible reads are
    rejected instead of being fed to the stall timer.
  • Frame loop 10 Hz → 4 Hz (internal/bot/bot.go) — during a battle the
    deploy and battle-end goroutines run their own captures at their own
    cadence, so the full-screen classify at 10 Hz was mostly redundant
    (~55ms captures + classify pinned a core). 4 Hz still catches the result
    overlay fast enough for ReturnHome and the stuck-watchdog.
  • ArmyCamp rule hardened (internal/game/classifier.go) — the lone
    brown pixel anchor also passed on ordinary village frames (live:
    (479,149) = RGB(61,53,62)), which made processFrame press Back on the
    real village and open the quit-confirm dialog the bot then sat on for the
    5-minute boot grace; the rule now requires both army-overview tab-header
    anchors, and a frame that still shows the real Attack! button is treated
    as the main village and never Back-pressed.
  • Battle-search / bonus ROIs widened (assets/battle_loot_rois.json) to
    match the new content-located loot reader.
  • make test now runs the full contract suite — go vet, Go tests
    (with the local OpenCV LC_RPATH injected via pkg-config), and the
    Python strategy tests, with a graceful skip when no pytest-capable
    interpreter is present.
  • valk_spam.yaml declares end_at_percent: 50 and army_slot: 4.

Fixed

  • Fabricated 3-star victories — the destruction-rule read used to
    OVERRIDE the result panel's parsed stars, so a garbage stall-ROI percent
    (381%, 851%, 991%) turned live defeats into wins. The visual parse is now
    ground truth and the rule read is only a fallback when the panel parse
    fails outright.
  • Star art read as victory on the defeat screen — the result-panel star
    parse is now two-pass and defeat-safe; pinned by the new
    internal/game/testdata/screen_defeat.png fixture.
  • Stale manual_labels.json entries creating duplicate unit identities
    (internal/attack/slot_manager.go) — a manual label now loses to a
    template match on a different slot. Live, a stale "grand warden" label
    on the unidentified Dragon Duke slot stole the warden's main-phase deploy
    and the Duke was never swept (it looked deployed).
  • wm size wedge aborting the boot — falls back to the live
    screencap's header for authoritative pixel dimensions (this is the same
    fix family as 0.4.0's boot fallback, now with the retry ladder above).
  • Pipe read deadline left armed after service negotiation
    (internal/adb/shellpipe.go) — the idle discardReader inherited the
    shell-timeout deadline and marked a perfectly healthy pipe broken
    ("adb shell pipe reader stopped: i/o timeout") mid battle-end wait.

Verified

  • Full live session on BlueStacks Air (860×732, SM-G998B profile): boot →
    classify → attack search → loot OCR → EDrag Rush and Valkyrie/EQ runs →
    result parse (stars derived from destruction, defeat fixture matched) →
    graceful shutdown.
  • make test green: go vet clean, all Go packages pass, 24/24 Python
    strategy-contract tests pass.

ClashGO v0.4.0-beta

Choose a tag to compare

@github-actions github-actions released this 01 Sep 03:39

Changed

  • Frame-hot-path template matching is single-scale by default
    (internal/vision/vision.go) — MatchTemplate no longer blindly
    escalates every call to a 5-step multi-scale search (0.8–1.2). That
    escalation cost 5 Resize allocations + 5 cgo matches per call on the
    per-frame path. Callers that genuinely need density-scale tolerance
    call MatchMultiScale explicitly (named templates hit the scaled
    template cache). Expected effect: per-frame template matching cgo work
    drops from 5×N to N matches (N = templates checked).
  • Pooled result Mats on the classifier and loot-OCR paths
    (internal/game/templates.go, internal/game/loot.go) — the result
    Mat for MatchTemplate results now comes from the shared vision Mat
    pool (vision.GetMat/PutMat) instead of gocv.NewMat() + Close()
    per template per frame. Zero result-Mat heap allocation on the
    classifier tick and loot OCR hot paths.
  • Persistent ADB shell pipe is now enabled by default
    (internal/config/config.go) — UseShellPipe: true. Removes the
    ~100–300ms app_process JVM spin-up per tap during attack cycles
    (measured 30–80ms/command on USB, more on WiFi ADB). Automatic
    fallback to the legacy one-shot transport is verified
    (routeTapmarkPipeBroken → legacy tap path), and pipe start
    failure logs a warning and degrades gracefully.

Fixed

  • --once CLI runs now exit cleanly (cli.go, internal/bot/bot.go)
    — main() previously blocked forever on ctx.Done() after the bot
    finished its final attack, so a --once run hung with the process
    alive after the session summary printed. Bot.Done() exposes a
    channel that closes on graceful attack-cap shutdown, and main()
    selects on it.
  • Boot survives a wedged wm size (internal/bot/bootorchestrator.go)
    — when the wm size shell call fails (BlueStacks returning
    "ADB: closed" while SurfaceFlinger still serves frames), the boot
    orchestrator now falls back to the live screencap's 12-byte header
    for authoritative pixel dimensions instead of aborting the whole
    boot and leaving the Start button dead.

Verified

  • Full end-to-end live run on BlueStacks Air (860×732): boot → calibrate
    → attack search → loot OCR → EDrag Rush attack (100% deploy, 3 stars,
    2.1M elixir) → graceful shutdown, exit code 0.

ClashGO v0.3.0-beta

Choose a tag to compare

@github-actions github-actions released this 11 Aug 02:04

Added

  • Auto-pop update dialog — when a new release is published, ClashGO
    now opens the update window by itself (no pill click needed): one-click
    Update & Restart, SHA256-verified download, in-place bundle swap, and
    a non-dismissible restart splash. "Later" silences it for the session;
    "Skip version" silences it permanently (web/src/components/UpdateBanner.tsx).
  • One-command release publishing — pushing a v* tag now runs
    .github/workflows/release.yml, which builds the macOS zip, DMG, and
    latest.json on a fresh runner and publishes them to a GitHub Release
    automatically. Uses only the built-in GITHUB_TOKEN — no personal
    access token ships in the app, the repo, or the artifacts.
  • Autonomous-run resilience hardening (all live-verified on BlueStacks Air):
    • Emulator-death recovery ladder — when screen capture dies mid-session
      the bot now escalates transport reconnect → adb-server reset →
      BlueStacks relaunch → boot re-orchestration instead of force-stopping
      the game against a dead transport and spinning forever
      (recoverEmulator in internal/bot/bot.go).
    • Panic containment — recover guards around the capture frame loop and
      the attack-sequence goroutine, so one bad frame or missing asset can no
      longer kill the whole process.
    • Nil-template fallback — the template store degrades to an empty
      (non-nil) store when assets can't be resolved, so loot/battle OCR keeps
      running instead of panicking mid-attack (internal/game/templates.go).
    • Process keepalivetools/run_bot_keepalive.sh respawns the CLI
      bot ~10s after ANY exit (panic, OOM, kill) and pins
      CLASHGO_ASSETS_DIR so templates/strategies resolve even under launchd
      (whose default cwd is /).
  • Web UI overhaul — polished dashboard console (severity chips,
    text filter, copy, match highlighting, pause-on-hover auto-scroll),
    config view with live range validation + role=switch toggles + keyboard
    accessible combobox, two-step armed reset confirm, ADB status pill with
    semantic colors, analytics donut, dark-mode toggle, and an a11y pass
    (role=log, focus-visible rings, prefers-reduced-motion).
  • Human-gesture input layer (autonomous-hardening iteration 1):
    • adb.SwipeBezier — low-level sendevent quadratic-bezier swipe with
      ease-in-out velocity (accelerate → coast → decelerate) and a random
      10-20% perpendicular arc so every drag reads as a real finger; wired
      into the navigator's village camera pans; degrades to the linear path
      on devices that can't inject raw input. Unit-tested
      (internal/adb/bezier_test.go).
    • TapHuman now emits ~1-in-5 taps as a 60-130ms press-and-release
      instead of an instant down/up pair, and hesitates with a Gaussian
      reaction delay (base 250ms / σ 70ms — mass in the 180-320ms human
      band, tail ~460ms) before committing. Hot deploy loops (TapFast /
      TapAsync) are untouched and stay fast.
    • Navigator.IdlePan — randomized bezier camera pan + micro-pause +
      mirrored return for idle base-wandering; throttled (~18s) in the
      bot's idle-in-village path and deliberately NOT recordActivity, so
      the stuck-watchdog still fires on genuinely stuck idles. Unit-tested
      (internal/game/navigator_test.go).
    • cmd/swipe_probe — standalone live-gesture verification harness
      (launcher / game / idlepan modes) for Phase-1 style isolated
      emulator action checks.
  • Logginglogs/autonomous_loop.log records each hardening-loop
    iteration's audit findings, live-verification results, and regression
    status.
  • Post-boot splash auto-handling — the bot can now boot unattended.
    After every relaunch, Clash of Clans shows a short splash chain (the
    "ТАР!" tap-to-continue / collect screen → the CoC castle logo, which
    sits static 1-3 min while the session connects → an optional news /
    announcement splash with a Continue button) before the village loads.
    Previously the classifier misread the collect splash's orange artwork
    as StateBattle (1/9 pixels), the stuck-watchdog force-stopped the
    game, and every relaunch re-showed the splash — an endless
    force-stop/relaunch loop with zero attacks. Now:
    • 3 new states — StateTapToContinue, StateNewsSplash, StateLogo
      (internal/game/types.go) with classifier rules
      (internal/game/classifier.go) verified at 0 distance on live
      captures and 0 false-positives on the village.
    • Auto-dismiss in processFrame (internal/bot/bot.go) — taps the
      "ТАР!" prompt text (ref 450,195) and the news Continue button (ref
      403,535), each through a single in-flight goroutine guarded by the
      atomic splashDismissInFlight flag. Deliberately does NOT
      recordActivity so a genuinely-stuck splash variant still trips the
      stuck-watchdog.
    • Boot-grace in checkStuck — splash states get a 5-minute window
      (the logo has no progress indicator) instead of the generic 35s
      timeout that caused mid-boot force-restarts.
    • Mirrored dismissal cases in internal/bot/wall_upgrade.go.
    • Live-verified: restart loop eliminated (1 startup restart vs 15+),
      splash auto-dismissals, and full attacks completing with correct
      result parsing.
  • Text-based observability tooling — the bot's "eye view" for a
    terminal-only session.
    • cmd/screendump — captures the live screen (or reads a saved PNG),
      runs the bot's real classifier with per-rule pixel evidence, renders
      a color-mapped ASCII layout, probes key button pixels, and
      optionally OCRs on-screen text. -watch loops every 3s.
    • tools/observe.sh — one-shot bundle: capture + classify + color map
      • OCR, artifacts saved to obs/<timestamp>/ with an obs/latest
        symlink for convenience.
    • tools/ocr.swift — on-device Apple Vision OCR (no tesseract / no
      network); prints x,y,w,h | text per recognized region in
      screenshot pixel space.
    • cmd/classify_probe / cmd/result_probe / cmd/swipe_probe
      standalone diagnostics for classifier state, battle-result OCR
      parsing, and human-gesture verification respectively.
    • See docs/OBSERVABILITY.md for the full workflow.

Changed

  • Massive dead-code cleanup — removed ~16.5k lines of unreachable code
    and pruned the repo tree:
    • Deleted the NATS event-bus subsystem (internal/bus,
      internal/agent, internal/geo, internal/world,
      game/enricher.go + game/explorer.go, docker-compose.yml) — zero
      production references; NATS deps dropped from go.mod/go.sum.
    • Removed ~35 verified-dead functions across attack, bot, game,
      vision, logger, adb, training, updater, strategy — incl. the
      NDJSON log mirror, ParseCSV, ClassifyStateFast, SpellLine,
      isUnitSelected, hasColorSignature, WaitForSlotEmpty, the legacy
      SlotManager helpers, the validator Planner engine
      (internal/attack/plan.go + its test), game.Calibrator, and the
      adb.WithDeviceID option.
    • Deleted 48 unreferenced cmd/ diagnostic tools — kept the five wired
      into Makefile/scripts (attack_record, capture_template,
      design_attack, release_manifest, test_wall_upgrade).
    • Dropped dead struct fieldsapp.echo, transport.seq,
      bot.lastFrameTime, bootorchestrator.mu, recovery.onApply,
      updater.manifest, troop_counter.calibrated/scaleX/scaleY.
    • Consolidated duplicated logicapp.go stats merge extracted into a
      mergeStats helper; Transport.ExecRaw merged into Exec; the
      version.go build-date + Makefile ldflag removed.
    • Frontend — fixed 4 unused-variable TS errors (App.tsx, main.tsx,
      Sidebar.tsx).
    • Docs + tree — README / DESIGN / PERFORMANCE / CHEST refreshed for the
      new layout; orphaned assets/grab/ screenshots and stale .gitignore
      entries removed.

Fixed

  • BlueStacks Air cold boot burned 90s then failedwaitForVMProcess
    waited for qemu-system/hd-adb process names that never appear on
    BlueStacks Air for Apple Silicon (the VM runs in-process), so every cold
    boot hit the full wait and logged a spurious "VM did not start" failure.
    An open adb port (5555+) now counts as a VM-up signal — the same signal
    the ADB-connect wait already uses (internal/adb/emulator_mac.go).
  • Nil-pointer panic on missing templatesNewLootRecognizer panicked
    on a nil template store when assets didn't resolve (e.g. running from a
    launchd cwd of /), killing the bot at attack entry. The store now
    falls back to an empty store and the attack goroutine is panic-guarded.
  • Attack History lagged the loot totals — the history entry was only
    appended after Return Home + wall upgrades (which can take minutes), so
    the dashboard showed fresh gold/elixir totals long before the new attack
    row appeared — and the entry was lost entirely if Return Home failed.
    executeAttackSequence now records the report and fires the UI refresh
    at battle-result parse time (internal/bot/bot.go).
  • League Bonus gold misread by a factor of 10 — the bonus column's
    right padding clipped the trailing digit (bonus gold "+256 000" read as
    25600): the digit lost its right edge and its template-match score fell
    below the 0.5 floor. Narrow columns now get relaxed padding
    (internal/game/loot.go) and the bonus ROI's right edge was widened
    (assets/battle_loot_rois.json). Regression-tested via
    TestLootVictory/screen_victory on the tracked fixture
    (internal/game/testdata/screen_victory.png); the former
    screen_victory_live.png fixture was removed for privacy (it was a live
    capture containing real player names and was gitignored, so it silently
    skipped on fresh clones anyway).
  • Endless force-stop/relaunch loop on the post-boot collect splash
    the "ТАР!" tap-to-continue screen was misclassified as StateBattle, so
    the stuck-watchdog force-stopped the game an...
Read more

ClashGO v0.2.0-beta

Choose a tag to compare

@DSargent21 DSargent21 released this 05 Aug 19:56

ClashGO v0.2.0-beta

Bug-fix + performance release. Full changelog: https://github.com/Ducky705/ClashGO/blob/main/CHANGELOG.md

Highlights

  • More reliable chest handling — event-agnostic chest detection gated on the hammer template, plus a retrying, template-driven Continue tap (no more hand-measured rects).
  • Faster & lighter — audit-driven perf pass cuts battle-state CPU ~10-20%, RSS ~10-20 MB, and GC cycles ~40-60%. See docs/PERFORMANCE.md.
  • Robust BlueStacks bring-up — boot orchestrator + ADB recovery ladder that survives macOS Sequoia failure modes (soft-reset before adb kill-server).
  • In-app updates — the dashboard now checks GitHub Releases and offers SHA256-verified downloads with in-place install.

What's new

  • Chest detection fires only on the hammer template; btn_continue template-driven Continue button
  • Device-independent CPU metric (cpu_time_sec) surfaced in Settings
  • Context-aware ADB shell/capture wrappers; AutoDetectDevice verifies BlueStacks via getprop
  • cmd/design_attack one-stop authoring/verify tool with per-corner formula overrides (target_edge: Random)
  • Wall-upgrade single-tap-each-X dismiss flow + unified modal-close event payloads
  • New tooling: cmd/test_wall_upgrade, cmd/adb_probe, cmd/boot_debug, cmd/capture_template, tools/picker.py

Bug fixes

  • Chest Continue tap waits for the button to render and retries (overlay lags ~1s)
  • MatPool key collision (silent corruption) — numeric pool keys
  • Frame-encode Mat leak closed; lastNav data race removed
  • Health().LastCapture reports the true last capture time
  • Attack history can no longer be wiped by a transient read error
  • Per-corner mirroring fixes (abbreviated names, pointer aliasing, quadrant scaling)
  • Web: light theme default (no more "black screen"), safeEventsOn guard, UpdateBanner Rules-of-Hooks fix
  • go vet clean (agent copylock + format-string fixes)

Performance

  • ~10-20% battle-state CPU freed, ~10-20 MB RSS, ~40-60% fewer GC cycles
  • Dead IPC emits removed, tab-gated screenshot poll, mat-cache keying, 1s world flush, in-memory history cache, detached teardown
  • Verification recipe: docs/PERFORMANCE.md

Install

  • Download ClashGO-v0.2.0-beta-macOS.zip (or the DMG) and drag ClashGO.app into Applications
  • Or click Update in the in-app banner (SHA256-verified, in-place replace)

⚠️ Beta — use with caution. Report bugs via GitHub Issues.