Compare commits

..

23 commits

Author SHA1 Message Date
Lukas Brübach
72aa830e7c [Tests] Link gtest_main on the fetched-gtest path
The downloaded-gtest branch set GTEST_BOTH_LIBRARIES to `gtest` alone, while
FindGTest sets it to both halves. Every test target links that list rather than
picking an entry point, so on this path nothing provides main() and any test
source that does not define its own fails at link with `undefined reference to
main` pointing at crt1.o, naming neither gtest nor the line responsible.

That stayed latent while every test carried its own four-line main(). A test that
omits it now fails, and the error points at the C runtime rather than at gtest,
which is a long way from the cause. Restoring both halves makes the two paths
agree and drops the boilerplate requirement on new test sources.

The 18 sources that still define main() keep linking: gtest_main.cc defines
nothing but main, so the linker leaves its object in the archive unused rather
than reporting a duplicate.
2026-10-10 19:48:21 +02:00
Lukas Brübach
3f9d6d7087 [Tests] Carry one CTest label per test instead of several
gtest_discover_tests() can hand CTest exactly one label. GoogleTestAddTests.cmake
accumulates its generated script with `foreach(arg ${ARGN})`, so a label list reaches
the CTestTestfile as bare `LABELS ci server`, and CTest reads only the first value of a
property and drops the rest without a word.

The `ci` label that is appended to every registered test was therefore absent from every
test that also asked for `server` or `bench`: `ctest -L ci` reported 400 of 469 cases,
and `ctest --print-labels` never listed a second label anywhere in the build.

Reduce each test to exactly one of `ci`, `server`, or `bench`, which is all the
selections need. The three now partition the suite exactly, 400 + 64 + 5 = 469, and
`ctest -LE bench` still means everything but benchmarks. A second label is now a
configure-time FATAL_ERROR rather than a line that quietly means something else.

Anything orthogonal to a test's kind belongs in a helper flag beside the label, so it
composes with the group instead of competing for the single slot.

Also raise DISCOVERY_TIMEOUT off GoogleTestAddTests' 5s default. A plain debug binary
answers --gtest_list_tests in 0.04s, but that budget is thin once several binaries
discover concurrently behind a -j build, and being over it fails at the *link* step with
a bare "Process terminated due to timeout" that points nowhere near the cause.
2026-10-10 19:48:21 +02:00
Lukas Brübach
e8739e175e [Tests] Correct the note on the oracle test compression defines
add_definitions() populates the directory's COMPILE_DEFINITIONS property, which is
consumed at generate time, so it reaches every target in the directory no matter
where it is called relative to add_executable(). The previous note claimed the
flags stayed confined to the benchmark because the find_package block came after
it; oracle_importer_test, created above that block, carries both defines too.

Verified harmless rather than a live bug: HAS_ZLIB and HAS_LZMA gate code only in
oracle/src/pages.cpp and oracle/src/pagetemplates.cpp, and no test target compiles
either. The ordering and the leaked defines are both pre-existing, so this only
corrects the explanation.
2026-10-10 19:48:21 +02:00
Lukas Brübach
b9063a7b86 [Tests] Make QtTest available to test targets
QtTest was not among the modules test targets could link, so the Qt model and
signal contracts had no way to be verified from a test: QAbstractItemModelTester
and QSignalSpy both live there.

Add Test to _TEST_NEEDED in cmake/FindQtRuntime.cmake. That is the single place the
union of test-only Qt modules is declared, so this is the only file that needs to
change to make the module reachable from every test target.

Nothing uses it yet. This lands the capability ahead of the model-layer tests that
need it, so those can be added as tests alone rather than as test plus build-system
plumbing.
2026-10-10 19:48:21 +02:00
Lukas Brübach
3a36b5eea4 [Tests] Register each test case with CTest instead of each test binary
Registering a test cost four edits across a dozen CMakeLists files: add_test,
add_executable, a conditional add_dependencies on gtest, and target_link_libraries.
The conditional branch was the trap -- it is only needed when GTest was fetched and
add_subdirectory'd, and omitting it yields undefined gtest symbols at link time --
so it was easy to leave out and impossible to notice until the link failed.

Fold all four steps into cockatrice_add_test() and migrate every test directory
onto it, with a cockatrice_add_manual_test() wrapper for the three benchmarks that
are built but deliberately kept out of ctest. The calls now read as a declaration
of what a test is rather than a transcript of how to register one.

While rewriting the registrations, replace add_test(NAME x COMMAND x) with
gtest_discover_tests(). Naming the binary as a single CTest entry meant a CI failure
reported only which binary failed, and ctest -R Suite.Case could not select an
individual case. Discovery raises the suite from 35 opaque entries to 469 real ones:
ctest -R ThemeMigrationTest.IsIdempotent now runs exactly that case, and
ctest -L server / -LE bench work off labels applied at registration.

Give every test a 60s TIMEOUT. CTest's implicit default is 1500s, so one hung
socket wait would stall CI for 25 minutes, and single_instance_manager_test already
does real QLocalSocket waits.

Dropping per-case granularity costs wall-clock time, since the suite becomes
process-spawn bound rather than CPU bound: serial ctest went from 3.8s to 30.8s. Run
it with -j in CI to recover it -- 7.6s at -j4, and 3.5s at -j8, both at or below
the old serial time. The binaries are parallel-safe: the only test claiming a fixed
resource scopes its local socket name to its own pid, so concurrent copies cannot
collide.

Also delete dummy_test, which asserted 1 == 1 and only proved the harness was
wired up -- something the other 468 cases already establish.

