Releases: DSargent21/ClashGo
Releases · DSargent21/ClashGo
Release list
ClashGO v0.5.0-beta
Added
- Deploy budget — the deploy phase is now wall-clock bounded
(internal/attack/attack.go).StartDeployBudgetarms a deadline
(~2× the longest legitimately-observed full deployment) and every
reconcile / sweep / verify loop consultsDeployBudgetExhausted()
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_percentper-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):
LastDestructionPercentlatches the highest destruction read during the
battle (monotonic, so a transient 0 as the overlay renders can't win),
ThDestroyedlatches the golden "Town Hall destroyed" banner from an
optionalstall_config.th_banner_zone, andStarsFromOutcomescores
stars from the outcome (≥50% = 1★, TH = +1★, 100% = 3★) when the result
panel's OCR fails.ResetBattleOutcomeclears 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 asStateBattleEnd, 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 declarearmy_slotand
selectArmySlotclicks 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 withFAIL "closed"while compound commands
(getprop x; <cmd>) run normally.shellWedgeFallbackrewrites the
service string,stripPrefixLinedrops the extra output line, and the
exec-service path falls back toshell:(with a 16→12-byte screencap
header normalizer) — the wedge survivesadb kill-server, so this is
the only durable fix at the transport layer. screenSizerecovery ladder (internal/bot/bootorchestrator.go) —
a failedwm sizenow 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 likeoffset: 130 # Deeper in for EQsnow applies to every unit in the phase (per-unitoffset
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
VerifyAndReconcilere-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 path —
deploy_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 intomake 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 madeprocessFramepress 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 testnow runs the full contract suite —go vet, Go tests
(with the local OpenCVLC_RPATHinjected viapkg-config), and the
Python strategy tests, with a graceful skip when no pytest-capable
interpreter is present.valk_spam.yamldeclaresend_at_percent: 50andarmy_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.pngfixture. - Stale
manual_labels.jsonentries 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 sizewedge 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 idlediscardReaderinherited 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 testgreen:go vetclean, all Go packages pass, 24/24 Python
strategy-contract tests pass.
ClashGO v0.4.0-beta
Changed
- Frame-hot-path template matching is single-scale by default
(internal/vision/vision.go) —MatchTemplateno longer blindly
escalates every call to a 5-step multi-scale search (0.8–1.2). That
escalation cost 5Resizeallocations + 5 cgo matches per call on the
per-frame path. Callers that genuinely need density-scale tolerance
callMatchMultiScaleexplicitly (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 forMatchTemplateresults now comes from the shared vision Mat
pool (vision.GetMat/PutMat) instead ofgocv.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–300msapp_processJVM 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
(routeTap→markPipeBroken→ legacy tap path), and pipe start
failure logs a warning and degrades gracefully.
Fixed
--onceCLI runs now exit cleanly (cli.go,internal/bot/bot.go)
— main() previously blocked forever onctx.Done()after the bot
finished its final attack, so a--oncerun 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 thewm sizeshell 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
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.jsonon a fresh runner and publishes them to a GitHub Release
automatically. Uses only the built-inGITHUB_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
(recoverEmulatorininternal/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 keepalive —
tools/run_bot_keepalive.shrespawns the CLI
bot ~10s after ANY exit (panic, OOM, kill) and pins
CLASHGO_ASSETS_DIRso templates/strategies resolve even under launchd
(whose default cwd is/).
- Emulator-death recovery ladder — when screen capture dies mid-session
- 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=switchtoggles + 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-levelsendeventquadratic-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).TapHumannow 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 NOTrecordActivity, 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/idlepanmodes) for Phase-1 style isolated
emulator action checks.
- Logging —
logs/autonomous_loop.logrecords 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
asStateBattle(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
atomicsplashDismissInFlightflag. Deliberately does NOT
recordActivityso 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.
- 3 new states —
- 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.-watchloops every 3s.tools/observe.sh— one-shot bundle: capture + classify + color map- OCR, artifacts saved to
obs/<timestamp>/with anobs/latest
symlink for convenience.
- OCR, artifacts saved to
tools/ocr.swift— on-device Apple Vision OCR (no tesseract / no
network); printsx,y,w,h | textper 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.mdfor 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 fromgo.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
SlotManagerhelpers, the validatorPlannerengine
(internal/attack/plan.go+ its test),game.Calibrator, and the
adb.WithDeviceIDoption. - 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 fields —
app.echo,transport.seq,
bot.lastFrameTime,bootorchestrator.mu,recovery.onApply,
updater.manifest,troop_counter.calibrated/scaleX/scaleY. - Consolidated duplicated logic —
app.gostats merge extracted into a
mergeStatshelper;Transport.ExecRawmerged intoExec; the
version.gobuild-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; orphanedassets/grab/screenshots and stale.gitignore
entries removed.
- Deleted the NATS event-bus subsystem (
Fixed
- BlueStacks Air cold boot burned 90s then failed —
waitForVMProcess
waited forqemu-system/hd-adbprocess 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 templates —
NewLootRecognizerpanicked
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.
executeAttackSequencenow 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_victoryon the tracked fixture
(internal/game/testdata/screen_victory.png); the former
screen_victory_live.pngfixture 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 asStateBattle, so
the stuck-watchdog force-stopped the game an...
ClashGO v0.2.0-beta
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_continuetemplate-driven Continue button - Device-independent CPU metric (
cpu_time_sec) surfaced in Settings - Context-aware ADB shell/capture wrappers;
AutoDetectDeviceverifies BlueStacks viagetprop cmd/design_attackone-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;
lastNavdata race removed Health().LastCapturereports 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"),
safeEventsOnguard,UpdateBannerRules-of-Hooks fix go vetclean (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 dragClashGO.appinto Applications - Or click Update in the in-app banner (SHA256-verified, in-place replace)
⚠️ Beta — use with caution. Report bugs via GitHub Issues.