Plugins: a dedicated server's plugins show players cards and ask them polls

A server plugin could only reach players through chat lines (say, tell).
A mode that asks players something (which track next, join the next
round) had to read chat commands, and could not show a card.

reskate.server.card(who, text, seconds) and reskate.server.poll(who,
question, answers, {seconds}) put a card or a poll on the screens of a
player, a list of players or "all", in the slot the roster already has
for the server's announcement and vote, so games need nothing new and
the protocol is unchanged. Each player's is their own and shows over the
server's until it ends, then the server's shows again. A poll has one id
for everyone it asks; a player's answer ("/2", as the game sends it)
closes it for them and comes back to the plugin that asked as a
poll_answer event; a poll that runs out, is replaced by a newer one for
that player, is closed with reskate.server.poll_close, or whose player
leaves comes back as poll_closed with why. The plugin counts the answers.

Both need the "server" permission and a server copy on a dedicated
server; a lobby's host has no roster slot for them. Answering a plugin's
poll is not a server vote, so it does not ask the player's role for
"votes". A plugin that stops takes its cards and polls with it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SYabE7FCPgj3SaWeF92EML
This commit is contained in:
Robin MoellerandClaude Opus 5.5 committed 2026-10-23 15:51:15 +02:00
1 parent 0706730e79
commit d6cf244c26
10 files changed
+507 -6

No files matched your search

+15
View File
@@ -90,6 +90,21 @@ class ServerGame final : public Game {
return host_.plugin_park(plugin, true, name, minutes);
}
std::string remove_park(std::string_view plugin, std::string_view name) override { return host_.plugin_park(plugin, false, name, 0); }
// Cards and polls on the players' screens, as the roster carries the server's own.
std::string server_card(std::string_view plugin, const std::vector<std::uint64_t> &players, std::string_view text, unsigned seconds) override {
return host_.plugin_card(plugin, players, text, seconds);
}
std::string server_poll(std::string_view plugin, const std::vector<std::uint64_t> &players, std::string_view question,
const std::vector<std::string> &answers, unsigned seconds, std::uint32_t &id) override {
return host_.plugin_poll(plugin, players, question, answers, seconds, id);
}
std::string server_poll_close(std::string_view plugin, std::uint32_t id) override { return host_.plugin_poll_close(plugin, id); }
std::vector<PollNews> take_poll_news() override {
std::vector<PollNews> news;
for (auto &n : host_.take_poll_news()) news.push_back({std::move(n.plugin), n.id, n.player, n.answer, std::move(n.text), std::move(n.why)});
return news;
}
void release(std::string_view plugin) override { host_.plugin_screens_release(plugin); }
// The skaters of the players in the world, as their latest poses put them. The server has
// no skater of its own, so this is every player's.
std::vector<PeerSkater> peer_skaters() override {