No test is added, removed, or changed by this commit; the 469 cases are the same
ones the 35 binaries contained.
2026-10-10 19:48:21 +02:00
ebbit1q
efc7e7a079
fix the desktop file, removing the invalid key (#7406)
Some checks failed
CodeQL / Analyze (cpp) (push) Waiting to run
CodeQL / Analyze (actions) (push) Waiting to run
Build Docker / Servatrice (arm) (push) Waiting to run
Build Docker / Servatrice (x86) (push) Waiting to run
Build Docker / Publish multi-platform Servatrice image (push) Blocked by required conditions
Build Desktop / Configure (push) Has been cancelled
Build Desktop / Debian 13 (push) Has been cancelled
Build Desktop / Debian 12 (push) Has been cancelled
Build Desktop / Fedora 44 (push) Has been cancelled
Build Desktop / Fedora 43 (push) Has been cancelled
Build Desktop / Servatrice_Debian 12 (push) Has been cancelled
Build Desktop / Ubuntu 26.04 (push) Has been cancelled
Build Desktop / Ubuntu 24.04 (push) Has been cancelled
Build Desktop / Arch (push) Has been cancelled
Build Desktop / macOS 13 Intel (push) Has been cancelled
Build Desktop / macOS 14 (push) Has been cancelled
Build Desktop / macOS 15 (push) Has been cancelled
Build Desktop / macOS 26 Debug (push) Has been cancelled
Build Desktop / Windows 10 (push) Has been cancelled
* fix the desktop file, removing the invalid key

* Update cockatrice.desktop

---------

Co-authored-by: BruebachL <44814898+BruebachL@users.noreply.github.com>
2026-10-10 17:15:10 +02:00
BruebachL
be2c16eca5
[UI] Fix auto-completion acceptance on Space/Tab/Enter (#7466)
* [UI] Fix auto-completion acceptance on Space/Tab/Enter

* [UI] Accept current completion when no item selected in popup

* [UI] Also accept completion on focus out when none selected

* [UI] Keep focus in chat on Tab completion acceptance

* [UI] Prevent Tab from moving focus when no completion popup

* [UI] Refocus on Tab when completing

* [UI] Let focusOut handle Tab completion acceptance

* [UI] Restore Tab behavior to match original (handle in focusOut)

* [UI] Defer refocus on Tab to avoid focus chain issues

* [UI] Auto-select first completion match in popup

* [UI] Auto-select first match when completer popup resets

* Revert "[UI] Auto-select first match when completer popup resets"

This reverts commit c7a3de3595.

* Revert "[UI] Auto-select first completion match in popup"

This reverts commit ae0dfb8622.

* [UI] Ensure completion selection updates on model changes

* Revert "[UI] Ensure completion selection updates on model changes"

This reverts commit 686bbef5b2.

* [UI] Highlight the selected completion in chat popups

The card completer's above-variant moved the current row with
NoUpdate, so the delegate never painted the selection border, and it
used Select which accumulated highlights while navigating. Use
ClearAndSelect so only the current row is highlighted and the old one is
cleared.

The mention popup opened with no current row at all, so nothing was
highlighted and there was no visual hint of what Enter would insert.
Select the row currentCompletion() uses, and install a delegate that
mirrors the active highlight into the inactive group so the selection
stays visible when the transient popup is not the active window.

---------

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2026-10-10 09:45:42 +02:00
BruebachL
b8e8f2c738
[PrintingSelector] Fix crash setting all printings to preferred (#7467)
getPreferredPrinting returns a null PrintingInfo when a deck card has no
database entry or printings. SetProviderIdToPreferred dereferenced
getSet() unconditionally, crashing on custom or unresolved cards.

Guard against a null preferred set and leave the card's cleared printing
data as is.

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2026-10-10 09:36:26 +02:00
BruebachL
1e1f79db0d
[Windows] Wait for uninstaller, rework .dll bundling, add logging (#7407)
Some checks are pending
CodeQL / Analyze (cpp) (push) Waiting to run
CodeQL / Analyze (actions) (push) Waiting to run
Build Desktop / Configure (push) Waiting to run
Build Desktop / Debian 13 (push) Blocked by required conditions
Build Desktop / Debian 12 (push) Blocked by required conditions
Build Desktop / Fedora 44 (push) Blocked by required conditions
Build Desktop / Fedora 43 (push) Blocked by required conditions
Build Desktop / Servatrice_Debian 12 (push) Blocked by required conditions
Build Desktop / Ubuntu 26.04 (push) Blocked by required conditions
Build Desktop / Ubuntu 24.04 (push) Blocked by required conditions
Build Desktop / Arch (push) Blocked by required conditions
Build Desktop / macOS 13 Intel (push) Blocked by required conditions
Build Desktop / macOS 14 (push) Blocked by required conditions
Build Desktop / macOS 15 (push) Blocked by required conditions
Build Desktop / macOS 26 Debug (push) Blocked by required conditions
Build Desktop / Windows 10 (push) Blocked by required conditions
Build Docker / Servatrice (arm) (push) Waiting to run
Build Docker / Servatrice (x86) (push) Waiting to run
Build Docker / Publish multi-platform Servatrice image (push) Blocked by required conditions
* [Windows] Purge every runtime DLL on upgrade instead of a named few

A user updating from 3.0.2 to 3.1 got "abseil_dll.dll is either not designed
to run on Windows or it contains an error" and could not start the client.

abseil_dll.dll comes from vcpkg, not Qt. It rides into the install directory
on the "*.dll" glob in cockatrice/CMakeLists.txt, alongside libprotobuf.dll,
liblzma.dll and z.dll, and none of those were named in the upgrade purge. So
on an upgrade the old uninstaller's RMDir /r skipped whichever of them was
locked, the purge did not look for them, HasStaleRuntimeFiles did not look
for them either, and the installer reported success - having written the new
executables next to the previous version's protobuf runtime. Windows then
refused to load it.

The mask list was also already wrong where it existed: it matches zlib*.dll
while vcpkg ships z.dll.

Delete every top-level DLL instead of naming library families. The payload is
written after the purge, so a DLL the new build still needs is put straight
back; what the purge has to guarantee is only that nothing from the previous
build is left to be loaded next to the new executables. Enumerated families
cannot do that - every transitive dependency that arrives between two
releases is one more name to forget, and the three previous rounds of this
work each reasoned about Qt because that is what the reports named at the
time.

HasStaleRuntimeFiles collapses to the matching *.dll probe, so the abort
fires on any survivor rather than only on the families it was told about.

IsExistingCockatriceInstall stays on Qt6*.dll on purpose: it decides whether a
directory is ours at all, and a folder that merely holds some DLLs of its own
must not be purged. Qt6*.dll is enough even when only the protobuf runtime
survived, because the whole Qt set is mapped by the same process that maps
abseil_dll.dll and so is locked or free with it.

* [CI] Assert the whole Windows runtime, not just the Qt modules

required-qt-runtime.txt listed only the Qt modules COCKATRICE_QT_MODULES
names, so it could not see any other runtime go missing. The three previous
rounds of installer work all reasoned about Qt*.dll because that was all the
build knew how to ask about, and the one runtime that actually broke the
reported upgrade - abseil_dll.dll - was outside the set entirely.

- Rename it to required-runtime.txt and take the third party runtime names
  from the vcpkg bin directory the app-local copies come from, so a
  dependency bump cannot leave the list behind and a versioned name such as
  libcrypto-3-x64.dll becoming libcrypto-4-x64.dll cannot either
- Union the three applications' module lists rather than the client's alone:
  Servatrice contributes Qt6Sql.dll, servatrice.exe is installed next to
  cockatrice.exe and cannot start without it, and nothing asserted it
- Add Core to the client's module list. It is the one module nothing can do
  without and it only ever arrived transitively, so Qt6Core.dll was shipped
  and never checked - the new unknown-runtime check flagged it on the first
  run
- Fail the build on a missing runtime, as before, and warn on a runtime
  nothing requires. Only the test framework is a hard failure there: "no
  shipped executable links gtest" is a fact, whereas a runtime missing from
  the manifest may be one the manifest failed to derive, and a check that has
  never run before should not be able to block a release

The warning is meant to be read. Qt6::Quick pulls in Qml, QmlModels,
QmlWorkerScript, QuickBasic, QuickTemplates2 and OpenGL transitively and none
are named, so the manifest is known to be a partial list; the first Windows
run reports the real one, which is evidence rather than a guess about what Qt
links. Fold that back in when it lands.

* [CI] Stop deriving the required runtime from the vcpkg bin directory

The first Windows run of this check failed, and the seven files it named as
missing are not runtime at all: gmock.dll, gmock_main.dll, legacy.dll,
libprotobuf-lite.dll, libprotoc.dll and pthreadVC3/VCE3/VSE3.dll. None of them
is linked by any shipped executable, so a correct package leaves them out.

vcpkg_installed/x64-windows/bin is everything vcpkg installed, not everything
the applications import. The protoc compiler, the GoogleMock library, a port
tool and three CMake FindThreads probes sit beside the genuine runtimes, and a
directory listing cannot tell them apart. Asserting it fails the build over a
package that is right - which is what happened, and it is the same mistake as
the one that produced this bug report: reasoning about a list of names instead
of about the build.

The real source of truth is the three executables' import tables, which
fixup_bundle already walks to decide what to copy. Until CMake can read that
result, the Qt half is what can be derived honestly, from the same module lists
the targets are built against. So assert that, and report the rest rather than
require it:

- Drop the vcpkg bin glob, its gtest filter and the vcpkg-runtime-known marker.
  All three existed only to support the glob.
- Report top level DLLs the manifest does not name without failing. These are
  expected: protobuf, Abseil, OpenSSL, liblzma, ffmpeg and the Qt debug DLLs all
  arrive on the build output glob because nothing in the build declares them by
  name. The list is a report of what the package carries, not a verdict, and it
  is how the missing Qt6Qml/Quick/OpenGL entries above became visible.
- Report a leaked gtest or gmock instead of failing on it. "No shipped
  executable links this" is a fact, but a check that has never passed on a real
  package has not earned the right to block a release, and the first run of an
  enforcing version is exactly when its own wrong assumptions show up.
- Skip DLLs under a subdirectory, which are platform plugins rather than
  imported runtimes, and the NSIS plugins, which extract to $PLUGINSDIR and so
  reach the comparison looking like payload.

Verified against the paths 7-Zip actually listed in the failing package: the
check passes on it, still fails when Qt6Sql.dll or the qwindows plugin is
removed, and still reports gtest.dll and gmock.dll if either is added.

The purge in cmake/NSIS.template.in covers the runtimes the manifest does not
name. That fix is independent of any list and is what makes the reported update
failure go away.

* [Installer] Fix the /R upgrade aborting before it does anything

WaitForLauncherToExit read the wrong registers. System.dll writes its
.rN outputs to $N and its .RN outputs to $RN, but the wait used
p.r0/i.r1 while testing $R1. $R1 therefore stayed empty, and the "did
not exit" test compared "" with "0" - true every time. Every in-app
update passes /PID=, so every upgrade hit AbortInstall before writing
anything; because /R also sets silent, the override just vanished with
exit code 1 and no message. The bug came in with #7372 and is inherited
by this branch, not introduced by it.

Use the uppercase .RN forms, and treat a null or plugin-failed
OpenProcess as the launcher already being gone - the case the old
${Errors} check never caught, because System.dll does not set the NSIS
error flag from the callee's return value.

Also restore the abort dialog for the in-app updater: AbortInstall and
the two inline warnings gated their message box on ${IfNot} ${Silent},
which is false for a /R upgrade, so any abort on that path was equally
silent. The unattended case is a /S install without /R, not /R, so show
the box for $ReinstallMode = 1 or an interactive install. The
stale-runtime abort now goes through AbortInstall so that decision
lives in one place.

* [Installer] Log every upgrade step to %TEMP%\Cockatrice-installer.log

* [Installer] Actually append to the upgrade log (FileSeek END)

* [Installer] Wait for the old uninstaller before replacing files

An NSIS uninstaller copies itself to %TEMP% and runs from there so that it
can delete its own directory; the process the installer started exits
immediately. A plain ExecWait therefore returns before the uninstall has
run, and the temp copy's "RMDir /r $INSTDIR" then executes concurrently
with the install section, deleting files the payload just wrote. That is
why an upgrade could leave Qt6Core/Gui/Multimedia and the other
alphabetically-first DLLs missing while the tail of the directory survived:
a recursive delete marching from the front while the final listing ran.

Pass _?=$INSTDIR to the old uninstaller so it runs in place and ExecWait
actually blocks until the uninstall completes. _?= must be the last
argument and unquoted, even for paths with spaces. Applied to both the
silent /R path (AutoUninstallIfNeeded) and the interactive path
(componentsPagePre).

* [Installer] Tighten the wording of the upgrade comments

Drop the dash-heavy phrasing from the comments this PR adds, and say plainly
in the _?= comment that ExecWait returns before the old uninstaller has run
and the temp copy then deletes the payload the section is still writing.

---------

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2026-10-09 20:09:34 +02:00
BruebachL
bb61617d42
[Versioning] Bump version number for 3.1.1 beta release. (#7464)
Some checks are pending
CodeQL / Analyze (cpp) (push) Waiting to run
CodeQL / Analyze (actions) (push) Waiting to run
Build Desktop / Configure (push) Waiting to run
Build Desktop / Debian 13 (push) Blocked by required conditions
Build Desktop / Debian 12 (push) Blocked by required conditions
Build Desktop / Fedora 44 (push) Blocked by required conditions
Build Desktop / Fedora 43 (push) Blocked by required conditions
Build Desktop / Servatrice_Debian 12 (push) Blocked by required conditions
Build Desktop / Ubuntu 26.04 (push) Blocked by required conditions
Build Desktop / Ubuntu 24.04 (push) Blocked by required conditions
Build Desktop / Arch (push) Blocked by required conditions
Build Desktop / macOS 13 Intel (push) Blocked by required conditions
Build Desktop / macOS 14 (push) Blocked by required conditions
Build Desktop / macOS 15 (push) Blocked by required conditions
Build Desktop / macOS 26 Debug (push) Blocked by required conditions
Build Desktop / Windows 10 (push) Blocked by required conditions
Build Docker / Servatrice (arm) (push) Waiting to run
Build Docker / Servatrice (x86) (push) Waiting to run
Build Docker / Publish multi-platform Servatrice image (push) Blocked by required conditions
Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2026-10-09 11:35:35 +02:00
BruebachL
a44757bd11
[Client] Improve card database update visibility (#7458)
* [Client] Improve card database update visibility

Addresses Cockatrice/Cockatrice#7431.

Cockatrice previously offered no in-client feedback while the card
database updater ran: the only progress UI lived in the first-run
wizard, stderr/stdout were not parsed in interactive runs, and starting
a second update with Oracle already open or with a hidden background run
active just showed a confusing 'already running' guard - even though
Oracle is launched as a separate process with no lifecycle tracking.

- Add a status-bar widget (CardDatabaseUpdateStatusBar) that appears
  while an update runs and shows the Downloading/Parsing/Importing
  stages with percent progress; it is also used in the quit-confirm
  prompt so users see an unfinished update before cancelling it.
- Parse the updater's PROGRESS lines (new CardUpdateProgressParser,
  unit-tested) in both foreground and background runs and log stage
  changes to the new card_database.update category, throttled to at
  most one line per second; forward Oracle stderr to the logs.
- Show a tray balloon when a background update starts and on finish or
  failure instead of staying silent.
- Request a running Oracle instance to raise itself (QLocalServer
  CockatriceOracleRaise-<user>) when the user starts another update, and
  demote the 'already running' guard to an informative message only when
  no running instance can be found.
- Emit download/scan/import progress unconditionally from Oracle so
  interactive and background runs behave the same.
- Document the new log category in the troubleshooting guide.

* [Client] Address card database update review feedback

* [Client] Add setting to control card database update tray notifications

* [Client] Address remaining card database update review nits

- Rename card_update_progress_parser.{h,cpp} to card_update_progress.{h,cpp}
- Store the CardUpdateProgress struct in the status bar widget

* Lint.

---------

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2026-10-09 11:07:48 +02:00
BruebachL
6bed5d6f67
[Style] Warn about the broken Windows native styles and stop resolving System to them (#7461)
* [Style] Fall back to the built-in windows style instead of windowsvista

The Windows Vista native style is broken the same way as the Windows 11 one,
so the sanitizer now catches both and falls back to the built-in QWindowsStyle
instead of the Vista plugin. The style picker no longer offers either.

* [Style] Keep Windows native styles selectable but warn about them

---------

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2026-10-09 11:07:22 +02:00
BruebachL
205e1ecebf
[CardDB] Keep parse-time set filtering and bust the cache on enablement changes (#7448)
Some checks are pending
CodeQL / Analyze (cpp) (push) Waiting to run
CodeQL / Analyze (actions) (push) Waiting to run
Build Desktop / Configure (push) Waiting to run
Build Desktop / Debian 13 (push) Blocked by required conditions
Build Desktop / Debian 12 (push) Blocked by required conditions
Build Desktop / Fedora 44 (push) Blocked by required conditions
Build Desktop / Fedora 43 (push) Blocked by required conditions
Build Desktop / Servatrice_Debian 12 (push) Blocked by required conditions
Build Desktop / Ubuntu 26.04 (push) Blocked by required conditions
Build Desktop / Ubuntu 24.04 (push) Blocked by required conditions
Build Desktop / Arch (push) Blocked by required conditions
Build Desktop / macOS 13 Intel (push) Blocked by required conditions
Build Desktop / macOS 14 (push) Blocked by required conditions
Build Desktop / macOS 15 (push) Blocked by required conditions
Build Desktop / macOS 26 Debug (push) Blocked by required conditions
Build Desktop / Windows 10 (push) Blocked by required conditions
Build Docker / Servatrice (arm) (push) Waiting to run
Build Docker / Servatrice (x86) (push) Waiting to run
Build Docker / Publish multi-platform Servatrice image (push) Blocked by required conditions
The parsers keep dropping printings for disabled sets so that disabling a
set hides them everywhere, not just in deck editor search. The cached parse
output therefore depends on enablement, which the source hash did not cover:
the first parse froze whatever enablement state existed at that moment and
later toggles hit the stale cache.

- Fold a parser schema version and the sorted enabled set names into the
  binary cache source hash so toggling a set or enabling newly discovered
  sets (including custom ones) forces a re-parse on the next load.
- Harden the legacy set migration to only write keys that exist so missing
  legacy values can no longer clobber cardDatabase.ini and silently disable
  sets on upgrade.
- Make CardDatabase::reloadCardDatabasesAndNotify() bypass the binary cache
  so an explicit reload always re-reads the files on disk, even when their
  size/mtime hash still matches.
- Cover cache invalidation end to end: sandboxed loads assert that disabling
  a set, adding a custom database and enabling a fresh set each rewrite the
  cache, that a no-op load keeps it, and that an explicit reload picks up
  edits the source hash cannot see.

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2026-10-09 06:09:18 +02:00
BruebachL
aaafa72c0e
[Game] Use native title bar height for ZoneViewWidget close button (#7450)
* [Game] Use native title bar height for ZoneViewWidget close button

Compute title bar height from style (PM_TitleBarHeight) instead of hardcoded 24.0 to align hit box with native close button.

* [Game] Fix ZoneViewWidget title bar height compile errors

Drop the redundant static on the anonymous namespace helper, stop
redeclaring titleBarHeight's parameter and reuse tbh in the fallback
path, and restore the position clamp that still referenced the removed
kTitleBarHeight constant.

---------

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2026-10-09 06:08:15 +02:00
BruebachL
56c456414b
[Game] Use non-blocking popup for zone context menus (#7452)
Replace QMenu::exec with popup() for zone context menus to avoid blocking the scene.

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2026-10-09 06:07:39 +02:00
BruebachL
95f02ac0a1
[CardDB] Drop the rebalanced-cards setting entirely (#7457)
* [CardDB] Drop rebalanced-card filtering from the v4 parser

Rebalanced cards no longer exist, so the includeRebalancedCards
preference has no data to filter. Always keep printings marked
isRebalanced and remove the now-unused ICardPreferenceProvider
plumbing from CockatriceXml4Parser and CardDatabaseLoader.

The setting itself (CardsDisplaySettings, Manage Sets checkbox,
Oracle attribute mapping) is removed in a follow-up.

* [CardDB] Drop the rebalanced-cards setting entirely

Rebalanced Alchemy cards no longer exist, so remove the
includeRebalancedCards preference surface: the CardsDisplaySettings
getter/setter/signal, the ICardPreferenceProvider and
ICardsDisplaySettingsProvider methods, the Manage Sets checkbox, the
legacy settings migration mapping, the isRebalanced attribute mapping
in the Oracle importer, and the isRebalanced attribute in the v4
schema.

Builds on #7448, which already stopped the v4 parser from filtering
on the preference.

* [CardDB] Drop the unused isOnlineOnly printing property

The Arena-card detection switched from isOnlineOnly to isRebalanced in
#5778, so nothing has read this printing property since; it only
round-trips from the Oracle importer into cards.xml. Remove the
importer mapping, the benchmark fixture field and the v4 schema
attribute so regenerated databases stop carrying it.

---------

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2026-10-09 06:02:47 +02:00
BruebachL
d0fc27e3a8
[Security] Harden network input handling and websocket proxying (#7076)
Some checks are pending
CodeQL / Analyze (cpp) (push) Waiting to run
CodeQL / Analyze (actions) (push) Waiting to run
Build Desktop / Configure (push) Waiting to run
Build Desktop / Debian 13 (push) Blocked by required conditions
Build Desktop / Debian 12 (push) Blocked by required conditions
Build Desktop / Fedora 44 (push) Blocked by required conditions
Build Desktop / Fedora 43 (push) Blocked by required conditions
Build Desktop / Servatrice_Debian 12 (push) Blocked by required conditions
Build Desktop / Ubuntu 26.04 (push) Blocked by required conditions
Build Desktop / Ubuntu 24.04 (push) Blocked by required conditions
Build Desktop / Arch (push) Blocked by required conditions
Build Desktop / macOS 13 Intel (push) Blocked by required conditions
Build Desktop / macOS 14 (push) Blocked by required conditions
Build Desktop / macOS 15 (push) Blocked by required conditions
Build Desktop / macOS 26 Debug (push) Blocked by required conditions
Build Desktop / Windows 10 (push) Blocked by required conditions
Build Docker / Servatrice (arm) (push) Waiting to run
Build Docker / Servatrice (x86) (push) Waiting to run
Build Docker / Publish multi-platform Servatrice image (push) Blocked by required conditions
- TCP client connections: reject messages whose declared length is
  negative or exceeds a 1.5MB cap immediately instead of buffering
  indefinitely, preventing unbounded memory growth and the previously
  stuck state caused by negative lengths overflowing the int header.
- ISL connections: apply the same length validation with a 4MB cap,
  disconnecting the peer on an implausible length.
- Websockets: only trust the forwarded client-address header (e.g.
  X-Forwarded-For) when the websocket connection originates from an
  address in security/trusted_sources. Previously any client could
  spoof its address to bypass bans, user limits and rate limiting.

Took 3 minutes

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2026-10-08 23:18:47 +02:00
BruebachL
514014dc00
[Completer] Stop line edit rewrite on popup highlight (#7447)
Some checks are pending
CodeQL / Analyze (cpp) (push) Waiting to run
CodeQL / Analyze (actions) (push) Waiting to run
Build Desktop / Configure (push) Waiting to run
Build Desktop / Debian 13 (push) Blocked by required conditions
Build Desktop / Debian 12 (push) Blocked by required conditions
Build Desktop / Fedora 44 (push) Blocked by required conditions
Build Desktop / Fedora 43 (push) Blocked by required conditions
Build Desktop / Servatrice_Debian 12 (push) Blocked by required conditions
Build Desktop / Ubuntu 26.04 (push) Blocked by required conditions
Build Desktop / Ubuntu 24.04 (push) Blocked by required conditions
Build Desktop / Arch (push) Blocked by required conditions
Build Desktop / macOS 13 Intel (push) Blocked by required conditions
Build Desktop / macOS 14 (push) Blocked by required conditions
Build Desktop / macOS 15 (push) Blocked by required conditions
Build Desktop / macOS 26 Debug (push) Blocked by required conditions
Build Desktop / Windows 10 (push) Blocked by required conditions
Build Docker / Servatrice (arm) (push) Waiting to run
Build Docker / Servatrice (x86) (push) Waiting to run
Build Docker / Publish multi-platform Servatrice image (push) Blocked by required conditions
* [Completer] Stop line edit rewrite on popup highlight

* [Completer] Extract the completion index into a variable

Make the popup selection update readable at a glance.

---------

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2026-10-08 14:38:11 +02:00
BruebachL
870ab23608
[Tooling] Add IWYU Qt6 mapping, generator, and runner script (#7454)
Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2026-10-08 11:17:01 +02:00
BruebachL
d603a2bb6a
[Tooling] Apply include-what-you-use across the tree (#7396)
* [DeckList] Apply include-what-you-use to libcockatrice_deck_list

* [IWYU] Apply include-what-you-use across the tree

Run one whole-tree IWYU pass over the libcockatrice_* libraries, the
Cockatrice client, Oracle, Servatrice and the test suite, so each
translation unit includes what it uses directly and forward-declares
what it does not need.

IWYU only analyses real translation units, never the moc code CMake
generates from Q_OBJECT headers, so it strips includes that moc output
silently relies on. Where a type is passed by value (or nested in a
QList/QMap) in a signal or slot signature, the generated moc code needs
the complete type; those includes are kept with an explanatory
`// IWYU pragma: keep`. The same holds for Q_DECLARE_METATYPE targets
such as QSqlDatabase.

A handful of includes are added by hand where callers brace-initialize a
const-reference parameter, which also requires the complete type.

Applied as a single commit on purpose: stripping includes from the
libcockatrice_* headers is precisely what breaks the client, test and
server translation units, and the fixes for those live in the same
translation units. Splitting by component would therefore leave
intermediate commits that do not compile.

All 426 modified Q_OBJECT/Q_GADGET headers were verified to be
moc-self-contained by compiling each generated moc_*.cpp standalone;
several built only because of moc include ordering in
mocs_compilation.cpp before the keep-includes were added.

* [Tooling] Emit public Qt headers and fix IWYU fallout CI found

Three problems the local build could not see, all because a green local
build only proves the configuration it was run under.

Private Qt headers. IWYU emitted private, lowercase Qt headers, and
qtypes.h does not exist at all before Qt 6.9, so the Debian 12 and
Ubuntu 24.04 jobs on Qt 6.4.2 failed to compile. The generator only
emitted a mapping when the capital header name mirrored the private one
(QAbstractAnimation for qabstractanimation.h), so qtypes.h, which is
wrapped by QtTypes instead, got no mapping and kept the private
spelling. Map it explicitly to <QtTypes>, which is public since Qt 5 and
provides the same typedefs either way, and rewrite the 100 affected
includes.

Do not generalize this to "prefer any Qt* wrapper". The table is
generated from whichever Qt is installed, and the wrappers are not
equally old: QtLogging only appeared in Qt 6.8 and QtMinMax in 6.5, so
that heuristic trades one breakage for another. Every other lowercase
header still in the tree has shipped publicly since Qt 5, so those are
left alone.

Platform-guarded includes. IWYU only sees the preprocessor configuration
it is handed, so it dropped an include that only the macOS branch of
main.cpp needs, and the macOS jobs failed on an undeclared
UrlSchemeEventFilter. Restore the include. Force-compiling every file
that carries a platform guard under Q_OS_MAC, Q_OS_MACOS and __APPLE__
reports nothing else, so the macOS branches are covered rather than
assumed.

shellcheck. Drop a leftover variable and stop assigning the
include-what-you-use lookup, which was only ever an existence check.

* [Tooling] Map Qt 6.5+ split headers to QtGlobal for Qt 6.4 compatibility

IWYU emitted QtTypes, QtPreprocessorSupport, QtVersionChecks, QtAssert,
QtMinMax, QtClassHelperMacros, QtEnvironmentVariables and QtTranslation.
Qt 6.5 split those declarations out of qglobal.h into separate headers, so
neither the Qt* wrapper nor the q*.h private name exists on the oldest Qt we
support (6.4.2), and Debian 12 / Ubuntu 24.04 fail with "No such file or
directory". qtypes.h is worse still: it only appeared in Qt 6.9.

QtGlobal is the one spelling that works across the whole supported range. It
has been public since Qt 5, defines these declarations itself up to Qt 6.4, and
includes the split headers from Qt 6.5 on, so redirect all eight private
headers to it and collapse the affected includes in the tree.

Curated overrides now take precedence over the name-mirroring rule, which
cannot know about Qt version floors because the mapping is generated from
whatever Qt is installed. That rule was mapping qtversionchecks.h to
<QtVersionChecks> even with an override present, because the override was only
consulted as a fallback. A curated key that matches nothing is now a hard
error rather than a silent fallback, and the redirected headers are no longer
advertised as the home of a symbol.

Verified every Qt include in the tree resolves against the real
qt6-base-dev 6.4.2 package: 15 distinct includes, 0 missing.

* [Tooling] Map QOverload to QtGlobal and drop the QMetaMethodArgument include

Two more headers IWYU emitted do not exist on Qt 6.4.2:

QOverload was split out of qglobal.h in Qt 6.5, so on 6.4.2 it is declared in
qglobal.h directly and the standalone header is a hard error. QtGlobal covers
both, so map qoverload.h to it like the other 6.5+ split headers.

QMetaMethodArgument is never referenced anywhere in the tree. It is a bare
forwarder for qobjectdefs.h that our generator advertised as a class symbol,
which is how IWYU came to add the include at all. The symbol mappings are
generated from header names, so they cannot tell a forwarder that happens to be
capitalised from a real class; removing the unused include is the fix, and the
generic case stays a known limitation of the generator.

Extending the audit to every Q* header (an earlier pass only matched headers
starting with "Qt" or lowercase q*.h, so it missed all of them) against the real
qt6-base-dev, qt6-multimedia-dev, qt6-declarative-dev, qt6-svg-dev and
qt6-websockets-dev 6.4.2 packages: 341 distinct Qt includes, 0 missing.

* [Game] Give moc the complete CardItem type in player_actions.h

player_actions.h forward declares CardItem but passes QList<CardItem *> by
value in actPlay/actPlayFacedown/actHide. moc instantiates the metatype for
those parameters, and on Qt 6.4 that expands to sizeof(CardItem), so Ubuntu
24.04 fails with "invalid application of 'sizeof' to incomplete type
'CardItem'". Newer Qt tolerates the incomplete type, which is why only the
6.4.2 jobs failed.

Include the defining header with an IWYU pragma keep, matching how the other
MOC-required includes in this area are handled.

* [Game] Give moc the complete ServerInfo_Card type

player_logic.h, game_scene.h, view_zone.h and view_zone_widget.h forward
declare ServerInfo_Card but pass QList<const ServerInfo_Card *> through signal
and slot signatures. moc instantiates the metatype for those parameters, which
Qt 6.4 expands to sizeof(ServerInfo_Card), so the connect in game_scene.cpp
fails on Debian 12 and Ubuntu 24.04 with "invalid application of 'sizeof' to
incomplete type 'const ServerInfo_Card'". Newer Qt tolerates it, so only the
6.4.2 jobs failed.

Include the generated protobuf header with an IWYU pragma keep, following the
pattern already used for ServerInfo_Player and ServerInfo_User in
game_event_handler.h.

* [Client] Complete the types Qt 6.4 needs for connect and moc

Qt 6.4 expands QMetaType::fromType on the normalised argument list of a
PMF connect and on moc-generated metatypes, which requires sizeof on every
signal and slot parameter. Newer Qt tolerates forward declarations there,
so only the Debian 12 and Ubuntu 24.04 jobs failed, with
"invalid application of 'sizeof' to incomplete type" for QMouseEvent,
QPrinter and GameReplay.

Replace the forward declarations with the real includes:

- QMouseEvent in the nine widget headers that pass it through signals
- QPrinter in abstract_tab_deck_editor.cpp, for the actPrintDeck lambda
- game_replay.pb.h in tab_replays.h. GameReplay is a protobuf message, so
  the project's game/replay.h only forward declares it and cannot supply
  the complete type.

Found by recompiling all 1918 project TUs against the Debian Qt 6.4.2
headers, which reproduces those two CI jobs locally in one pass.

* [Client] Complete Release and QMenu for Qt 6.4 moc and connect

Continuing the Qt 6.4 complete-type sweep:

- window_main.cpp connects ClientUpdateChecker::finishedCheck to
  MainWindow::checkClientUpdatesFinished, whose Release * parameter made
  moc 6.4 instantiate the metatype. GameReplay turned out to be a protobuf
  message, so Release likewise needed release_channel.h in the three
  headers declaring those signals: window_main.h, dlg_update.h and
  client_update_checker.h.
- moc 6.4 also needs sizeof(QMenu) for the QList<QMenu *> carried by
  TabSupervisor::setMenu and MainWindow::updateTabMenu.

Verified by regenerating moc output with the Debian moc 6.4.2 for all 434
Q_OBJECT/Q_GADGET classes and compiling it, plus recompiling all 1612
source TUs, against the Qt 6.4.2 headers: no remaining failures.

---------

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2026-10-08 11:13:50 +02:00
BruebachL
b1f4d1e99d
[UI] Flip tear-off menus default to off (#7449)
Detach menus no longer default to tear-off; users can re-enable in settings.

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2026-10-08 10:51:03 +02:00
BruebachL
d0991b68f6
[EDHRec] Update tab title when a card is searched (#7408)
Some checks are pending
CodeQL / Analyze (cpp) (push) Waiting to run
CodeQL / Analyze (actions) (push) Waiting to run
Build Desktop / Configure (push) Waiting to run
Build Desktop / Debian 13 (push) Blocked by required conditions
Build Desktop / Debian 12 (push) Blocked by required conditions
Build Desktop / Fedora 44 (push) Blocked by required conditions
Build Desktop / Fedora 43 (push) Blocked by required conditions
Build Desktop / Servatrice_Debian 12 (push) Blocked by required conditions
Build Desktop / Ubuntu 26.04 (push) Blocked by required conditions
Build Desktop / Ubuntu 24.04 (push) Blocked by required conditions
Build Desktop / Arch (push) Blocked by required conditions
Build Desktop / macOS 13 Intel (push) Blocked by required conditions
Build Desktop / macOS 14 (push) Blocked by required conditions
Build Desktop / macOS 15 (push) Blocked by required conditions
Build Desktop / macOS 26 Debug (push) Blocked by required conditions
Build Desktop / Windows 10 (push) Blocked by required conditions
Build Docker / Servatrice (arm) (push) Waiting to run
Build Docker / Servatrice (x86) (push) Waiting to run
Build Docker / Publish multi-platform Servatrice image (push) Blocked by required conditions
TabEdhRecMain never emitted tabTextChanged, so TabSupervisor::updateTabText
was never called and the tab kept the title it was created with.

addEdhrecMainTab() creates the tab without a card, so every search left the
title reading "EDHRec: " with no card name for the rest of the tab's life.

addEdhrecTab() sets the card before myAddTab(), which is why the older
TabEdhRec tab was never affected.

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2026-10-07 14:55:25 +02:00
tooomm
08a608992d
[Docs] Cleanup Doxygen files (#7361)
Some checks are pending
CodeQL / Analyze (cpp) (push) Waiting to run
CodeQL / Analyze (actions) (push) Waiting to run
Build Docker / Servatrice (arm) (push) Waiting to run
Build Docker / Servatrice (x86) (push) Waiting to run
Build Docker / Publish multi-platform Servatrice image (push) Blocked by required conditions
* Table layout

* table layout

* table layout

* Delete doc/doxygen/extra-pages/developer_documentation/network/game_event_handler.md

* Delete doc/doxygen/extra-pages/developer_documentation/network/player_event_handler.md

* use default value
2026-10-06 07:23:41 +02:00
1108 changed files with 13645 additions and 2493 deletions

View file

@ -357,15 +357,21 @@ if [[ $MAKE_PACKAGE ]]; then
fi
echo "Installer content is clean"
# Fail the build if the installer is missing a Qt runtime the applications
# link against. The DLLs reach the package by globbing every *.dll out of
# the build output directories, so a module the client links statically
# (Qt6Multimedia.dll, Qt6QuickWidgets.dll) can be left out without anything
# else noticing, and the only symptom is a client that refuses to start
# after an update. required-qt-runtime.txt is written by the top level
# CMakeLists.txt from the same module list the targets are built against.
if [[ ! -f required-qt-runtime.txt ]]; then
echo "::error file=$0::required-qt-runtime.txt not found in the build dir, cannot verify the Qt runtime"
# Fail the build if the installer does not carry the runtime the
# applications link against - a file that must be there, or a DLL that must
# not be. The runtime DLLs reach the package by globbing every *.dll out of
# the build output directories, so anything that build produced can ride
# along and nothing else in the build objects to it: a Qt module the client
# links statically (Qt6Multimedia.dll, Qt6QuickWidgets.dll) can be left out,
# and the test framework's gtest.dll can be shipped. Either only surfaces on
# a user's machine after an update has already replaced their install, as
# "The code execution cannot proceed because Qt6Multimedia.dll was not
# found" or "abseil_dll.dll is either not designed to run on Windows or it
# contains an error". required-runtime.txt is written by the top level
# CMakeLists.txt from the same module lists the targets are built against
# plus the vcpkg bin directory the app-local copies come from.
if [[ ! -f required-runtime.txt ]]; then
echo "::error file=$0::required-runtime.txt not found in the build dir, cannot verify the runtime"
exit 1
fi
# 7-Zip writes CRLF on Windows, so the \r has to come off before any
@ -375,7 +381,7 @@ if [[ $MAKE_PACKAGE ]]; then
# being a wildcard; -i because that is how the installed tree behaves -
# the uninstaller clears both $INSTDIR\plugins and $INSTDIR\Plugins.
# The archive side and the manifest side have to agree on line endings.
# CMake writes required-qt-runtime.txt with the platform's line ending and
# CMake writes required-runtime.txt with the platform's line ending and
# 7-Zip writes CRLF on Windows, so a trailing \r survives on $entry and
# defeats the whole-line match - every entry then reads as missing even
# though the listing holds it verbatim.
@ -384,7 +390,7 @@ if [[ $MAKE_PACKAGE ]]; then
installer_paths="$("$seven_zip" l -slt "$package" | tr -d '\r' |
sed -n 's/^Path = //p' |
sed -e 's|\\|/|g' -e 's|^[$]INSTDIR/||' -e 's|^[$]OUTDIR/||' -e 's|^[$]PLUGINSDIR/||' -e 's|^\./||' -e 's|^/||')"
manifest="$(tr -d '\r' <required-qt-runtime.txt)"
manifest="$(tr -d '\r' <required-runtime.txt)"
missing=""
checked=0
while IFS= read -r entry; do
@ -397,11 +403,11 @@ if [[ $MAKE_PACKAGE ]]; then
fi
done <<<"$manifest"
if [[ -n $missing ]]; then
echo "::error file=$0::Installer is missing required Qt runtime files:$missing"
echo "::error file=$0::Installer is missing required runtime files:$missing"
# Print both sides of the comparison. A mismatch here has twice been
# caused by the shape of 7-Zip's output rather than by a missing file,
# and a bare "missing" line cannot tell those apart.
echo "required-qt-runtime.txt asked for $checked path(s); 7-Zip listed $(grep -c '' <<<"$installer_paths") path(s)"
echo "required-runtime.txt asked for $checked path(s); 7-Zip listed $(grep -c '' <<<"$installer_paths") path(s)"
# Indent with parameter expansion rather than sed 's/^/ /', which the
# linter reports as SC2001.
echo "--- required ---"
@ -411,7 +417,66 @@ if [[ $MAKE_PACKAGE ]]; then
echo "${listed_head//$'\n'/$'\n '}"
exit 1
fi
echo "Installer contains the full Qt runtime ($checked files)"
echo "Installer carries the Qt runtime of every module the three applications link ($checked files)"
# Now the other direction: a top level DLL in the package that the manifest
# does not name. The missing check above cannot see a runtime that was
# never expected.
#
# Two things are reported here and neither may fail the build.
#
# The test framework is a fact rather than a guess - no shipped executable
# links gtest or gmock, and the build output directories the "*.dll" glob
# reads are shared with the test targets, so gtest.dll and gmock.dll are
# one filter away from shipping in every release. Even so it is reported
# instead of enforced: a check that has never passed on a real package has
# not earned the right to block a release, and the first Windows run of an
# enforcing version is exactly when its own wrong assumptions show up.
#
# Everything else is expected to be there. required-runtime.txt names the
# Qt modules the three applications link, and the protobuf, Abseil,
# OpenSSL, liblzma, ffmpeg and Qt debug DLLs in the package come in on the
# build output glob instead, because nothing in the build declares them by
# name. So this list is a report of what the package carries, not a verdict.
# Read it when a dependency is added; do not fail on it.
forbidden=""
unexpected=""
while IFS= read -r entry; do
[[ -z $entry ]] && continue
# Top level only. A DLL under Plugins/ or a nested image format plugin is
# a plugin the platform loads by name, not a runtime the executable
# imports, and requiring one here would list all of them every run.
[[ $entry == */* ]] && continue
if grep -qxiF "$entry" <<<"$manifest"; then
continue
fi
# NSIS extracts its plugins to $PLUGINSDIR, which the path normalization
# above strips, so they arrive here looking like payload files. They are
# part of the installer, not of the installed tree.
if [[ $entry == [Nn][Ss][Dd][Ii][Aa][Ll][Oo][Gg][Ss].dll ||
$entry == [Nn][Ss][Ee][Xx][Ee][Cc].dll ||
$entry == [Ss][Yy][Ss][Tt][Ee][Mm].dll ||
$entry == [Uu][Ss][Ee][Rr][Ii][Nn][Ff][Oo].dll ||
$entry == [Ii][Nn][Ee][Tt].dll ]]; then
continue
fi
if [[ $entry == [Gg][Tt][Ee][Ss][Tt]* || $entry == [Gg][Mm][Oo][Cc][Kk]* ]]; then
forbidden+=" $entry"
else
unexpected+=" $entry"
fi
done < <(grep -i '\.dll$' <<<"$installer_paths")
if [[ -n $forbidden ]]; then
echo "::warning file=$0::Installer contains test framework DLLs that no shipped executable links:$forbidden"
echo "A build output directory shared with the test targets has leaked into the package."
fi
if [[ -n $unexpected ]]; then
echo "Top level DLLs in the package beyond the linked Qt modules:$unexpected"
echo "These arrive on the build output glob, not from required-runtime.txt, so they are reported and not required."
fi
if [[ -z $forbidden && -z $unexpected ]]; then
echo "Installer carries no runtime files beyond the linked Qt modules"
fi
fi
echo "::endgroup::"
fi

View file

@ -86,7 +86,7 @@ endif()
# A project name is needed for CPack
# Version can be overriden by git tags, see cmake/getversion.cmake
project("Cockatrice" VERSION 3.1.0)
project("Cockatrice" VERSION 3.1.1)
# Set release name if not provided via env/cmake var
if(NOT DEFINED GIT_TAG_RELEASENAME)
@ -326,38 +326,54 @@ elseif(WIN32)
# Configure file with custom definitions for NSIS.
configure_file("${COCKATRICE_CMAKE_PATH}/NSIS.definitions.nsh.in" "${PROJECT_BINARY_DIR}/NSIS.definitions.nsh")
# Every Qt module the client links against, as the DLL names a Windows install
# has to contain, plus the platform plugin without which the client cannot
# start. .ci/compile.sh reads this and fails the build when the packaged
# installer is missing one of them.
# Every runtime DLL a Windows install has to contain, as paths relative to the
# install root. .ci/compile.sh reads this and fails the build when the packaged
# installer is missing one of them, or carries a runtime it does not know about.
#
# Only the client is packaged on Windows, so this is the client's module list
# rather than the union across server, client and Oracle: demanding Oracle's or
# Servatrice's modules of the client installer checks nothing about the client.
# All three applications are packaged into the same directory on Windows, so
# this is the union of their Qt module lists, not just the client's: Servatrice
# contributes Qt6Sql.dll and Oracle contributes nothing the client lacks, and a
# client-only manifest leaves Qt6Sql.dll unasserted even though servatrice.exe
# is installed next to cockatrice.exe and cannot start without it.
#
# A statically linked Qt module ships no runtime DLL, so requiring one would
# fail the package check on a static build for no reason. cockatrice/CMakeLists.txt
# installs the runtime of every module listed here, and skips static ones the
# same way, so the two can never disagree.
#
# A DLL missing from the package only surfaces on a user's machine, after an
# update has already replaced their install, as "The code execution cannot
# proceed because Qt6Multimedia.dll was not found" or as a missing procedure
# entry point in a Qt6QuickWidgets.dll left over from the previous version.
# Assert it while the installer is still being built instead.
set(_required_qt_runtime "")
foreach(_qt_module IN LISTS COCKATRICE_QT_MODULES)
# Only the Qt modules, and that is deliberate. protobuf, Abseil, liblzma, zlib
# and OpenSSL also ride in on the "*.dll" glob, and a client whose runtime is
# absent, stale or of the wrong architecture fails to start with "abseil_dll.dll
# is either not designed to run on Windows or it contains an error", so they
# are exactly the files worth asserting.
#
# Their names cannot be derived from the vcpkg bin directory, which is what a
# first attempt did and what a Windows build immediately refuted: bin holds
# everything vcpkg installed, not everything the applications import. It also
# contains gmock.dll, libprotobuf-lite.dll, libprotoc.dll, legacy.dll and three
# pthreadVC*.dll FindThreads probes, none of which any shipped executable
# links, so requiring them failed a build over a package that was correct.
#
# Deriving them from the executables' own import tables is the real answer,
# and fixup_bundle already walks it to decide what to copy. Until that result
# is available to CMake, requiring the vcpkg half would mean guessing names
# again, which is what produced this bug report in the first place. So assert
# what is derived from the build's own link lists and leave the rest to the
# purge in cmake/NSIS.template.in, which removes every DLL regardless of name.
set(_required_runtime "")
foreach(_qt_module IN LISTS COCKATRICE_QT_MODULES SERVATRICE_QT_MODULES ORACLE_QT_MODULES)
get_target_property(_qt_module_type ${_qt_module} TYPE)
if(_qt_module_type STREQUAL "SHARED_LIBRARY")
string(REGEX REPLACE "^Qt6::" "" _qt_component "${_qt_module}")
list(APPEND _required_qt_runtime "Qt6${_qt_component}.dll")
list(APPEND _required_runtime "Qt6${_qt_component}.dll")
endif()
endforeach()
list(APPEND _required_qt_runtime "Plugins/platforms/qwindows.dll")
list(REMOVE_DUPLICATES _required_qt_runtime)
list(SORT _required_qt_runtime)
string(REPLACE ";" "\n" _required_qt_runtime "${_required_qt_runtime}")
file(WRITE "${PROJECT_BINARY_DIR}/required-qt-runtime.txt" "${_required_qt_runtime}\n")
list(APPEND _required_runtime "Plugins/platforms/qwindows.dll")
list(REMOVE_DUPLICATES _required_runtime)
list(SORT _required_runtime)
string(REPLACE ";" "\n" _required_runtime "${_required_runtime}")
file(WRITE "${PROJECT_BINARY_DIR}/required-runtime.txt" "${_required_runtime}\n")
# include vcredist into the package; NSIS will take care of running it
if(VCREDISTRUNTIME_FOUND)

View file

@ -2667,7 +2667,7 @@ DOT_NUM_THREADS = 0
# Minimum value: 1, maximum value: 1000, default value: 50.
# This tag requires that the tag HAVE_DOT is set to YES.
DOT_BATCH_SIZE = 500
DOT_BATCH_SIZE = 50
# DOT_COMMON_ATTR is common attributes for nodes, edges and labels of
# subgraphs. When you want a differently looking font in the dot files that

View file

@ -7,6 +7,12 @@
# Output: ORACLE_QT_MODULES
# Output: TEST_QT_MODULES
# Every Qt module an application links against, as the DLL names a Windows
# install has to contain. Core is listed explicitly rather than left to arrive
# transitively: it is the one module nothing can do without, and required-runtime.txt
# is built from these lists, so a module missing here is a runtime the package
# check never asserts. That is how Qt6Core.dll went unasserted while every other
# Qt module was checked.
set(REQUIRED_QT_COMPONENTS Core)
if(WITH_SERVER)
set(_SERVATRICE_NEEDED Network Sql WebSockets)
@ -14,6 +20,7 @@ endif()
if(WITH_CLIENT)
set(_COCKATRICE_NEEDED
Concurrent
Core
Gui
Multimedia
Network

View file

@ -21,6 +21,13 @@ Var IsUpgrade
Var AbortReason
Var WaitPid
Var LauncherExited
Var InstallLogPath
Var LogHandle
Var LogMessage
Var LogFindHandle
Var LogFindName
Var LogMatchLabel
Var LogMatchPattern
!include LogicLib.nsh
!include FileFunc.nsh
@ -64,8 +71,67 @@ Page Custom PortableModePageCreate PortableModePageLeave
!insertmacro MUI_LANGUAGE English
; Installer log
; Every run appends a step-by-step trace to a file so a failed upgrade on a
; user's machine can be diagnosed after the fact. Kept in $TEMP rather than in
; $INSTDIR because the previous version's uninstaller removes the whole install
; directory part-way through an upgrade. Read it back with:
; notepad %TEMP%\Cockatrice-installer.log
!macro CockLog text
Push "${text}"
Call CockLogWrite
!macroend
Function CockLogWrite
Pop $LogMessage
FileOpen $LogHandle "$InstallLogPath" a
${If} $LogHandle == ""
Return
${EndIf}
; FileOpen places the pointer at the start of the file in every mode, so
; 'a' alone would overwrite the log from the beginning on each line. Seek
; past the existing content first to actually append.
FileSeek $LogHandle 0 END
FileWrite $LogHandle "$LogMessage$\r$\n"
FileClose $LogHandle
FunctionEnd
; Logs every file matching $INSTDIR\<mask>. Used to record the DLL inventory
; before and after the upgrade purge, which is what shows whether Qt6Gui.dll was
; on disk and what (if anything) survived the deletes.
!macro CockLogListing label mask
Push "${label}"
Push "$INSTDIR\${mask}"
Call CockLogListing
!macroend
Function CockLogListing
Pop $LogMatchPattern
Pop $LogMatchLabel
!insertmacro CockLog "listing [$LogMatchLabel] pattern=$LogMatchPattern"
FindFirst $LogFindHandle $LogFindName "$LogMatchPattern"
${If} $LogFindHandle == ""
!insertmacro CockLog "listing [$LogMatchLabel] (no matches)"
Return
${EndIf}
log_listing_loop:
!insertmacro CockLog "listing [$LogMatchLabel] $LogFindName"
ClearErrors
FindNext $LogFindHandle $LogFindName
IfErrors 0 log_listing_loop
FindClose $LogFindHandle
FunctionEnd
Function .onInit
StrCpy $InstallLogPath "$TEMP\Cockatrice-installer.log"
; Start each run from a clean file so the log that gets sent back is the last
; run, not every past run glued together.
FileOpen $LogHandle "$InstallLogPath" w
FileClose $LogHandle
!insertmacro CockLog "=================================================================="
!insertmacro CockLog "installer start: @CPACK_PACKAGE_NAME@ @CPACK_PACKAGE_VERSION@"
${If} ${NSIS_IS_64_BIT} == 1 #NSIS 64bit
${IfNot} ${RunningX64}
MessageBox MB_OK|MB_ICONSTOP "This version of Cockatrice requires a 64-bit Windows system."
@ -158,6 +224,13 @@ ${EndIf}
; Now that $PortableMode reflects reality, commit InstDir into the correct slot
Call SetModeDestinationFromInstdir
!insertmacro CockLog "options: InstDir=$InstDir PortableMode=$PortableMode ReinstallMode=$ReinstallMode WaitPid=$WaitPid"
${If} ${Silent}
!insertmacro CockLog "options: running silently"
${Else}
!insertmacro CockLog "options: interactive"
${EndIf}
; Wait for the process that launched this installer to exit before anything is
; replaced or deleted. It goes first because it is the one check here that needs
; no powershell.exe: on a machine where the process lookup cannot run at all, the
@ -175,12 +248,14 @@ Call SetModeDestinationFromInstdir
; interactive installs the section re-checks after the directory page, when
; $INSTDIR is the directory the user actually picked.
${If} $ReinstallMode = 1
!insertmacro CockLog "reinstall: waiting for launcher and other instances"
Call WaitForLauncherToExit
Call EnsureAppsNotRunning
${EndIf}
${If} $ReinstallMode = 1
${AndIf} $PortableMode = 0
!insertmacro CockLog "reinstall: auto-uninstalling previous version"
Call AutoUninstallIfNeeded
${EndIf}
@ -226,13 +301,22 @@ Function AutoUninstallIfNeeded
SetShellVarContext all
; _?=$INSTDIR keeps the old uninstaller running in place. An NSIS uninstaller
; normally copies itself to %TEMP% and runs from there so that it can delete its
; own directory, and the process we started exits at once. ExecWait then returns
; before the uninstall has run, and the temp copy's "RMDir /r $INSTDIR" executes
; while the section below is still writing the new payload. _?= disables the copy
; and makes ExecWait block until the uninstall finishes. It must be the last
; argument and must not be quoted, even when the path contains spaces.
;
; --- 32-bit uninstall ---
SetRegView 32
ReadRegStr $R0 HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Cockatrice" "QuietUninstallString"
!insertmacro CockLog "uninstall (32-bit): '$R0 _?=$INSTDIR'"
StrCmp $R0 "" done32
DetailPrint "Removing previous version (32-bit)..."
ExecWait '$R0'
ExecWait '$R0 _?=$INSTDIR'
done32:
@ -241,9 +325,10 @@ ${If} ${RunningX64}
SetRegView 64
ReadRegStr $R0 HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Cockatrice" "QuietUninstallString"
!insertmacro CockLog "uninstall (64-bit): '$R0 _?=$INSTDIR'"
StrCmp $R0 "" done64
DetailPrint "Removing previous version (64-bit)..."
ExecWait '$R0'
ExecWait '$R0 _?=$INSTDIR'
done64:
${EndIf}
@ -360,6 +445,7 @@ Function WaitForAppToClose
; usage: set $R1 to the display name (e.g. "cockatrice.exe") and $R2 to the
; base image name (e.g. "cockatrice")
Call IsAppRunning
!insertmacro CockLog "guard $R1: state=$R0 (dir=$GuardDir)"
; Only a definite "running" is worth waiting for. "Not running" is done, and
; "could not determine" must not keep the installer waiting on an answer it
; will never get - but it cannot simply be waved through either, see
@ -384,6 +470,7 @@ Function WaitForAppToClose
Sleep 500
Call IsAppRunning
${If} $R0 = 0
!insertmacro CockLog "guard $R1: closed gracefully"
DetailPrint "$R1 closed."
Return
${EndIf}
@ -402,6 +489,7 @@ Function WaitForAppToClose
; deck, and nothing has been replaced yet, so aborting just defers the
; update and preserves the user's data.
${If} $AllowForceClose = 0
!insertmacro CockLog "guard $R1: still running after 60s, aborting (no force close)"
DetailPrint "$R1 is still running after 60 s; aborting the update so that no data is lost."
StrCpy $AbortReason \
"$R1 did not close within 60 seconds, so the installation was aborted to avoid losing unsaved data.$\r$\n$\r$\nPlease close $R1 and run the installer again."
@ -410,11 +498,13 @@ Function WaitForAppToClose
; Oracle and Servatrice are console applications: CloseMainWindow()
; returned false for them and waiting longer cannot help. They hold no
; unsaved user data, so stop them by PID.
!insertmacro CockLog "guard $R1: still running after 60s, force-stopping"
DetailPrint "Force-stopping $R1 ..."
Call ForceCloseApps
Sleep 2000
Call IsAppRunning
${If} $R0 = 0
!insertmacro CockLog "guard $R1: force-stopped"
DetailPrint "$R1 closed."
Return
${EndIf}
@ -422,6 +512,7 @@ Function WaitForAppToClose
Call HandleUnknownAppState
Return
${EndIf}
!insertmacro CockLog "guard $R1: could not be stopped, aborting"
DetailPrint "$R1 is still running after 60 s; aborting the update."
StrCpy $AbortReason \
"$R1 could not be stopped, so the installation was aborted.$\r$\n$\r$\nPlease close $R1 and run the installer again."
@ -486,8 +577,16 @@ FunctionEnd
; Only the first of those two gets a dialog; the second reports through the log
; and the exit code.
Function AbortInstall
${IfNot} ${Silent}
MessageBox MB_OK|MB_ICONEXCLAMATION "$AbortReason"
!insertmacro CockLog "ABORT: $AbortReason"
!insertmacro CockLog "full installer log: $InstallLogPath"
; Show a dialog whenever someone is at the keyboard to see it: an interactive
; install, or the in-app updater's /R upgrade. The /R upgrade is silent, but
; the client that launched the installer has already quit, so the user is
; still there. Only a /S install without /R is attended by a package manager
; and must go straight to the exit code.
${If} $ReinstallMode = 1
${OrIfNot} ${Silent}
MessageBox MB_OK|MB_ICONEXCLAMATION "$AbortReason$\r$\n$\r$\nA detailed installer log was written to:$\r$\n$InstallLogPath"
${EndIf}
SetErrorLevel 1
Abort
@ -510,17 +609,33 @@ FunctionEnd
; falls back to the name based guard.
Function WaitForLauncherToExit
StrCpy $LauncherExited 0
!insertmacro CockLog "wait-launcher: pid='$WaitPid'"
${If} $WaitPid == ""
!insertmacro CockLog "wait-launcher: no pid given, falling back to name check"
Return
${EndIf}
; PROCESS_SYNCHRONIZE is the only access this needs - enough to wait on the
; handle, and the least likely to be refused for a reason that has nothing to
; do with the upgrade.
;
; System.dll maps its output registers so that .rN writes $N and .RN writes
; $RN. The caller reads $R0/$R1, so the uppercase .RN form is required; the
; original .r0/.r1 wrote $0/$1 and left $R1 empty, which made the "did not
; exit" test below compare "" against "0" and abort on every /PID= upgrade.
ClearErrors
System::Call 'kernel32::OpenProcess(i 0x00100000, i 0, i $WaitPid) p.r0'
System::Call 'kernel32::OpenProcess(i 0x00100000, i 0, i $WaitPid) p.R0'
; OpenProcess returns a null handle for a process that is already gone. The
; System plugin does not raise the NSIS error flag from a called function's
; return value, so ${Errors} alone never saw that case and the null handle was
; passed straight to WaitForSingleObject. Fold a plugin failure into the same
; null-handle case instead of reading a handle that was never written.
${If} ${Errors}
StrCpy $R0 0
${EndIf}
${If} $R0 == 0
; The launcher is gone - OpenProcess cannot open a dead process - which is
; exactly the state the wait was for.
!insertmacro CockLog "wait-launcher: already exited"
DetailPrint "The application that started this installer has already exited."
StrCpy $LauncherExited 1
Return
@ -529,14 +644,16 @@ Function WaitForLauncherToExit
; Same 60 s grace period the name based check uses, so a client that is slow
; to flush its card database does not get less room than it used to.
; WAIT_OBJECT_0 is 0; WAIT_TIMEOUT is 258 and a failed wait reports 0xFFFFFFFF.
System::Call 'kernel32::WaitForSingleObject(p r0, i 60000) i.r1'
System::Call 'kernel32::CloseHandle(p r0)'
System::Call 'kernel32::WaitForSingleObject(p R0, i 60000) i.R1'
System::Call 'kernel32::CloseHandle(p R0)'
${If} $R1 != 0
!insertmacro CockLog "wait-launcher: did not exit within 60s (wait=$R1)"
DetailPrint "The application that started this installer did not exit within 60 s."
StrCpy $AbortReason \
"The application that started this update has not exited yet, so the installation was cancelled rather than replace files it is still using.$\r$\n$\r$\nPlease close Cockatrice and run the installer again."
Call AbortInstall
${EndIf}
!insertmacro CockLog "wait-launcher: launcher exited"
DetailPrint "The application that started this installer has exited."
StrCpy $LauncherExited 1
FunctionEnd
@ -562,9 +679,11 @@ FunctionEnd
Function GuardAppsNotRunning
; usage: set $GuardDir to the directory to guard, then call this
Call IsProcessLookupAvailable
!insertmacro CockLog "guard: powershell available=$R0 dir=$GuardDir launcherExited=$LauncherExited"
${If} $R0 = 0
; Without PowerShell we cannot tell whether a running instance is
; holding locks on the files we are about to replace.
!insertmacro CockLog "guard: powershell unavailable, skipping instance check"
DetailPrint "Could not start powershell.exe; skipping the running instance check. Close Cockatrice, Oracle and Servatrice manually if the installation reports a problem."
; On a silent upgrade that used to be a warning and nothing more, which
; left the very process that launched the installer free to go on
@ -587,7 +706,8 @@ Function GuardAppsNotRunning
${EndIf}
; The user has to be told to close the applications by hand, but a /S
; install without /R is unattended and would block on this forever.
${IfNot} ${Silent}
${If} $ReinstallMode = 1
${OrIfNot} ${Silent}
MessageBox MB_OK|MB_ICONEXCLAMATION "This installer could not check whether Cockatrice is still running, because powershell.exe could not be started.$\r$\n$\r$\nPlease close Cockatrice, Oracle and Servatrice manually before continuing."
${EndIf}
Return
@ -633,7 +753,11 @@ Function IsExistingCockatriceInstall
; there to prove that it is one. Every Qt module Cockatrice links is part of
; the payload, so match them all: probing only Qt6Core.dll would miss a
; directory where that one file happened to be deletable and the others
; were not.
; were not. Qt6*.dll rather than *.dll on purpose: this function decides
; whether a directory is ours, and a folder that merely holds some DLLs of
; its own must not be purged. Qt6*.dll is enough even when only the protobuf
; runtime survived, because the whole Qt set is mapped by the same process
; that maps abseil_dll.dll and so is locked or free with it.
StrCpy $R3 "Qt6*.dll"
Call CheckStaleRuntimeMask
${If} ${FileExists} "$INSTDIR\qt.conf"
@ -645,36 +769,23 @@ FunctionEnd
; the purge. NSIS silently skips whatever it cannot delete, so one surviving file
; is enough to prove that something still holds a lock on the install directory.
;
; The masks below have to cover the purge above one for one. A check that only
; probed named files could not see a locked Qt6Multimedia.dll or a Plugins
; directory the purge was unable to remove, so the exact files that broke the
; install were also the ones this check was blind to.
; Any DLL at all counts, not a list of expected ones. The purge removes every
; top-level DLL, so after it has run the only DLL that can still be there is one
; it failed to delete, whatever its name. A mask per library family (Qt, then
; OpenSSL, then zlib) is what let abseil_dll.dll through: it is in neither the
; purge nor this check, so it survived a 3.0.2 to 3.1 update untouched, the new
; executables were written next to it, and the client then failed to start with
; "abseil_dll.dll is either not designed to run on Windows or it contains an
; error". Probing *.dll has no list to fall out of date when the next
; transitive dependency appears.
Function HasStaleRuntimeFiles
StrCpy $R0 0
StrCpy $R3 "Qt*.dll"
StrCpy $R3 "*.dll"
Call CheckStaleRuntimeMask
StrCpy $R3 "libcrypto*.dll"
Call CheckStaleRuntimeMask
StrCpy $R3 "libssl*.dll"
Call CheckStaleRuntimeMask
StrCpy $R3 "zlib*.dll"
Call CheckStaleRuntimeMask
StrCpy $R3 "icu*.dll"
Call CheckStaleRuntimeMask
StrCpy $R3 "libeay32.dll"
Call CheckStaleRuntimeMask
StrCpy $R3 "ssleay32.dll"
Call CheckStaleRuntimeMask
${If} $R0 = 1
Return
${EndIf}
${If} ${FileExists} "$INSTDIR\libmysql.dll"
StrCpy $R0 1
Return
${EndIf}
; IfFileExists takes wildcards, so a Plugins directory the purge could not
; remove counts as a leftover too.
${If} ${FileExists} "$INSTDIR\Plugins\*.*"
!insertmacro CockLog "stale-runtime: Plugins directory survived the purge"
StrCpy $R0 1
${EndIf}
FunctionEnd
@ -687,6 +798,7 @@ Function CheckStaleRuntimeMask
${EndIf}
FindFirst $StaleFindHandle $StaleFindName "$INSTDIR\$R3"
${If} $StaleFindHandle != ""
!insertmacro CockLog "stale-runtime: '$StaleFindName' matched $R3 in $INSTDIR"
StrCpy $R0 1
FindClose $StaleFindHandle
${EndIf}
@ -925,9 +1037,10 @@ ${If} $PortableMode = 0
; directory before letting it delete anything. The uninstall string is
; stashed away first, the check works on $R0.
StrCpy $OldUninstallString $R0
!insertmacro CockLog "componentsPagePre: old 32-bit uninstall '$OldUninstallString _?=$INSTDIR'"
Call EnsureOldInstallNotRunning
ClearErrors
ExecWait "$OldUninstallString"
ExecWait "$OldUninstallString _?=$INSTDIR"
done32:
@ -947,9 +1060,10 @@ ${If} $PortableMode = 0
uninst64:
StrCpy $OldUninstallString $R0
!insertmacro CockLog "componentsPagePre: old 64-bit uninstall '$OldUninstallString _?=$INSTDIR'"
Call EnsureOldInstallNotRunning
ClearErrors
ExecWait "$OldUninstallString"
ExecWait "$OldUninstallString _?=$INSTDIR"
done64:
${EndIf}
@ -964,15 +1078,19 @@ Section "Application" SecApplication
SetShellVarContext all
SetOutPath "$INSTDIR"
!insertmacro CockLog "section: InstDir=$INSTDIR PortableMode=$PortableMode ReinstallMode=$ReinstallMode"
; No application instance may be running while any file below is deleted or
; replaced: both upgrade blocks start by removing the old executables and
; runtime DLLs, and NSIS silently skips whatever is locked, which is how an
; install ends up with a mix of old and new Qt DLLs next to the new executable
; ("The procedure entry point X could not be located in the dynamic link
; library ...Qt6Network.dll"). So the check has to come before the first
; Delete/RMDir and not after it - an interactive install into an existing
; portable directory with cockatrice.exe still running would otherwise delete
; the old files under its feet.
; install ends up with a mix of old and new runtimes next to the new executable.
; The next start then fails with "The procedure entry point X could not be
; located in the dynamic link library ...Qt6Network.dll" for the Qt ones, or
; "abseil_dll.dll is either not designed to run on Windows or it contains an
; error" for the protobuf ones. So the check has to come before the first
; Delete/RMDir and not after it: an interactive install into an existing portable
; directory with cockatrice.exe still running would otherwise delete the old
; files under its feet.
;
; It is skipped on the /R path: .onInit already ran it before
; AutoUninstallIfNeeded removed the previous installation, so by the time this
@ -987,6 +1105,8 @@ ${EndIf}
${If} $PortableMode = 1
${AndIf} ${FileExists} "$INSTDIR\portable.dat"
; upgrade portable mode
!insertmacro CockLog "section: portable upgrade purge"
!insertmacro CockLogListing "before-portable-purge" "*.dll"
RMDir /r "$INSTDIR\plugins"
RMDir /r "$INSTDIR\sounds"
RMDir /r "$INSTDIR\themes"
@ -995,24 +1115,24 @@ ${AndIf} ${FileExists} "$INSTDIR\portable.dat"
Delete "$INSTDIR\cockatrice.exe"
Delete "$INSTDIR\oracle.exe"
Delete "$INSTDIR\servatrice.exe"
Delete "$INSTDIR\Qt*.dll"
Delete "$INSTDIR\libmysql.dll"
Delete "$INSTDIR\icu*.dll"
Delete "$INSTDIR\libcrypto*.dll"
Delete "$INSTDIR\libssl*.dll"
Delete "$INSTDIR\libeay32.dll"
Delete "$INSTDIR\ssleay32.dll"
; Every top-level DLL, not a list of expected ones. The payload is written
; after this block, so a DLL the new build still needs is put straight back;
; what this has to guarantee is that nothing from the previous build is left
; to be loaded next to the new executables. Naming the families by hand is
; what let abseil_dll.dll through; see HasStaleRuntimeFiles.
Delete "$INSTDIR\*.dll"
Delete "$INSTDIR\qt.conf"
Delete "$INSTDIR\qdebug.txt"
Delete "$INSTDIR\servatrice.sql"
Delete "$INSTDIR\servatrice.ini.example"
Delete "$INSTDIR\zlib*.dll"
RMDir "$INSTDIR"
!insertmacro CockLogListing "after-portable-purge" "*.dll"
${EndIf}
; Remove any runtime DLLs left over from older versions, so a mismatched
; Qt/OpenSSL set cannot survive next to the new executables.
; Qt/OpenSSL/protobuf set cannot survive next to the new executables.
Call IsExistingCockatriceInstall
!insertmacro CockLog "section: IsExistingCockatriceInstall=$R0"
; Remembered because the stale-runtime check below must only ever fire for a
; directory this installer recognised as a Cockatrice install. Scanning for
; leftovers in an unrelated directory (a first-time install into a folder that
@ -1021,48 +1141,48 @@ Call IsExistingCockatriceInstall
StrCpy $IsUpgrade $R0
${If} $PortableMode = 0
${AndIf} $R0 = 1
!insertmacro CockLog "section: non-portable upgrade purge"
!insertmacro CockLogListing "before-purge" "*.dll"
RMDir /r "$INSTDIR\Plugins"
Delete "$INSTDIR\Qt*.dll"
Delete "$INSTDIR\libcrypto*.dll"
Delete "$INSTDIR\libssl*.dll"
Delete "$INSTDIR\zlib*.dll"
Delete "$INSTDIR\libmysql.dll"
Delete "$INSTDIR\icu*.dll"
Delete "$INSTDIR\libeay32.dll"
Delete "$INSTDIR\ssleay32.dll"
Delete "$INSTDIR\*.dll"
!insertmacro CockLogListing "after-purge" "*.dll"
!insertmacro CockLogListing "after-plugins" "Plugins\*.*"
${EndIf}
; Whatever was locked during the purge - by an instance that started while the
; Whatever was locked during the purge (by an instance that started while the
; installer was running, or because the running instance check could not be
; performed at all - is still on disk, and the new executables are about to be
; performed at all) is still on disk, and the new executables are about to be
; written next to it. That mix is exactly what makes the next start fail with
; "The procedure entry point X could not be located in the dynamic link library
; ...Qt6QuickWidgets.dll" or "The code execution cannot proceed because
; Qt6Multimedia.dll was not found", so stop here instead of compounding it.
; Nothing of the new payload has been written at this point, so the next run -
; with the applications closed - gets a clean install.
; ...Qt6QuickWidgets.dll", "The code execution cannot proceed because
; Qt6Multimedia.dll was not found", or "abseil_dll.dll is either not designed to
; run on Windows or it contains an error", so stop here instead of compounding
; it. Nothing of the new payload has been written at this point, so the next run,
; with the applications closed, gets a clean install.
${If} $IsUpgrade = 1
Call HasStaleRuntimeFiles
!insertmacro CockLog "section: HasStaleRuntimeFiles=$R0"
${Else}
StrCpy $R0 0
${EndIf}
${If} $R0 = 1
!insertmacro CockLog "section: aborting, files of a previous version survived the purge"
DetailPrint "Files of a previous version could not be removed; aborting the installation."
; The in-app updater runs this installer silent and detached and never looks
; at its exit code, so the user has to be told what happened. A /S install
; without /R is unattended - a package manager, for instance - and a message
; without /R is unattended (a package manager, for instance) and a message
; box there would block forever, so that case only reports through the log
; and the exit code.
${IfNot} ${Silent}
MessageBox MB_OK|MB_ICONEXCLAMATION \
"The installation could not remove all files of a previous version of Cockatrice, most likely because it is still running or was started as administrator, and was cancelled rather than leave a mismatched install behind.$\r$\n$\r$\nPlease close Cockatrice, Oracle and Servatrice and run the installer again."
${EndIf}
SetErrorLevel 1
Abort
; and the exit code. AbortInstall owns that decision.
StrCpy $AbortReason \
"The installation could not remove all files of a previous version of Cockatrice, most likely because it is still running or was started as administrator, and was cancelled rather than leave a mismatched install behind.$\r$\n$\r$\nPlease close Cockatrice, Oracle and Servatrice and run the installer again."
Call AbortInstall
${EndIf}
@CPACK_NSIS_EXTRA_PREINSTALL_COMMANDS@
!insertmacro CockLog "section: writing payload to $INSTDIR"
@CPACK_NSIS_FULL_INSTALL@
!insertmacro CockLog "section: payload written"
!insertmacro CockLogListing "final" "Qt6*.dll"
${If} $PortableMode = 0
WriteUninstaller "$INSTDIR\uninstall.exe"
@ -1126,6 +1246,7 @@ ${If} $ReinstallMode = 1
Exec '"$INSTDIR\cockatrice.exe"'
${EndIf}
!insertmacro CockLog "section: application install complete"
SectionEnd
Section "Start menu item" SecStartMenu

View file

@ -140,6 +140,10 @@ set(cockatrice_SOURCES
src/game_graphics/zones/view_zone.cpp
src/game_graphics/zones/view_zone_widget.cpp
src/game_graphics/board/abstract_graphics_item.cpp
src/interface/card_database_update/card_database_update_status_bar.cpp
src/interface/card_database_update/card_database_update_status_bar.h
src/interface/card_database_update/card_update_progress.cpp
src/interface/card_database_update/card_update_progress.h
src/interface/card_picture_loader/card_picture_loader.cpp
src/interface/card_picture_loader/card_picture_loader_local.cpp
src/interface/card_picture_loader/card_picture_loader_request_status_display_widget.cpp
@ -687,7 +691,7 @@ if(WIN32)
# import table, and the glob above only sees DLLs that were already copied next
# to the executable. Qt6::Concurrent is linked but never imported - QtConcurrent::run
# and QFutureWatcher are header-only in Qt 6 - so neither step ships
# Qt6Concurrent.dll, even though required-qt-runtime.txt lists it and the
# Qt6Concurrent.dll, even though required-runtime.txt lists it and the
# Windows package check then fails on a package that is fine to run.
# Qt6::ShaderTools is skipped for the same reason.
#

View file

@ -6,5 +6,4 @@ Name=Cockatrice
Exec=cockatrice %U
Icon=cockatrice
Categories=Game;CardGame;
MimeType=application/x-cockatrice;
X-Scheme-Handler/cockatrice=true
MimeType=application/x-cockatrice;x-scheme-handler/cockatrice;

View file

@ -1,7 +1,10 @@
#include "lag_monitor.h"
#include <QApplication>
#include <QCoreApplication>
#include <QDateTime>
#include <QEvent>
#include <QMessageLogger>
#include <QTimer>
LagMonitor::LagMonitor(QObject *parent) : QObject(parent)

View file

@ -6,15 +6,15 @@
#ifndef LAG_MONITOR_H
#define LAG_MONITOR_H
#include <QDateTime>
#include <QElapsedTimer>
#include <QList>
#include <QLoggingCategory>
#include <QObject>
#include <QtGlobal>
#include <qtmetamacros.h>
inline Q_LOGGING_CATEGORY(LagMonitorLog, "lag_monitor");
class QEvent;
class QTimer;
/**

View file

@ -5,7 +5,11 @@
#include "latency_graph_widget.h"
#include <QColor>
#include <QPainter>
#include <QRectF>
#include <QtGlobal>
#include <qnumeric.h>
LatencyGraphWidget::LatencyGraphWidget(QWidget *parent) : QWidget(parent)
{

View file

@ -8,6 +8,8 @@
#include <QList>
#include <QWidget>
#include <QtGlobal>
#include <qtmetamacros.h>
/**
* @brief Bar graph of recent network round-trip samples.

View file

@ -6,11 +6,15 @@
#include "latency_status_widget.h"
#include "latency_graph_widget.h"
#include "latency_tracker.h"
#include <QEvent>
#include <QHBoxLayout>
#include <QLabel>
#include <QObject>
#include <QPoint>
#include <QVBoxLayout>
#include <qnamespace.h>
LatencyStatusWidget::LatencyStatusWidget(QWidget *parent) : QWidget(parent)
{

View file

@ -7,8 +7,10 @@
#define LATENCY_STATUS_WIDGET_H
#include <QList>
#include <QString>
#include <QWidget>
#include <libcockatrice/network/client/abstract/latency_tracker.h>
#include <qtmetamacros.h>
class QLabel;
class LatencyGraphWidget;

View file

@ -8,14 +8,25 @@
#include "../interface/widgets/dialogs/dlg_forgot_password_reset.h"
#include "../interface/widgets/dialogs/dlg_register.h"
#include "../interface/widgets/utility/get_text_with_max.h"
#include "libcockatrice/protocol/pb/event_connection_closed.pb.h"
#include "libcockatrice/protocol/pb/event_server_shutdown.pb.h"
#include <QChar>
#include <QDateTime>
#include <QDebug>
#include <QLineEdit>
#include <QList>
#include <QMessageBox>
#include <QPixmap>
#include <QStringList>
#include <QStringLiteral>
#include <QThread>
#include <libcockatrice/network/client/remote/remote_client.h>
#include <libcockatrice/protocol/pb/response.pb.h>
#include <libcockatrice/settings/servers_settings.h>
#include <qnamespace.h>
class QWidget;
ConnectionController::ConnectionController(QWidget *dialogParent, QObject *parent)
: QObject(parent), dialogParent(dialogParent)

View file

@ -2,17 +2,22 @@
#define COCKATRICE_REMOTE_CONNECTION_CONTROLLER_H
#include "abstract_client.h"
#include "latency_tracker.h"
#include <QMessageBox>
#include <QObject>
#include <QString>
#include <QThread>
#include <libcockatrice/protocol/pb/event_connection_closed.pb.h>
#include <libcockatrice/protocol/pb/event_server_shutdown.pb.h>
#include <QtGlobal>
#include <qtmetamacros.h>
class RemoteClient;
class ServerInfo_User;
class DlgConnect;
class Event_ConnectionClosed;
class Event_ServerShutdown;
class QThread;
class QWidget;
template <typename T> class QList;
/**
* Owns the RemoteClient and its worker thread.

View file

@ -1,11 +1,22 @@
#include "deck_stats_interface.h"
#include "libcockatrice/card/card_info.h"
#include "libcockatrice/card/database/card_database_querier.h"
#include "libcockatrice/deck_list/tree/inner_deck_list_node.h"
#include <QByteArray>
#include <QDesktopServices>
#include <QMessageBox>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QNetworkRequest>
#include <QRegularExpression>
#include <QRegularExpressionMatch>
#include <QSharedPointer>
#include <QString>
#include <QUrl>
#include <QUrlQuery>
#include <functional>
#include <libcockatrice/card/database/card_database_manager.h>
#include <libcockatrice/deck_list/deck_list.h>
#include <libcockatrice/deck_list/tree/deck_list_card_node.h>

View file

@ -7,7 +7,8 @@
#ifndef DECKSTATS_INTERFACE_H
#define DECKSTATS_INTERFACE_H
#include <libcockatrice/deck_list/deck_list.h>
#include <QObject>
#include <qtmetamacros.h>
class QByteArray;
class QNetworkAccessManager;

View file

@ -1,11 +1,28 @@
#include "tapped_out_interface.h"
#include "libcockatrice/card/card_info.h"
#include "libcockatrice/card/database/card_database_querier.h"
#include "libcockatrice/deck_list/tree/inner_deck_list_node.h"
#include <QByteArray>
#include <QDebug>
#include <QDesktopServices>
#include <QList>
#include <QMessageBox>
#include <QMessageLogger>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QNetworkRequest>
#include <QRegularExpression>
#include <QRegularExpressionMatch>
#include <QRegularExpressionMatchIterator>
#include <QSharedPointer>
#include <QString>
#include <QStringList>
#include <QUrl>
#include <QUrlQuery>
#include <QVariant>
#include <functional>
#include <libcockatrice/card/database/card_database_manager.h>
#include <libcockatrice/deck_list/deck_list.h>
#include <libcockatrice/deck_list/tree/deck_list_card_node.h>

View file

@ -9,6 +9,7 @@
#include <QLoggingCategory>
#include <QObject>
#include <qtmetamacros.h>
inline Q_LOGGING_CATEGORY(TappedOutInterfaceLog, "tapped_out_interface");

View file

@ -1,6 +1,7 @@
#include "deck_link_to_api_transformer.h"
#include <QRegularExpression>
#include <QRegularExpressionMatch>
namespace DeckLinkToApiTransformer
{

View file

@ -1,21 +1,35 @@
#include "spoiler_background_updater.h"
#include "../../../../interface/window_main.h"
#include "../../../../main.h"
#include "../../../settings/cache_settings.h"
#include <QChar>
#include <QCryptographicHash>
#include <QDateTime>
#include <QDebug>
#include <QDir>
#include <QFile>
#include <QFileInfo>
#include <QIODevice>
#include <QList>
#include <QLocale>
#include <QMessageLogger>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QNetworkRequest>
#include <QSharedPointer>
#include <QSystemTrayIcon>
#include <QTimeZone>
#include <QUrl>
#include <QtConcurrent>
#include <QtConcurrentRun>
#include <QtGlobal>
#include <functional>
#include <libcockatrice/card/database/card_database.h>
#include <libcockatrice/card/database/card_database_manager.h>
#include <libcockatrice/settings/download_settings.h>
#include <libcockatrice/settings/paths_settings.h>
#include <tuple>
#include <utility>
#include <version_string.h>
#define SPOILERS_STATUS_URL "https://raw.githubusercontent.com/Cockatrice/Magic-Spoiler/files/SpoilerSeasonEnabled"

View file

@ -10,7 +10,11 @@
#include <QByteArray>
#include <QLoggingCategory>
#include <QObject>
#include <QProcess>
#include <QString>
#include <qtmetamacros.h>
class QProcess;
class QUrl;
inline Q_LOGGING_CATEGORY(SpoilerBackgroundUpdaterLog, "spoiler_background_updater");

View file

@ -6,9 +6,12 @@
#ifndef CLIENT_UPDATE_CHECKER_H
#define CLIENT_UPDATE_CHECKER_H
#include <QObject>
#include "release_channel.h"
class Release;
#include <QMetaObject>
#include <QObject>
#include <QString>
#include <qtmetamacros.h>
/**
* We use a singleton instance of UpdateChannel, which can cause interference and feedback loops when multiple objects

View file

@ -2,15 +2,27 @@
#include "version_string.h"
#include <QByteArray>
#include <QDebug>
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
#include <QMessageBox>
#include <QJsonParseError>
#include <QJsonValue>
#include <QMap>
#include <QMessageLogger>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QNetworkRequest>
#include <QRegularExpression>
#include <QSysInfo>
#include <QRegularExpressionMatch>
#include <QUrl>
#include <QVariant>
#include <QVariantMap>
#include <QtGlobal>
#include <optional>
#include <qnamespace.h>
#include <qprocessordetection.h>
#if defined(Q_OS_MACOS)
#include <sys/sysctl.h>

View file

@ -11,8 +11,9 @@
#include <QLoggingCategory>
#include <QObject>
#include <QString>
#include <QVariantMap>
#include <QVariantList>
#include <optional>
#include <qtmetamacros.h>
#include <utility>
inline Q_LOGGING_CATEGORY(ReleaseChannelLog, "release_channel");

View file

@ -1,6 +1,14 @@
#include "update_downloader.h"
#include <QByteArray>
#include <QChar>
#include <QDir>
#include <QFile>
#include <QIODevice>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QUrl>
#include <QVariant>
UpdateDownloader::UpdateDownloader(QObject *parent) : QObject(parent), response(nullptr)
{

View file

@ -7,8 +7,14 @@
#ifndef COCKATRICE_UPDATEDOWNLOADER_H
#define COCKATRICE_UPDATEDOWNLOADER_H
#include <QNetworkReply>
#include <QObject>
#include <QtNetwork>
#include <QString>
#include <QUrl>
#include <QtGlobal>
#include <qtmetamacros.h>
class QNetworkAccessManager;
class UpdateDownloader : public QObject
{

View file

@ -2,15 +2,20 @@
#include "../network/update/client/release_channel.h"
#include "card_counter_settings.h"
#include "libcockatrice/interfaces/interface_card_database_path_provider.h"
#include "shortcuts_settings.h"
#include "version_string.h"
#include <QApplication>
#include <QDebug>
#include <QDir>
#include <QFile>
#include <QGlobalStatic>
#include <QMessageLogger>
#include <QSettings>
#include <QSharedPointer>
#include <QStandardPaths>
#include <QVariant>
#include <QtGlobal>
#include <libcockatrice/settings/appearance_settings.h>
#include <libcockatrice/settings/cache_storage_settings.h>
#include <libcockatrice/settings/card_database_settings.h>

View file

@ -7,11 +7,13 @@
#ifndef SETTINGSCACHE_H
#define SETTINGSCACHE_H
#include <QList>
#include <QLoggingCategory>
#include <QString>
#include <QStringList>
#include <libcockatrice/interfaces/interface_card_database_path_provider.h>
#include <libcockatrice/interfaces/interface_network_settings_provider.h>
#include <libcockatrice/utility/macros.h>
#include <qtmetamacros.h>
inline Q_LOGGING_CATEGORY(SettingsCacheLog, "settings_cache");

View file

@ -1,8 +1,15 @@
#include "card_counter_settings.h"
#include "libcockatrice/settings/settings_manager.h"
#include <QChar>
#include <QColor>
#include <QSettings>
#include <QVariant>
#include <QtMath>
#include <iterator>
class QObject;
CardCounterSettings::CardCounterSettings(const QString &settingsPath, QObject *parent)
: SettingsManager(settingsPath + "card_counters.ini", "cards", "counters", parent)

View file

@ -7,10 +7,12 @@
#ifndef CARD_COUNTER_SETTINGS_H
#define CARD_COUNTER_SETTINGS_H
#include <QString>
#include <libcockatrice/settings/settings_manager.h>
#include <qtmetamacros.h>
class QSettings;
class QColor;
class QObject;
class CardCounterSettings : public SettingsManager
{

View file

@ -3,7 +3,24 @@
#include "cache_settings.h"
#include "shortcuts_settings.h"
#include <QAbstractItemModel>
#include <QAbstractItemView>
#include <QFont>
#include <QHash>
#include <QHeaderView>
#include <QList>
#include <QModelIndex>
#include <QRegularExpression>
#include <QSharedPointer>
#include <QStandardItem>
#include <QStandardItemModel>
#include <QStringList>
#include <QVariant>
#include <algorithm>
#include <qnamespace.h>
class QObject;
class QWidget;
ShortcutFilterProxyModel::ShortcutFilterProxyModel(QObject *parent) : QSortFilterProxyModel(parent)
{

View file

@ -8,8 +8,13 @@
#define SHORTCUT_TREEVIEW_H
#include <QSortFilterProxyModel>
#include <QStandardItemModel>
#include <QString>
#include <QTreeView>
#include <qtmetamacros.h>
class QObject;
class QStandardItemModel;
class QWidget;
/**
* Custom implementation of QSortFilterProxyModel that appends the source and parent strings together when filtering

View file

@ -2,9 +2,13 @@
#include <QDebug>
#include <QFile>
#include <QMap>
#include <QMessageBox>
#include <QMessageLogger>
#include <QSettings>
#include <QSharedPointer>
#include <QStringList>
#include <utility>
#include <QVariant>
ShortcutKey::ShortcutKey(const QString &_name, QList<QKeySequence> _sequence, ShortcutGroup::Groups _group)
: QList<QKeySequence>(_sequence), name(_name), group(_group)

View file

@ -8,9 +8,18 @@
#define SHORTCUTSSETTINGS_H
#include <QApplication>
#include <QByteArray>
#include <QChar>
#include <QHash>
#include <QKeySequence>
#include <QList>
#include <QLoggingCategory>
#include <QSettings>
#include <QObject>
#include <QString>
#include <QStringList>
#include <QtGlobal>
#include <qtmetamacros.h>
#include <utility>
inline Q_LOGGING_CATEGORY(ShortcutsSettingsLog, "shortcuts_settings");

View file

@ -4,8 +4,15 @@
#include <QApplication>
#include <QAudioOutput>
#include <QDebug>
#include <QDir>
#include <QFile>
#include <QList>
#include <QMediaPlayer>
#include <QMessageLogger>
#include <QStringList>
#include <QUrl>
#include <QtGlobal>
#include <libcockatrice/settings/sound_settings.h>
#define DEFAULT_THEME_NAME "Default"

View file

@ -7,17 +7,17 @@
#ifndef SOUNDENGINE_H
#define SOUNDENGINE_H
#include <QAudioOutput>
#include <QLoggingCategory>
#include <QMap>
#include <QMediaPlayer>
#include <QObject>
#include <QString>
#include <qtmetamacros.h>
class QAudioOutput;
class QMediaPlayer;
inline Q_LOGGING_CATEGORY(SoundEngineLog, "sound_engine");
class QBuffer;
typedef QMap<QString, QString> QStringMap;
class SoundEngine : public QObject

View file

@ -13,11 +13,6 @@ public:
{
return SettingsCache::instance().cardOverrides().getCardPreferenceOverride(cardName);
}
[[nodiscard]] bool getIncludeRebalancedCards() const override
{
return SettingsCache::instance().cardsDisplay().getIncludeRebalancedCards();
}
};
#endif // COCKATRICE_SETTINGS_CARD_PREFERENCE_PROVIDER_H

View file

@ -1,9 +1,27 @@
#include "deck_filter_string.h"
#include "../interface/deck_loader/loaded_deck.h"
#include "libcockatrice/card/card_localization.h"
#include "libcockatrice/card/database/card_database_querier.h"
#include "libcockatrice/deck_list/deck_list.h"
#include "libcockatrice/deck_list/tree/deck_list_card_node.h"
#include <QByteArray>
#include <QDebug>
#include <QFileInfo>
#include <QList>
#include <QMessageLogger>
#include <QSharedPointer>
#include <algorithm>
#include <any>
#include <libcockatrice/card/database/card_database_manager.h>
#include <libcockatrice/filters/filter_string.h>
#include <libcockatrice/utility/peglib.h>
#include <mutex>
#include <qnamespace.h>
#include <stddef.h>
#include <string>
#include <vector>
static peg::parser search(R"(
Start <- QueryPartList

View file

@ -7,13 +7,14 @@
#ifndef DECK_FILTER_STRING_H
#define DECK_FILTER_STRING_H
#include "../interface/deck_loader/loaded_deck.h"
#include <QLoggingCategory>
#include <QString>
#include <functional>
#include <libcockatrice/card/card_localization.h>
struct CardSearchLanguage;
struct LoadedDeck;
inline Q_LOGGING_CATEGORY(DeckFilterStringLog, "deck_filter_string");
/**

View file

@ -5,8 +5,15 @@
#include <QComboBox>
#include <QGridLayout>
#include <QIcon>
#include <QPushButton>
#include <QSizePolicy>
#include <QString>
#include <QStringLiteral>
#include <QVariant>
#include <QtGlobal>
#include <libcockatrice/filters/filter_card.h>
#include <stddef.h>
FilterBuilder::FilterBuilder(QWidget *parent) : QWidget(parent)
{

View file

@ -8,8 +8,8 @@
#define FILTERBUILDER_H
#include <QWidget>
#include <qtmetamacros.h>
class QCheckBox;
class QComboBox;
class LineEditUnfocusable;
class CardFilter;

View file

@ -1,8 +1,15 @@
#include "filter_tree_model.h"
#include <QFlags>
#include <QFont>
#include <QString>
#include <QVariant>
#include <functional>
#include <libcockatrice/filters/filter_card.h>
#include <libcockatrice/filters/filter_tree.h>
#include <stddef.h>
class QObject;
FilterTreeModel::FilterTreeModel(QObject *parent) : QAbstractItemModel(parent)
{

View file

@ -8,11 +8,15 @@
#define FILTERTREEMODEL_H
#include <QAbstractItemModel>
#include <QList>
#include <QModelIndex>
#include <libcockatrice/filters/filter_card.h>
#include <qnamespace.h>
#include <qtmetamacros.h>
class FilterTree;
class CardFilter;
class FilterTreeNode;
class QObject;
class FilterTreeModel : public QAbstractItemModel
{

View file

@ -1,8 +1,21 @@
#include "syntax_help.h"
#include <QDebug>
#include <QFile>
#include <QFlags>
#include <QIODevice>
#include <QLineEdit>
#include <QMessageLogger>
#include <QObject>
#include <QRegularExpression>
#include <QSharedPointer>
#include <QSize>
#include <QString>
#include <QTextBrowser>
#include <QTextDocument>
#include <QTextStream>
#include <QUrl>
#include <qnamespace.h>
/**
* Creates the card search syntax help window

View file

@ -8,9 +8,10 @@
#ifndef SEARCH_SYNTAX_HELP_H
#define SEARCH_SYNTAX_HELP_H
#include <QLineEdit>
#include <QLoggingCategory>
#include <QTextBrowser>
class QLineEdit;
class QTextBrowser;
inline Q_LOGGING_CATEGORY(SyntaxHelpLog, "syntax_help");

View file

@ -1,7 +1,18 @@
#include "abstract_game.h"
#include "../interface/widgets/tabs/tab_game.h"
#include "game_event_handler.h"
#include "game_meta_info.h"
#include "game_state.h"
#include "libcockatrice/protocol/pb/game_replay.pb.h"
#include "player/player_info.h"
#include "player/player_logic.h"
#include "player/player_manager.h"
#include "zones/card_zone_logic.h"
#include <QList>
#include <QMap>
class AbstractClient;
AbstractGame::AbstractGame(QObject *_parent) : QObject(_parent)
{

View file

@ -7,15 +7,18 @@
#ifndef COCKATRICE_ABSTRACT_GAME_H
#define COCKATRICE_ABSTRACT_GAME_H
#include "game_event_handler.h"
#include "game_meta_info.h"
#include "game_state.h"
#include "player/player_manager.h"
#include <QObject>
#include <libcockatrice/protocol/pb/game_replay.pb.h>
#include <QString>
#include <qtmetamacros.h>
class CardItem;
class AbstractClient;
class GameEventHandler;
class GameMetaInfo;
class GameReplay;
class GameState;
class PlayerManager;
class AbstractGame : public QObject
{
Q_OBJECT

View file

@ -1,6 +1,9 @@
#include "arrow_registry.h"
#include "../game_graphics/board/arrow_item.h"
#include "board/arrow_data.h"
#include <QSharedPointer>
void ArrowRegistry::insert(QSharedPointer<ArrowData> data, ArrowItem *arrow)
{

View file

@ -1,13 +1,13 @@
#ifndef COCKATRICE_ARROW_REGISTRY_H
#define COCKATRICE_ARROW_REGISTRY_H
#include "board/arrow_data.h"
#include <QList>
#include <QMap>
#include <QSet>
#include <QSharedPointer>
class ArrowItem;
struct ArrowData;
template <class T> class QSharedPointer;
struct ArrowKey
{

View file

@ -1,5 +1,8 @@
#include "arrow_data.h"
#include "libcockatrice/protocol/pb/serverinfo_arrow.pb.h"
#include "libcockatrice/utility/color.h"
ArrowData ArrowData::fromProto(const ServerInfo_Arrow &arrow, int creatorId, bool isLocalCreator)
{
ArrowData data;

View file

@ -3,8 +3,8 @@
#include <QColor>
#include <QString>
#include <libcockatrice/protocol/pb/serverinfo_arrow.pb.h>
#include <libcockatrice/utility/color.h>
class ServerInfo_Arrow;
struct ArrowData
{

View file

@ -1,9 +1,14 @@
#include "card_list.h"
#include "../../game_graphics/board/card_item.h"
#include "libcockatrice/card/printing/exact_card.h"
#include <QChar>
#include <QDebug>
#include <QMessageLogger>
#include <QSharedPointer>
#include <algorithm>
#include <compare>
#include <libcockatrice/card/card_info.h>
CardList::CardList(bool _contentsKnown) : QList<CardItem *>(), contentsKnown(_contentsKnown)

View file

@ -9,6 +9,8 @@
#include <QList>
#include <QLoggingCategory>
#include <QString>
#include <functional>
inline Q_LOGGING_CATEGORY(CardListLog, "card_list");

View file

@ -1,5 +1,7 @@
#include "card_state.h"
#include <QSharedPointer>
void CardState::resetState(bool keepAnnotations)
{
attacking = false;

View file

@ -3,9 +3,12 @@
#include <QMap>
#include <QObject>
#include <QString>
#include <qtmetamacros.h>
class CardZoneLogic;
class CardItem;
class CardState : public QObject
{
Q_OBJECT

View file

@ -1,5 +1,7 @@
#include "counter_state.h"
#include "libcockatrice/protocol/pb/serverinfo_counter.pb.h"
#include <libcockatrice/utility/color.h>
CounterState::CounterState(int id, const QString &name, const QColor &color, int radius, int value, QObject *parent)

View file

@ -4,7 +4,9 @@
#include <QColor>
#include <QObject>
#include <QString>
#include <libcockatrice/protocol/pb/serverinfo_counter.pb.h>
#include <qtmetamacros.h>
class ServerInfo_Counter;
class CounterState : public QObject
{

View file

@ -1,9 +1,17 @@
#include "game.h"
#include "../interface/widgets/tabs/tab_game.h"
#include "game_meta_info.h"
#include "game_state.h"
#include "player/player_manager.h"
#include <QList>
#include <QMap>
#include <QString>
#include <libcockatrice/protocol/pb/event_game_joined.pb.h>
class AbstractClient;
class QObject;
Game::Game(QObject *_parent,
bool isLocalGame,
QList<AbstractClient *> &_clients,

View file

@ -9,7 +9,14 @@
#include "abstract_game.h"
#include <QObject>
#include <qtmetamacros.h>
class AbstractClient;
class Event_GameJoined;
class QObject;
class QString;
template <class Key, class T> class QMap;
template <typename T> class QList;
class Game : public AbstractGame
{

View file

@ -1,9 +1,30 @@
#include "game_event_handler.h"
#include "../game_graphics/log/message_log_widget.h"
#include "../interface/widgets/tabs/tab_game.h"
#include "abstract_game.h"
#include "game_meta_info.h"
#include "game_state.h"
#include "libcockatrice/protocol/pb/commands.pb.h"
#include "libcockatrice/protocol/pb/game_commands.pb.h"
#include "libcockatrice/protocol/pb/game_event.pb.h"
#include "libcockatrice/protocol/pb/game_event_context.pb.h"
#include "libcockatrice/protocol/pb/response.pb.h"
#include "libcockatrice/protocol/pb/serverinfo_game.pb.h"
#include "libcockatrice/protocol/pb/serverinfo_player.pb.h"
#include "libcockatrice/protocol/pb/serverinfo_playerproperties.pb.h"
#include "libcockatrice/protocol/pb/serverinfo_user.pb.h"
#include "player/player_event_handler.h"
#include "player/player_info.h"
#include "player/player_logic.h"
#include "player/player_manager.h"
#include <QList>
#include <QMap>
#include <QMapIterator>
#include <QMessageLogger>
#include <QSharedPointer>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/message.h>
#include <google/protobuf/stubs/port.h>
#include <libcockatrice/network/client/abstract/abstract_client.h>
#include <libcockatrice/protocol/get_pb_extension.h>
#include <libcockatrice/protocol/pb/command_concede.pb.h>
@ -13,7 +34,6 @@
#include <libcockatrice/protocol/pb/command_next_turn.pb.h>
#include <libcockatrice/protocol/pb/command_reverse_turn.pb.h>
#include <libcockatrice/protocol/pb/command_set_active_phase.pb.h>
#include <libcockatrice/protocol/pb/context_connection_state_changed.pb.h>
#include <libcockatrice/protocol/pb/context_deck_select.pb.h>
#include <libcockatrice/protocol/pb/event_game_closed.pb.h>
#include <libcockatrice/protocol/pb/event_game_host_changed.pb.h>
@ -28,6 +48,8 @@
#include <libcockatrice/protocol/pb/event_set_active_player.pb.h>
#include <libcockatrice/protocol/pb/game_event_container.pb.h>
#include <libcockatrice/protocol/pending_command.h>
#include <string>
#include <utility>
GameEventHandler::GameEventHandler(AbstractGame *_game) : QObject(_game), game(_game)
{

View file

@ -19,23 +19,29 @@
#include <QLoggingCategory>
#include <QObject>
#include <QPair>
#include <QString>
#include <QVector>
#include <libcockatrice/protocol/pb/event_leave.pb.h>
#include <qtmetamacros.h>
// IWYU pragma: keep
// GameEventContext, ServerInfo_Player and ServerInfo_User are passed by value
// to signals and slots, so the moc-generated code needs the complete types.
#include <libcockatrice/protocol/pb/game_event_context.pb.h>
#include <libcockatrice/protocol/pb/serverinfo_player.pb.h>
#include <libcockatrice/protocol/pb/serverinfo_user.pb.h>
class AbstractClient;
class AbstractGame;
class CommandContainer;
class GameCommand;
class GameEventContainer;
class GameEventContext;
class PendingCommand;
class PlayerLogic;
class Response;
class Event_GameStateChanged;
class Event_PlayerPropertiesChanged;
class Event_Join;
class Event_Leave;
class Event_GameHostChanged;
class Event_GameClosed;
class Event_SetActivePlayer;
@ -44,6 +50,15 @@ class Event_GameSay;
class Event_Kicked;
class Event_ReverseTurn;
class Event_Ping;
class ServerInfo_PlayerProperties;
namespace google
{
namespace protobuf
{
class Message;
} // namespace protobuf
} // namespace google
template <typename T> class QList;
inline Q_LOGGING_CATEGORY(GameEventHandlerLog, "game_event_handler");

View file

@ -9,13 +9,16 @@
#include <QMap>
#include <QObject>
#include <QString>
#include <libcockatrice/protocol/pb/serverinfo_game.pb.h>
#include <qtmetamacros.h>
// Translation layer class to expose protobuf safely and hook it up to Qt Signals.
// This class de-couples the domain object (i.e. the GameMetaInfo) from the network object.
// If the network object changes, only this class needs to be adjusted.
class AbstractGame;
class GameMetaInfo : public QObject
{
Q_OBJECT

View file

@ -2,6 +2,11 @@
#include "abstract_game.h"
#include <QChar>
#include <QTimer>
class AbstractClient;
GameState::GameState(AbstractGame *parent,
int _secondsElapsed,
int _hostId,

View file

@ -7,12 +7,14 @@
#ifndef COCKATRICE_GAME_STATE_H
#define COCKATRICE_GAME_STATE_H
#include <QTimer>
#include <libcockatrice/network/client/abstract/abstract_client.h>
#include <QList>
#include <QObject>
#include <QString>
#include <qtmetamacros.h>
class AbstractGame;
class ServerInfo_PlayerProperties;
class ServerInfo_User;
class AbstractClient;
class QTimer;
class GameState : public QObject
{

View file

@ -1,5 +1,10 @@
#include "phase.h"
#include <QByteArray>
#include <QList>
#include <QSharedPointer>
#include <QtGlobal>
Phase::Phase(const QString &_name, const QString &_color, const QString &_soundFileName)
: name(_name), color(_color), soundFileName(_soundFileName)
{

View file

@ -7,8 +7,9 @@
#ifndef PHASE_H
#define PHASE_H
#include <QApplication>
#include <QCoreApplication>
#include <QString>
#include <QVector>
class Phase
{

View file

@ -1,14 +1,54 @@
#include "player_actions.h"
#include "../../client/settings/cache_settings.h"
#include "../../game_graphics/board/card_item.h"
#include "../../game_graphics/dialogs/dlg_create_token.h"
#include "../../game_graphics/dialogs/dlg_move_top_cards_until.h"
#include "../../game_graphics/dialogs/dlg_roll_dice.h"
#include "../../game_graphics/player/card_menu_action_type.h"
#include "../../game_graphics/zones/hand_zone.h"
#include "../../game_graphics/zones/table_zone.h"
#include "../../interface/widgets/tabs/tab_game.h"
#include "../../interface/widgets/utility/get_text_with_max.h"
#include "../../interface/deck_loader/loaded_deck.h"
#include "../abstract_game.h"
#include "../board/counter_state.h"
#include "../game_event_handler.h"
#include "../zones/card_zone_logic.h"
#include "../zones/hand_zone_logic.h"
#include "../zones/pile_zone_logic.h"
#include "../zones/table_zone_logic.h"
#include "../zones/view_zone_logic.h"
#include "libcockatrice/card/database/card_database_querier.h"
#include "libcockatrice/card/printing/exact_card.h"
#include "libcockatrice/card/printing/printing_info.h"
#include "libcockatrice/card/relation/card_relation_type.h"
#include "libcockatrice/deck_list/deck_list.h"
#include "libcockatrice/filters/filter_string.h"
#include "libcockatrice/protocol/pb/card_attributes.pb.h"
#include "libcockatrice/protocol/pb/game_commands.pb.h"
#include "libcockatrice/settings/cards_display_settings.h"
#include "player_info.h"
#include "player_logic.h"
#include <QAction>
#include <QChar>
#include <QColor>
#include <QFlags>
#include <QInputDialog>
#include <QKeyEvent>
#include <QList>
#include <QMap>
#include <QMapIterator>
#include <QMetaType>
#include <QPoint>
#include <QPointF>
#include <QSharedPointer>
#include <QTimer>
#include <QVariant>
#include <QVariantList>
#include <QtGlobal>
#include <algorithm>
#include <functional>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/message.h>
#include <google/protobuf/stubs/port.h>
#include <libcockatrice/card/database/card_database_manager.h>
#include <libcockatrice/card/relation/card_relation.h>
#include <libcockatrice/protocol/pb/command_attach_card.pb.h>
@ -26,13 +66,16 @@
#include <libcockatrice/protocol/pb/command_set_card_counter.pb.h>
#include <libcockatrice/protocol/pb/command_shuffle.pb.h>
#include <libcockatrice/protocol/pb/command_undo_draw.pb.h>
#include <libcockatrice/protocol/pb/context_move_card.pb.h>
#include <libcockatrice/settings/card_override_settings.h>
#include <libcockatrice/settings/interface_settings.h>
#include <libcockatrice/utility/clamped_arithmetic.h>
#include <libcockatrice/utility/counter_limits.h>
#include <libcockatrice/utility/expression.h>
#include <libcockatrice/utility/zone_names.h>
#include <memory>
#include <qnamespace.h>
#include <qnumeric.h>
#include <string>
// milliseconds in between triggers of the move top cards until action
static constexpr int MOVE_TOP_CARD_UNTIL_INTERVAL = 100;

View file

@ -8,17 +8,25 @@
#ifndef COCKATRICE_PLAYER_ACTIONS_H
#define COCKATRICE_PLAYER_ACTIONS_H
#include "../../game_graphics/board/card_item.h"
#include "../../game_graphics/board/card_item.h" // IWYU pragma: keep - moc instantiates the metatype for QList<CardItem *>, which Qt 6.4 needs complete
#include "../../game_graphics/dialogs/dlg_create_token.h"
#include "../../game_graphics/dialogs/dlg_move_top_cards_until.h"
#include "../../game_graphics/player/card_menu_action_type.h"
#include "event_processing_options.h"
#include "player_logic.h"
#include "../board/card_list.h"
#include "libcockatrice/card/card_info.h"
#include <QMenu>
#include <QObject>
#include <QString>
#include <QStringList>
#include <libcockatrice/card/relation/card_relation_type.h>
#include <libcockatrice/filters/filter_string.h>
#include <qtmetamacros.h>
class CardItem;
class CardRelation;
class QAction;
class QTimer;
template <typename T> class QList;
namespace google
{
@ -29,9 +37,9 @@ class Message;
} // namespace google
class Command_MoveCard;
class GameEventContext;
class PendingCommand;
class PlayerLogic;
class PlayerActions : public QObject
{
Q_OBJECT

View file

@ -1,15 +1,32 @@
#include "player_event_handler.h"
#include "../../game_graphics/board/arrow_item.h"
#include "../../game_graphics/board/card_item.h"
#include "../../game_graphics/zones/view_zone.h"
#include "../../interface/widgets/tabs/tab_game.h"
#include "../abstract_game.h"
#include "../board/arrow_data.h"
#include "../board/card_list.h"
#include "../board/counter_state.h"
#include "../zones/card_zone_logic.h"
#include "../zones/hand_zone_logic.h"
#include "../zones/pile_zone_logic.h"
#include "libcockatrice/card/card_info.h"
#include "libcockatrice/card/printing/exact_card.h"
#include "libcockatrice/protocol/pb/card_attributes.pb.h"
#include "libcockatrice/protocol/pb/game_event.pb.h"
#include "libcockatrice/protocol/pb/game_event_context.pb.h"
#include "libcockatrice/protocol/pb/serverinfo_card.pb.h"
#include "libcockatrice/utility/card_ref.h"
#include "player_actions.h"
#include "player_info.h"
#include "player_logic.h"
#include "player_manager.h"
#include <libcockatrice/protocol/pb/command_set_card_attr.pb.h>
#include <QDebug>
#include <QList>
#include <QMap>
#include <QSharedPointer>
#include <QtGlobal>
#include <algorithm>
#include <libcockatrice/protocol/pb/context_move_card.pb.h>
#include <libcockatrice/protocol/pb/context_undo_draw.pb.h>
#include <libcockatrice/protocol/pb/event_attach_card.pb.h>
@ -32,8 +49,9 @@
#include <libcockatrice/protocol/pb/event_set_card_counter.pb.h>
#include <libcockatrice/protocol/pb/event_set_counter.pb.h>
#include <libcockatrice/protocol/pb/event_shuffle.pb.h>
#include <libcockatrice/utility/color.h>
#include <libcockatrice/utility/zone_names.h>
#include <qlogging.h>
#include <string>
PlayerEventHandler::PlayerEventHandler(PlayerLogic *_player) : QObject(_player), player(_player)
{

View file

@ -22,14 +22,14 @@
#include "event_processing_options.h"
#include <QObject>
#include <libcockatrice/protocol/pb/card_attributes.pb.h>
#include <QString>
#include <libcockatrice/protocol/pb/game_event.pb.h>
#include <libcockatrice/protocol/pb/game_event_context.pb.h>
#include <qtmetamacros.h>
#include <sys/types.h>
class CardItem;
class CardZoneLogic;
class PlayerLogic;
class Event_AttachCard;
class Event_ChangeZoneProperties;
class Event_CreateArrow;
@ -50,6 +50,9 @@ class Event_SetCardCounter;
class Event_SetCounter;
class Event_Shuffle;
class Event_GameLogNotice;
class GameEventContext;
enum CardAttribute : int;
template <typename T> class QList;
/**
* @class PlayerEventHandler

View file

@ -1,5 +1,7 @@
#include "player_info.h"
#include "libcockatrice/protocol/pb/serverinfo_user.pb.h"
PlayerInfo::PlayerInfo(const ServerInfo_User &info, int _id, bool _local, bool _judge)
: id(_id), local(_local), judge(_judge)
{

View file

@ -7,10 +7,10 @@
#ifndef COCKATRICE_PLAYER_INFO_H
#define COCKATRICE_PLAYER_INFO_H
#include "../../game_graphics/player/player_target.h"
#include <QObject>
#include <QString>
#include <libcockatrice/protocol/pb/serverinfo_user.pb.h>
#include <qtmetamacros.h>
class PlayerInfo : public QObject
{

View file

@ -1,33 +1,37 @@
#include "player_logic.h"
#include "../../game_graphics/board/arrow_item.h"
#include "../../game_graphics/board/card_item.h"
#include "../../game_graphics/board/counter_general.h"
#include "../../game_graphics/game_scene.h"
#include "../../game_graphics/player/player_target.h"
#include "../../game_graphics/zones/hand_zone.h"
#include "../../game_graphics/zones/pile_zone.h"
#include "../../game_graphics/zones/stack_zone.h"
#include "../../game_graphics/zones/table_zone.h"
#include "../../interface/theme_manager.h"
#include "../../interface/widgets/tabs/tab_game.h"
#include "../board/card_list.h"
#include "../abstract_game.h"
#include "../board/arrow_data.h"
#include "../board/counter_state.h"
#include "../game_meta_info.h"
#include "../zones/hand_zone_logic.h"
#include "../zones/pile_zone_logic.h"
#include "../zones/stack_zone_logic.h"
#include "../zones/table_zone_logic.h"
#include "libcockatrice/protocol/pb/serverinfo_card.pb.h"
#include "libcockatrice/protocol/pb/serverinfo_counter.pb.h"
#include "libcockatrice/protocol/pb/serverinfo_playerproperties.pb.h"
#include "libcockatrice/utility/zone_names.h"
#include "player_actions.h"
#include "player_event_handler.h"
#include "player_info.h"
#include "player_manager.h"
#include <QDebug>
#include <QMenu>
#include <QMetaType>
#include <QPainter>
#include <QtConcurrent>
#include <libcockatrice/protocol/pb/command_attach_card.pb.h>
#include <libcockatrice/protocol/pb/command_set_card_counter.pb.h>
#include <libcockatrice/protocol/pb/event_create_arrow.pb.h>
#include <libcockatrice/protocol/pb/event_create_counter.pb.h>
#include <libcockatrice/protocol/pb/event_draw_cards.pb.h>
#include <QMapIterator>
#include <QMessageLogger>
#include <QMutableMapIterator>
#include <QSet>
#include <QSharedPointer>
#include <QtGlobal>
#include <libcockatrice/protocol/pb/serverinfo_player.pb.h>
#include <libcockatrice/protocol/pb/serverinfo_user.pb.h>
#include <libcockatrice/protocol/pb/serverinfo_zone.pb.h>
#include <libcockatrice/utility/card_ref.h>
#include <libcockatrice/utility/color.h>
#include <qalgorithms.h>
#include <string>
PlayerLogic::PlayerLogic(const ServerInfo_User &info, int _id, bool _local, bool _judge, AbstractGame *_parent)
: QObject(_parent), game(_parent), playerInfo(new PlayerInfo(info, _id, _local, _judge)),

View file

@ -7,57 +7,48 @@
#ifndef PLAYER_H
#define PLAYER_H
#include "../../game_graphics/player/player_area.h"
#include "../../interface/widgets/menus/tearoff_menu.h"
#include "../board/arrow_data.h"
#include "../interface/deck_loader/loaded_deck.h"
#include "../zones/card_zone_logic.h"
#include "../zones/hand_zone_logic.h"
#include "../zones/pile_zone_logic.h"
#include "../zones/stack_zone_logic.h"
#include "../zones/table_zone_logic.h"
#include "player_event_handler.h"
#include "player_info.h"
#include "player_manager.h"
#include "libcockatrice/deck_list/deck_list.h"
#include "libcockatrice/utility/card_ref.h"
#include "libcockatrice/utility/playmat_params.h"
#include <QColor>
#include <QInputDialog>
#include <QList>
#include <QLoggingCategory>
#include <QMap>
#include <QTimer>
#include <libcockatrice/filters/filter_string.h>
#include <libcockatrice/protocol/pb/card_attributes.pb.h>
#include <libcockatrice/protocol/pb/game_event.pb.h>
#include <QObject>
#include <QString>
#include <libcockatrice/utility/zone_names.h>
#include <qtmetamacros.h>
// IWYU pragma: keep
// ServerInfo_Card appears inside QList<...> in signal and slot
// signatures, which the moc-generated code needs to be complete.
#include <libcockatrice/protocol/pb/serverinfo_card.pb.h>
class CardItem;
class CounterState;
class QWidget;
class ServerInfo_PlayerProperties;
struct ArrowData;
struct LoadedDeck;
template <class T> class QSharedPointer;
inline Q_LOGGING_CATEGORY(PlayerLog, "player");
namespace google
{
namespace protobuf
{
class Message;
}
} // namespace google
class AbstractCardItem;
class AbstractGame;
class ArrowItem;
class ArrowTarget;
class CardDatabase;
class CardZone;
class CommandContainer;
class GameCommand;
class GameEvent;
class PlayerInfo;
class PlayerEventHandler;
class PlayerActions;
class PlayerMenu;
class QAction;
class QMenu;
class ServerInfo_Arrow;
class ServerInfo_Card;
class ServerInfo_Counter;
class ServerInfo_Player;
class ServerInfo_User;
class TabGame;
const int MAX_TOKENS_PER_DIALOG = 99;

View file

@ -1,8 +1,14 @@
#include "player_manager.h"
#include "../abstract_game.h"
#include "../game_state.h"
#include "player_info.h"
#include "player_logic.h"
#include <QList>
#include <QMapIterator>
#include <QSharedPointer>
PlayerManager::PlayerManager(AbstractGame *_game,
int _localPlayerId,
bool _localPlayerIsJudge,

View file

@ -7,12 +7,17 @@
#ifndef COCKATRICE_PLAYER_MANAGER_H
#define COCKATRICE_PLAYER_MANAGER_H
#include "libcockatrice/protocol/pb/serverinfo_user.pb.h"
#include <QMap>
#include <QObject>
#include <QString>
#include <libcockatrice/protocol/pb/serverinfo_playerproperties.pb.h>
#include <qtmetamacros.h>
class AbstractGame;
class PlayerLogic;
class PlayerManager : public QObject
{
Q_OBJECT

View file

@ -1,6 +1,13 @@
#include "replay.h"
#include "../interface/widgets/tabs/tab_game.h"
#include "game_meta_info.h"
#include "game_state.h"
#include "player/player_manager.h"
#include <QList>
class GameReplay;
class QObject;
Replay::Replay(QObject *_parent, const GameReplay *_replay, bool isLocalGame) : AbstractGame(_parent)
{

View file

@ -10,6 +10,11 @@
#include "abstract_game.h"
#include <qtmetamacros.h>
class GameReplay;
class QObject;
class Replay : public AbstractGame
{
Q_OBJECT

View file

@ -1,16 +1,25 @@
#include "card_zone_logic.h"
#include "../../client/translation.h"
#include "../../game_graphics/board/card_item.h"
#include "../../game_graphics/zones/card_zone.h"
#include "../../game_graphics/zones/view_zone.h"
#include "../board/card_list.h"
#include "../player/player_actions.h"
#include "../player/player_info.h"
#include "../player/player_logic.h"
#include "libcockatrice/card/database/card_database.h"
#include "view_zone_logic.h"
#include <QAction>
#include <QDebug>
#include <QMessageLogger>
#include <QSharedPointer>
#include <QVariant>
#include <libcockatrice/card/database/card_database_manager.h>
#include <libcockatrice/protocol/pb/command_move_card.pb.h>
#include <libcockatrice/utility/zone_names.h>
#include <string>
/**
* @param _player the player that the zone belongs to

View file

@ -10,17 +10,18 @@
#include "../../client/translation.h"
#include "../board/card_list.h"
#include <QList>
#include <QLoggingCategory>
#include <QObject>
#include <QString>
#include <qtmetamacros.h>
class CardItem;
inline Q_LOGGING_CATEGORY(CardZoneLogicLog, "card_zone_logic");
class PlayerLogic;
class ZoneViewZone;
class QMenu;
class QAction;
class QPainter;
class CardDragItem;
class CardZoneLogic : public QObject
{

View file

@ -3,6 +3,9 @@
#include "../../game_graphics/board/card_item.h"
#include "card_zone_algorithms.h"
class PlayerLogic;
class QObject;
HandZoneLogic::HandZoneLogic(PlayerLogic *_player,
const QString &_name,
bool _hasCardAttr,

View file

@ -8,6 +8,12 @@
#define COCKATRICE_HAND_ZONE_LOGIC_H
#include "card_zone_logic.h"
#include <QString>
#include <qtmetamacros.h>
class PlayerLogic;
class QObject;
class HandZoneLogic : public CardZoneLogic
{
Q_OBJECT

View file

@ -1,6 +1,10 @@
#include "pile_zone_logic.h"
#include "../../game_graphics/board/card_item.h"
#include "../board/card_list.h"
class PlayerLogic;
class QObject;
PileZoneLogic::PileZoneLogic(PlayerLogic *_player,
const QString &_name,

View file

@ -8,6 +8,12 @@
#define COCKATRICE_PILE_ZONE_LOGIC_H
#include "card_zone_logic.h"
#include <QString>
#include <qtmetamacros.h>
class PlayerLogic;
class QObject;
class PileZoneLogic : public CardZoneLogic
{

View file

@ -3,6 +3,9 @@
#include "../../game_graphics/board/card_item.h"
#include "card_zone_algorithms.h"
class PlayerLogic;
class QObject;
StackZoneLogic::StackZoneLogic(PlayerLogic *_player,
const QString &_name,
bool _hasCardAttr,

View file

@ -8,6 +8,12 @@
#define COCKATRICE_STACK_ZONE_LOGIC_H
#include "card_zone_logic.h"
#include <QString>
#include <qtmetamacros.h>
class PlayerLogic;
class QObject;
class StackZoneLogic : public CardZoneLogic
{
Q_OBJECT

View file

@ -1,6 +1,13 @@
#include "table_zone_logic.h"
#include "../../game_graphics/board/card_item.h"
#include "../board/card_list.h"
#include "libcockatrice/card/card_info.h"
#include <QPoint>
class PlayerLogic;
class QObject;
TableZoneLogic::TableZoneLogic(PlayerLogic *_player,
const QString &_name,

View file

@ -8,6 +8,12 @@
#define COCKATRICE_TABLE_ZONE_LOGIC_H
#include "card_zone_logic.h"
#include <QString>
#include <qtmetamacros.h>
class PlayerLogic;
class QObject;
class TableZoneLogic : public CardZoneLogic
{
Q_OBJECT

View file

@ -2,8 +2,14 @@
#include "../../client/settings/cache_settings.h"
#include "../../game_graphics/board/card_item.h"
#include "../board/card_list.h"
#include <QtGlobal>
#include <libcockatrice/settings/interface_settings.h>
class PlayerLogic;
class QObject;
/**
* @param _player the player that the cards are revealed to.
* @param _origZone the zone the cards were revealed from.

View file

@ -8,6 +8,11 @@
#define COCKATRICE_VIEW_ZONE_LOGIC_H
#include "card_zone_logic.h"
#include <qtmetamacros.h>
class PlayerLogic;
class QObject;
class ZoneViewZoneLogic : public CardZoneLogic
{
Q_OBJECT

View file

@ -2,12 +2,20 @@
#include "../../client/settings/cache_settings.h"
#include "../z_values.h"
#include "abstract_card_item.h"
#include <QBrush>
#include <QColor>
#include <QCursor>
#include <QDebug>
#include <QGraphicsSceneMouseEvent>
#include <QPainter>
#include <QPainterPath>
#include <QTransform>
#include <QtGlobal>
#include <libcockatrice/settings/cards_display_settings.h>
#include <qnamespace.h>
class QPointF;
const QColor GHOST_MASK = QColor(255, 255, 255, 50);

View file

@ -7,11 +7,17 @@
#ifndef ABSTRACTCARDDRAGITEM_H
#define ABSTRACTCARDDRAGITEM_H
#include "abstract_card_item.h"
#include "../card_dimensions.h"
#include "graphics_item_type.h"
class QGraphicsScene;
class CardZone;
class CardInfo;
#include <QGraphicsItem>
#include <QList>
#include <QObject>
#include <QPointF>
#include <QRectF>
#include <qtmetamacros.h>
class AbstractCardItem;
class AbstractCardDragItem : public QObject, public QGraphicsItem
{

View file

@ -3,19 +3,42 @@
#include "../../client/settings/cache_settings.h"
#include "../../interface/card_localization.h"
#include "../../interface/card_picture_loader/card_picture_loader.h"
#include "../card_dimensions.h"
#include "../game_scene.h"
#include "../z_values.h"
#include "abstract_graphics_item.h"
#include "libcockatrice/card/card_info.h"
#include "libcockatrice/card/database/card_database_querier.h"
#include "libcockatrice/card/printing/exact_card.h"
#include "libcockatrice/utility/card_ref.h"
#include <QBrush>
#include <QChar>
#include <QCursor>
#include <QFlags>
#include <QFont>
#include <QGraphicsScene>
#include <QGraphicsSceneMouseEvent>
#include <QHash>
#include <QLineF>
#include <QList>
#include <QPainter>
#include <QPainterPath>
#include <QPen>
#include <QPixmap>
#include <QPointF>
#include <QRectF>
#include <QTransform>
#include <QVariant>
#include <QtGlobal>
#include <algorithm>
#include <libcockatrice/card/database/card_database.h>
#include <libcockatrice/card/database/card_database_manager.h>
#include <libcockatrice/settings/appearance_settings.h>
#include <libcockatrice/settings/cards_display_settings.h>
#include <libcockatrice/settings/debug_settings.h>
#include <qnamespace.h>
class QSizeF;
AbstractCardItem::AbstractCardItem(QGraphicsItem *parent, const CardRef &cardRef, PlayerLogic *_owner, int _id)
: ArrowTarget(_owner, parent), id(_id), cardRef(cardRef), tapped(false), facedown(false), tapAngle(0),

View file

@ -8,14 +8,22 @@
#define ABSTRACTCARDITEM_H
#include "../animated_item.h"
#include "../card_dimensions.h"
#include "arrow_target.h"
#include "graphics_item_type.h"
#include <QColor>
#include <QGraphicsItem>
#include <QSizeF>
#include <QString>
#include <QtGlobal>
#include <libcockatrice/card/printing/exact_card.h>
#include <libcockatrice/utility/card_ref.h>
#include <qtmetamacros.h>
class PlayerLogic;
class CardInfo;
class QPainter;
class QPoint;
class AbstractCardItem : public ArrowTarget, public IAnimatedItem
{

View file

@ -2,21 +2,33 @@
#include "../../client/settings/cache_settings.h"
#include "../../client/settings/shortcuts_settings.h"
#include "../../game/board/counter_state.h"
#include "../../game/player/player_actions.h"
#include "../../game/player/player_info.h"
#include "../../game/player/player_logic.h"
#include "../../game_graphics/board/translate_counter_name.h"
#include "../../interface/widgets/tabs/tab_game.h"
#include "../../interface/widgets/menus/tearoff_menu.h"
#include <QAction>
#include <QApplication>
#include <QEvent>
#include <QFlags>
#include <QGraphicsScene>
#include <QGraphicsSceneMouseEvent>
#include <QGraphicsView>
#include <QKeyEvent>
#include <QMenu>
#include <QKeySequence>
#include <QList>
#include <QSharedPointer>
#include <QString>
#include <QVariant>
#include <QtGlobal>
#include <libcockatrice/protocol/pb/command_inc_counter.pb.h>
#include <libcockatrice/protocol/pb/command_set_counter.pb.h>
#include <libcockatrice/utility/expression.h>
#include <qnamespace.h>
class QWidget;
AbstractCounter::AbstractCounter(CounterState *state,
PlayerLogic *_player,

View file

@ -7,18 +7,21 @@
#ifndef COUNTER_H
#define COUNTER_H
#include "../../game/board/counter_state.h"
#include "../../interface/widgets/menus/tearoff_menu.h"
#include "../player/menu/abstract_player_component.h"
#include <QColor>
#include <QGraphicsItem>
#include <QInputDialog>
#include <QObject>
#include <QString>
#include <qtmetamacros.h>
class PlayerLogic;
class QAction;
class QKeyEvent;
class QMenu;
class QString;
class CounterState;
class QWidget;
class AbstractCounter : public QObject, public QGraphicsItem, public AbstractPlayerComponent
{

View file

@ -1,6 +1,14 @@
#include "abstract_graphics_item.h"
#include <QBrush>
#include <QFont>
#include <QFontMetrics>
#include <QPainter>
#include <QRectF>
#include <QString>
#include <QTransform>
#include <QtGlobal>
#include <qnamespace.h>
void AbstractGraphicsItem::paintNumberEllipse(int number,
int fontSize,

View file

@ -7,7 +7,12 @@
#ifndef ABSTRACTGRAPHICSITEM_H
#define ABSTRACTGRAPHICSITEM_H
#include <QGraphicsItem>
#include <QColor>
#include <QGraphicsObject>
#include <qtmetamacros.h>
class QGraphicsItem;
class QPainter;
/**
* Parent class of all objects that appear in a game.

View file

@ -2,28 +2,42 @@
#include "arrow_item.h"
#include "../../client/settings/cache_settings.h"
#include "../../game/board/arrow_data.h"
#include "../../game/player/player_actions.h"
#include "../../game/player/player_info.h"
#include "../../game/player/player_logic.h"
#include "../../game/zones/card_zone_logic.h"
#include "../game_scene.h"
#include "../player/player_target.h"
#include "../z_values.h"
#include "../zones/card_zone.h"
#include "card_item.h"
#include "libcockatrice/card/printing/exact_card.h"
#include "libcockatrice/protocol/pb/color.pb.h"
#include <QDebug>
#include <QBrush>
#include <QElapsedTimer>
#include <QGraphicsScene>
#include <QGraphicsSceneMouseEvent>
#include <QLineF>
#include <QLinearGradient>
#include <QPainter>
#include <QPen>
#include <QPoint>
#include <QString>
#include <QTransform>
#include <QtGlobal>
#include <QtMath>
#include <libcockatrice/card/card_info.h>
#include <libcockatrice/protocol/pb/command_attach_card.pb.h>
#include <libcockatrice/protocol/pb/command_create_arrow.pb.h>
#include <libcockatrice/protocol/pb/command_delete_arrow.pb.h>
#include <libcockatrice/settings/cards_display_settings.h>
#include <libcockatrice/settings/interface_settings.h>
#include <libcockatrice/utility/color.h>
#include <libcockatrice/utility/zone_names.h>
#include <math.h>
#include <qnamespace.h>
#include <string>
#include <utility>
namespace
{

Some files were not shown because too many files have changed in this diff Show more