[Game] Playmats (#7101)

* [Game] Playmats

Took 19 seconds

Took 1 minute

* [Playmats] Add fixed override and configurable fallbacks to settings.

Took 29 minutes

Took 43 seconds

* Add main to test.

Took 1 minute

Took 29 seconds

* Move settings to own group

Took 11 minutes

* Some attempts to refresh macOS compositor

Took 2 minutes

* Try something else

Took 17 minutes

* Don't manipulate live list

Took 11 minutes

* Change things about resolution, address comments.

Took 45 minutes

Took 12 minutes

* Comments.

Took 14 minutes

Took 8 seconds

* Re-order settings menu location

Took 2 minutes

* Rename PlaymatResolution to Info and add enums

Took 8 minutes

---------

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
This commit is contained in:
BruebachL 2026-08-21 10:40:49 +02:00 • committed by GitHub
parent 74a454552a
commit 9eafd90a91
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
52 changed files with 1931 additions and 28 deletions

View file

@ -37,6 +37,7 @@
#include <libcockatrice/protocol/pb/command_set_card_attr.pb.h>
#include <libcockatrice/protocol/pb/command_set_card_counter.pb.h>
#include <libcockatrice/protocol/pb/command_set_counter.pb.h>
#include <libcockatrice/protocol/pb/command_set_playmat.pb.h>
#include <libcockatrice/protocol/pb/command_set_sideboard_lock.pb.h>
#include <libcockatrice/protocol/pb/command_set_sideboard_plan.pb.h>
#include <libcockatrice/protocol/pb/command_shuffle.pb.h>
@ -144,6 +145,13 @@ Response::ResponseCode Server_AbstractParticipant::cmdSetSideboardLock(const Com
return Response::RespFunctionNotAllowed;
}
Response::ResponseCode Server_AbstractParticipant::cmdSetPlaymat(const Command_SetPlaymat & /*cmd*/,
ResponseContainer & /*rc*/,
GameEventStorage & /*ges*/)
{
return Response::RespFunctionNotAllowed;
}
Response::ResponseCode Server_AbstractParticipant::cmdConcede(const Command_Concede & /*cmd*/,
ResponseContainer & /*rc*/,
GameEventStorage & /*ges*/)
@ -525,6 +533,9 @@ Server_AbstractParticipant::processGameCommand(const GameCommand &command, Respo
case GameCommand::REVERSE_TURN:
return cmdReverseTurn(command.GetExtension(Command_ReverseTurn::ext), rc, ges);
break;
case GameCommand::SET_PLAYMAT:
return cmdSetPlaymat(command.GetExtension(Command_SetPlaymat::ext), rc, ges);
break;
default:
return Response::RespInvalidCommand;
}

View file

@ -52,6 +52,7 @@ class Command_SetSideboardPlan;
class Command_DeckSelect;
class Command_SetSideboardLock;
class Command_ChangeZoneProperties;
class Command_SetPlaymat;
class Server_AbstractParticipant : public Server_ArrowTarget, public ServerInfo_User_Container
{
@ -124,6 +125,8 @@ public:
cmdSetSideboardPlan(const Command_SetSideboardPlan &cmd, ResponseContainer &rc, GameEventStorage &ges);
virtual Response::ResponseCode
cmdSetSideboardLock(const Command_SetSideboardLock &cmd, ResponseContainer &rc, GameEventStorage &ges);
virtual Response::ResponseCode
cmdSetPlaymat(const Command_SetPlaymat &cmd, ResponseContainer &rc, GameEventStorage &ges);
virtual Response::ResponseCode cmdGameSay(const Command_GameSay &cmd, ResponseContainer &rc, GameEventStorage &ges);
virtual Response::ResponseCode cmdShuffle(const Command_Shuffle &cmd, ResponseContainer &rc, GameEventStorage &ges);
virtual Response::ResponseCode

View file

@ -1653,5 +1653,13 @@ void Server_AbstractPlayer::getPlayerProperties(ServerInfo_PlayerProperties &res
result.set_ready_start(readyStart);
if (deck) {
result.set_deck_hash(deck->getDeckHash().toStdString());
const auto &playmat = deck->getPlaymat();
auto *playmatParams = result.mutable_playmat_params();
playmatParams->set_card_name(playmat.card.name.toStdString());
playmatParams->set_card_provider_id(playmat.card.providerId.toStdString());
playmatParams->set_margin_pct_l(playmat.params.marginPctL);
playmatParams->set_margin_pct_r(playmat.params.marginPctR);
playmatParams->set_vertical_offset(playmat.params.verticalOffset);
playmatParams->set_zoom(playmat.params.zoom);
}
}

View file

@ -27,6 +27,7 @@
#include <libcockatrice/protocol/pb/command_mulligan.pb.h>
#include <libcockatrice/protocol/pb/command_set_active_phase.pb.h>
#include <libcockatrice/protocol/pb/command_set_counter.pb.h>
#include <libcockatrice/protocol/pb/command_set_playmat.pb.h>
#include <libcockatrice/protocol/pb/command_set_sideboard_lock.pb.h>
#include <libcockatrice/protocol/pb/command_set_sideboard_plan.pb.h>
#include <libcockatrice/protocol/pb/command_shuffle.pb.h>
@ -250,6 +251,14 @@ Server_Player::cmdDeckSelect(const Command_DeckSelect &cmd, ResponseContainer &r
Event_PlayerPropertiesChanged event;
event.mutable_player_properties()->set_sideboard_locked(true);
event.mutable_player_properties()->set_deck_hash(deck->getDeckHash().toStdString());
const auto &playmat = deck->getPlaymat();
auto *playmatParams = event.mutable_player_properties()->mutable_playmat_params();
playmatParams->set_card_name(playmat.card.name.left(MAX_NAME_LENGTH).toStdString());
playmatParams->set_card_provider_id(playmat.card.providerId.left(MAX_NAME_LENGTH).toStdString());
playmatParams->set_margin_pct_l(playmat.params.marginPctL);
playmatParams->set_margin_pct_r(playmat.params.marginPctR);
playmatParams->set_vertical_offset(playmat.params.verticalOffset);
playmatParams->set_zoom(playmat.params.zoom);
ges.enqueueGameEvent(event, playerId);
Context_DeckSelect context;
@ -594,6 +603,46 @@ Server_Player::cmdReverseTurn(const Command_ReverseTurn &cmd, ResponseContainer
return Server_AbstractParticipant::cmdReverseTurn(cmd, rc, ges);
}
Response::ResponseCode
Server_Player::cmdSetPlaymat(const Command_SetPlaymat &cmd, ResponseContainer &rc, GameEventStorage &ges)
{
Q_UNUSED(rc);
if (!deck) {
return Response::RespContextError;
}
const auto &pp = cmd.playmat_params();
const auto rawName = QString::fromStdString(pp.card_name());
const auto rawProviderId = QString::fromStdString(pp.card_provider_id());
if (rawName.length() > MAX_NAME_LENGTH || rawProviderId.length() > MAX_NAME_LENGTH) {
return Response::RespInvalidData;
}
PlaymatInfo playmat;
playmat.card.name = rawName;
playmat.card.providerId = rawProviderId;
playmat.params.marginPctL = qBound(0.0, pp.margin_pct_l(), 0.95);
playmat.params.marginPctR = qBound(0.0, pp.margin_pct_r(), 0.95);
playmat.params.verticalOffset = qBound(0.0, pp.vertical_offset(), 1.0);
playmat.params.zoom = qBound(0.1, pp.zoom(), 4.0);
deck->setPlaymat(playmat);
Event_PlayerPropertiesChanged event;
auto *props = event.mutable_player_properties();
props->set_sideboard_locked(sideboardLocked);
props->set_deck_hash(deck->getDeckHash().toStdString());
auto *playmatParams = props->mutable_playmat_params();
playmatParams->set_card_name(playmat.card.name.toStdString());
playmatParams->set_card_provider_id(playmat.card.providerId.toStdString());
playmatParams->set_margin_pct_l(playmat.params.marginPctL);
playmatParams->set_margin_pct_r(playmat.params.marginPctR);
playmatParams->set_vertical_offset(playmat.params.verticalOffset);
playmatParams->set_zoom(playmat.params.zoom);
ges.enqueueGameEvent(event, playerId);
return Response::RespOk;
}
void Server_Player::getInfo(ServerInfo_Player *info,
Server_AbstractParticipant *recipient,
bool omniscient,

View file

@ -62,6 +62,8 @@ public:
cmdSetActivePhase(const Command_SetActivePhase &cmd, ResponseContainer &rc, GameEventStorage &ges) override;
Response::ResponseCode
cmdReverseTurn(const Command_ReverseTurn & /*cmd*/, ResponseContainer & /*rc*/, GameEventStorage &ges) override;
Response::ResponseCode
cmdSetPlaymat(const Command_SetPlaymat &cmd, ResponseContainer &rc, GameEventStorage &ges) override;
Response::ResponseCode cmdChangeZoneProperties(const Command_ChangeZoneProperties &cmd,
ResponseContainer &rc,
GameEventStorage &ges) override;