Commit Graph
7 Commits
Author SHA1 Message Date
AyeZeeBB 60cd8395d9 Merge pull request #351 from moelrobi/plugins/server-cards-content-w2s
Plugins: server cards and polls, mods.content on dedicated servers, world_to_screen bounds

Conflicts in the plugin and server plugin tests, where #348's role tests and this PR's tests were
added in the same places: both kept.
2026-10-23 15:56:02 -05:00
Robin MoellerandClaude Opus 5.5 d6cf244c26 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
2026-10-23 15:51:15 +02:00
Robin MoellerandClaude Opus 5.5 0706730e79 Plugins: mods.content and read_content read the server's Mods on a dedicated server
A server plugin with mods.read could call reskate.mods.content, but the
server's game had no content of its own, so it got nil and "not
available". A mode that keeps its data in mods (a race reading start
and finish from a park mod) could only read it in the players' games.

The server now answers from every mod folder in its Mods, by name, as it
finds its maps there; it has no load order or mods.json. A hidden folder
(.reskate_plugin_data) and names a plugin could not ask for are left out,
and a mod's title is its manifest.json's "name".

The listing and reading moved from plugin_game_runtime.cpp into
plugin_content.cpp, which the game and the server share, so both keep
the same limits: the folders the manifest's "content" names, 1000 files,
four folders deep, 1 MB a file, nothing outside the mod's folder. The
game's side is unchanged apart from calling it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SYabE7FCPgj3SaWeF92EML
2026-10-23 15:50:55 +02:00
Robin MoellerandClaude Opus 5.5 71e3460182 Plugins: server plugins know each player's role
A server plugin could not see the roles of a dedicated server (data/roles.json), so a plugin that
wanted only moderators to use some of its commands had to keep its own list of SteamIDs. In a
server copy with the server permission, a player table now has role: a read-only {name, rank,
staff}, the role the player has now (the one given them, or the server's default), read from the
server each time. staff is whether the role gives any of the server's commands. It is nil for a
player with no role, for the server itself and on a lobby's host. Each read counts as a server call.

dingosdk_server_plugin_tests reads a given role, the default role and a role given while the
player is on, and checks the table is read-only and a plugin without server is refused;
dingosdk_plugin_tests checks the API on a server copy, and that a player's copy and a plugin
without server cannot read it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Hs7xxJDf6SDcQUaXnzmtL5
2026-10-23 10:43:34 +02:00
Robin MoellerandClaude Opus 5.5 5b10469bad Plugins: server plugins spawn and remove the server's park mods
A dedicated server's park mods could only be spawned from its console, an admin's chat or a vote,
so a server plugin could not bring out the park its game is played in. A new permission,
server.parks, gives a server copy reskate.server.parks(), which lists the park mods set up with
whether each fits the map running now and is spawned (its objects and minutes left), and
reskate.server.park_spawn(name, minutes?) and park_remove(name), which return ok or false and why.

They go through park-mod add and remove, so the park limits, the map check and the chat lines stay
the server's. Their "[parks]" lines are logged "by plugin <id>". A name is a park mod's own (1 to 16
of a-z 0-9 - _) and minutes are 1 to 1440, or none for until removed. Reading the park files is not
part of this: a plugin brings what it needs to know about a park in its own package.

dingosdk_server_plugin_tests spawns and removes a park mod through a plugin and checks what it is
refused; dingosdk_plugin_tests checks the API on a server copy, and that a player's copy and a
plugin without server.parks cannot use it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Hs7xxJDf6SDcQUaXnzmtL5
2026-10-22 20:43:01 +02:00
Robin MoellerandClaude Opus 5.5 fd5f95467f Plugins: server plugins know the map and hear it change
On a dedicated server reskate.level.current() was empty and level_loaded and level_unloading never
fired, so a server plugin could not tell which map ran or that it had changed. The server's
plugins are now told the map's level each tick, named as players' games name it (a destination's
level, after its "|"). When the server changes the map, they hear level_unloading for the old one
and level_loaded for the new one, as a game's plugins do; players load it after.

dingosdk_server_plugin_tests checks level.current() and both events across a map change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Hs7xxJDf6SDcQUaXnzmtL5
2026-10-22 20:38:22 +02:00
Robin MoellerandClaude Opus 5.5 45d4c64c75 Plugins: a dedicated server's plugins see the skaters
reskate.session.skaters() returned an empty list on a dedicated server: its game for plugins did
not say where anyone was, though the host holds every player's latest pose. A server copy now gets
each player in the world with a pose: their id, the pose's root position, its heading (read as a
client reads it) and how long ago it arrived. A server plugin can now follow players itself, for
a race's checkpoints or a game of tag, instead of trusting what each player's copy reports.

Host::skater_poses() lists them for the plugins. dingosdk_server_plugin_tests drives the host with
simulated players sending poses and checks what a server plugin sees, and that a plugin without
session.skaters is still refused.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Hs7xxJDf6SDcQUaXnzmtL5
2026-10-22 20:30:07 +02:00