- C++ 49.6%
- QML 30.4%
- Python 15%
- CMake 2.9%
- Shell 1.7%
- Other 0.4%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
|
All checks were successful
CI / build-test (push) Successful in 1m48s
Der 2804 („Dialog konnte nicht geöffnet werden") trat beim Klick auf „Weiter" im Zielordner-Dialog auf. Ursache im InstallUISequence-Event: NewDialog -> VerifyReadyDlg hängt an der Bedingung `WIXUI_DONTVALIDATEPATH OR WIXUI_INSTALLDIR_VALID="1"`, und WIXUI_INSTALLDIR_VALID wird von der CustomAction WixUIValidatePath gesetzt — einer wixlib-DLL-Action, die in der wixl-MSI nicht existiert. Die Bedingung evaluiert dadurch dauerhaft falsch, der Dialog wechselt nie. Unter Wine reproduziert und per MSI-Log bestätigt (Sequenz endet bei „Action start: WelcomeDlg"/Zielordner ohne NewDialog). Fix: - WIXUI_DONTVALIDATEPATH=1 injizieren — der offizielle WiX-Schalter, der die Pfadvalidierung (und damit die fehlende CustomAction) überspringt; die NewDialog-Bedingung evaluiert dadurch wahr. - DoAction-Zeilen auf WixUI-*CustomActions generell droppen (es gibt keine wixlib-Aktionen im Paket; betroffen war nur WixUIValidatePath aus dem nie erreichbaren BrowseDlg). End-to-end unter Wine/Xvfb verifiziert: Willkommen (mit Programm- erklärung) → Lizenz (Checkbox, vollständiger MIT-RTF-Text) → Zielordner (Pfadauswahl + Desktop-Shortcut-Haken) → Bereit → Installation → „Setup abgeschlossen"; danach 153 Dateien in C:\Program Files\DoubleOut sowie Desktop- und Startmenü-Verknüpfung im wineprefix nachgewiesen. |
||
| .github/workflows | ||
| cmake | ||
| core | ||
| docs | ||
| tests | ||
| tools | ||
| ui | ||
| .clang-format | ||
| .gitignore | ||
| CMakeLists.txt | ||
| LICENSE | ||
| README.md | ||
DoubleOut
Nativer Desktop-Darts-Scorer mit modernem Dark-UI — inspiriert vom Klassiker n01, mit interaktiver Vektor-Dartscheibe, Checkout-Guide, CPU-Bot, Telemetrie und Audio-Caller.
| Spielansicht | Match-Setup |
|---|---|
![]() |
![]() |
Features
- X01 komplett: 301–1001 · In: Straight / Double / Master · Out: Straight / Double / Master
- Eigener Fensterrand: rahmenloses Fenster mit eigener Titelzeile (Ziehen, Maximieren, Fenster-Buttons, Resize an allen Kanten) und konsistentem Design-System — Titelzeile, Karten, Controls und Overlays aus einem Token-Satz
- Sets & Legs: First-to-Ziele frei konfigurierbar, 1–8 Spieler bzw. Teams, Starter rotiert
- CPU-Bot mit einstellbarem 3-Dart-Average (30–110) und Gauß-Streuung über die echte Brettgeometrie — Misses entstehen natürlich, der Bot spielt bust-sicher
- Eingabe jederzeit umschaltbar: Quick-Mode (
140+ ⏎), Dart-by-Dart (T20+ ⏎) oder Klick direkt auf die Scheibe - Lückenloses Undo/Redo pro Dart und pro Aufnahme — auch über Leg-/Set-Grenzen; Smart-Undo nimmt die Bot-Antwortdarts gleich mit
- Interaktive Vektor-Dartscheibe mit offizieller WDF-Geometrie, Hover-Feedback, Dart-Pins der laufenden Aufnahme und Heatmap
- Dynamischer Checkout-Guide ab Rest ≤ 170, mit sofortiger Neuberechnung nach jedem Dart (z. B. nach verfehltem Triple)
- Telemetrie: 3-Dart-Ø · First-9-Ø · Checkout-Quote · 100+/140+/180 · Score-Verlaufsgraph
- TV-Modus: separates Vollbild-Scoreboard für Zweitbildschirm/Beamer
- Audio-Caller — eigene WAV-Samples, Sprachausgabe (Qt TextToSpeech) oder dezente Beeps
- SQLite-Persistenz: Spielerprofile, Matches, Legs und jeder einzelne Wurf
Architektur
Strikte Entkopplung in zwei Module (Details in docs/DESIGN.md):
┌─────────────────────────────────────────────┐
│ DoubleOutUI (Qt 6 Quick) │
│ QML-Views · GameViewModel · Caller · SQLite │
└───────────────────┬─────────────────────────┘
│ nur Core-Header
┌───────────────────▼─────────────────────────┐
│ DoubleOutCore (reines C++20, kein Qt) │
│ Leg · Match · Commands · Checkout · Bot │
│ BoardGeometry · Stats │
└─────────────────────────────────────────────┘
Bauen (Linux)
Voraussetzungen: CMake ≥ 3.25, C++20-Compiler, Qt 6.5+
(qt6-base qt6-declarative qt6-multimedia qt6-speech), Ninja optional.
cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release
cmake --build build
ctest --test-dir build # 3785 Core-Assertions
./build/bin/DoubleOut
Ohne Qt (nur Core + Tests): -DDOUBLEOUT_BUILD_UI=OFF.
Für die Desktop-Integration (Launcher + Icon unter Wayland/X11) zusätzlich
cmake --install build --prefix ~/.local.
Bauen (Windows)
Mit Qt-Online-Installer (Qt 6.5+, Komponenten Qt Quick, Qt Multimedia, Qt Speech, Qt SQL) und aktiver Qt-Konsole:
cmake -S . -B build -DCMAKE_PREFIX_PATH=C:/Qt/6.x.y/msvc2019_64
cmake --build build --config Release
build\bin\Release\DoubleOut.exe
Windows-Build + MSI vom Linux-Host (Cross-Build)
tools/windows/build-windows.sh baut die Windows-EXE samt MSI-Installer
komplett in einem Docker-Container (Fedora mit MinGW-w64 + Qt 6) und
verifiziert anschließend den MSI-Inhalt gegen das Deployment:
./tools/windows/build-windows.sh --wine-smoke
# → build-win/DoubleOut-<Version>-x64.msi
--wine-smokestartet die Windows-EXE zusätzlich unter Wine (Offscreen- Rendering) und prüft, ob sie fehlerfrei bis zum Exit läuft.- Da Fedora kein windeployqt für MinGW-Ziele mitbringt, stellt
tools/windows/deploy.pydas Runtime-Paket selbst zusammen: Import-Closure der EXE/Plugins (Qt-DLLs, MinGW-Runtime, ICU), kuratierte Plugin-Auswahl (qwindows, qoffscreen, SVG/ICO/JPEG, SQLite, Windows-Media-Foundation) und die genutzten QML-Module (QtQuick mit Controls/Basic). - Das MSI wird mit
wixl(msitools) gebaut — WiX v5/v6 scheitern unter Linux an WIX0389 (GetCanonicalRelativePathprüft mitC:\-Root). - Der Installer führt einen kompletten deutschen Assistenten: Willkommen (mit Programm-Erklärung), MIT-Lizenz, Optionsseite mit Pfadauswahl und Desktop-Shortcut-Checkbox, Bereit-seite und Fortschritt. Die UI-Tabellen stammen aus den offiziellen WixUI_InstallDir-Dialogen (WiX-3-Quelle, per candle/mono kompiliert und per msibuild-SQL injiziert). Die EXE wird als Windows-GUI-Subsystem gebaut — kein Konsolenfenster.
Bedienung
| Taste | Aktion |
|---|---|
0–9 |
Ziffern eingeben |
T / D |
Treble/Double für den nächsten Dart (Umschalter) |
⏎ / Numpad-Enter |
Wurf/Aufnahme bestätigen |
M |
Miss (nur Dart-by-Dart) |
B / Shift+B |
Bull 25 / Bullseye 50 |
Backspace |
Ziffer löschen; ohne Buffer: Undo |
Strg+Z / Strg+Y |
Undo / Redo |
Leertaste |
„Game Shot“ bestätigen → nächstes Leg |
Esc |
Eingabe leeren |
| Maus | Feld auf der Scheibe anklicken = Einzeldart |
Versionierung
Die Version hat eine einzige Quelle: project(DoubleOut VERSION x.y.z …) im
Root-CMakeLists.txt. Daraus generiert CMake doubleout/core/Version.hpp:
./DoubleOut --versiongibt die Version aus,- Fenstertitel und Setup-Seite zeigen sie an,
- Builds aus einem Git-Checkout betten zusätzlich
git describe --tags --always --dirty(Stand des Configure-Laufs) ein und zeigen sie als „Build …“ an — bei Tag-Builds also z. B.v0.1.0.
Versionsstoß: project(VERSION …) anheben → Commit → annotierten Tag
vX.Y.Z setzen → neu konfigurieren (cmake -S . -B build).
Sounds
Der Caller sucht pro Phrase eine WAV unter
~/.local/share/DoubleOut/sounds/ (Windows: %APPDATA%\DoubleOut\sounds\),
z. B. t20.wav, d16.wav, s5.wav, 25.wav, 50.wav, miss.wav,
180.wav, gameshot.wav, bust.wav, ton140.wav — Vorlagen siehe
ui/assets/sounds/README.md. Fehlende Dateien
ersetzt die Sprachausgabe (Qt TextToSpeech) oder dezente Beeps.
Daten
Matches landen automatisch in ~/.local/share/DoubleOut/doubleout.sqlite3
(Schema: docs/DESIGN.md).
Projektstruktur
core/ DoubleOutCore — reines C++20: Regeln, Match, Commands, Checkout,
Bot, Geometrie, Statistik (kein Qt)
ui/ DoubleOutUI — Qt-Quick-App: ViewModels, QML-Views, Caller, DB, Icon
tests/ Unit-Tests für den Core (CTest)
tools/ gen_icon.py — erzeugt App-Icon/Logo aus Brettgeometrie
windows/ — Windows-Cross-Build + MSI (Docker, MinGW-Qt6, wixl)
docs/ DESIGN.md — Architektur & Algorithmen · assets/ — Logo & Screenshots
Dev-/Debug-Flags
./build/bin/DoubleOut --smoke out.png --shot-delay 2000 # Bot-Match + Screenshot
./build/bin/DoubleOut --setup-shot out.png # Setup-Seite + Screenshot
./build/bin/DoubleOut --window-size 1920x1080 # Fenstergröße
./build/bin/DoubleOut --dump-tree # QML-Geometrie-Dump
QT_QPA_PLATFORM=offscreen QT_QUICK_BACKEND=software ./build/bin/DoubleOut --smoke out.png
Roadmap
- Cricket-/Shanghai-Modi (Core ist darauf vorbereitet:
Leg::applyThrowist die einzige Einspeisestelle — ideale Anbindung für Automat-Boards via USB/Serial) - Heatmap-Scope umschaltbar (Leg / Match)
- Statistik-Export (die
throws-Tabelle enthält bereits Dart-für-Dart-Daten)
Lizenz
MIT — © 2026 Tronax

