Commit Graph
42 Commits
Author SHA1 Message Date
gbgyo 550887162f Effects: release stale resources and require resident assets
Resolve private effects only from the level-wide Game compartment and validate
their resident declarations with the same parser used by the mod merge.

Release surviving native services during world changes, check decal realm
ownership before cleanup, defer ordinary off-thread releases, and prune expired
VM handles so they return their quota. Size the temporary decal allowance from
the live count while preserving external settings changes.

Gate contact geometry behind events.physics.geometry, document the manifest
migration, and test Blood impacts through the plugin host using its own manifest.
Add regression coverage for residency, lifetime, quota and draw-budget handling.

Validation: Release builds of the runtime and plugin/effect test targets succeed.
The plugins, effect_geometry and effect_lifetime tests pass. Existing MSBuild
asset-directory dependency warnings remain; native visuals need an in-game check.
2026-10-26 22:19:43 +03:00
gbgyo b9c30d120a Effects: merge main while preserving plugin resource cleanup
Merge main into feature/effects. Keep both effects and declared board material cleanup in the shared plugin test fixture.
2026-10-26 18:13:08 +03:00
AyeZeeBB 7170938799 Merge pull request #358 from hypnomalice/runtime/declared-board-materials
Plugins: support declared colour inputs on mod-owned board materials

Conflicts with #363 resolved by keeping both: reconcile_variant_additions beside
active_mod_sources in mod_catalog.h, and both test targets in cmake/Apps.cmake.
2026-10-25 14:38:17 -05:00
gbgyo 4f07b448a3 Plugins: render private particles and decals with physics geometry
Add permission-gated effect handles, native surface attachments, and world lifetime cleanup. Extend physics_step with optional contact geometry and body poses. Document the generic API and validate it with self-contained plugin and geometry fixtures.
2026-10-25 10:56:59 +03:00
mauwpixandClaude Opus 5.5 8fe5d01942 Plugins: skater.pose can fully control a joint (its own place, relative to its parent, another joint, the skater or the world) instead of only adding to the game's animation
So far a plugin could only add to what the game's animation does with a joint. Now it can give the
joint its own transform, which the animation's is replaced by: its own animations, joints reused for
body parts the skater doesn't have, joints moved by a simulation in Luau, joints pinned to a point.
A joint's entry takes place = {position, rotation | angles, relative_to} and keep_children = true
(its children stay where they were); a pose takes up to 128 joints. Each frame the place is turned
into the joint's value under its real parent, the joints posed in an order that puts each after its
posed parents and the joint it is placed relative to; a pose without such an order is refused with
the reason.

Extension/Skater/pose_place.h/.cpp hold the maths, with pose_place_tests; skater_animation applies it
after a joint's offsets; plugin_api_world reads it and sorts the joints.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 05:27:48 +01:00
hypnomalice c29cffdf9b Plugins: enforce declared input ownership and preserve holds through rebuilds 2026-10-25 00:01:46 +01:00
hypnomalice 4c2b500a99 Plugins: hold declared colour inputs on mod-owned board materials 2026-10-24 22:51:59 +01:00
Robin MoellerandClaude Opus 5.5 dd8e610482 Plugins: a dedicated server's plugins hide a player from others, or mute them
Hide and Seek, tag, spectating and ghost runs need one player to be
gone for some others, which no plugin could do.

reskate.server.hide(target, viewers, {skater, name, voice, sound}) and
reskate.server.unhide(target, viewers?) do it per viewer; viewers is a
player, a list of players or "all" (everyone on now but the target).

Wholly (the default) the target leaves those viewers' rosters, so their
games take the skater, its name tag and its objects away as for a player
who left, and the server sends them nothing of the target: poses, sound,
voice, outfit, effects and objects. No protocol change: the roster per
viewer is the one the cards and polls use, and the server's introduce
already holds a player back until shown. Shown again, the target is
introduced anew (outfit, then whole poses, then all its objects).

Without the skater (skater = false), only the voice and/or the sound is
held back and the player stays. Name and skater go together: a game has
no skater without its player, and hiding one without the other would
need a protocol change.

Refused while the target shares a party or a throwdown with one of the
viewers, whose game would lose a party member or a player mid-way; while
hidden, the two cannot come into one party. A plugin that stops shows
everyone it hid; a player who leaves is dropped from every list.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SYabE7FCPgj3SaWeF92EML
2026-10-24 12:26:31 +02:00
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 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
AyeZeeBB e35e33d66d Plugins: board.parameters reads the board's shader values, and set_parameter holds its colours and numbers
Each part of the local board (deck, grip, trucks, wheels) has a material instance with a few
shader values of its own, found in the running game. reskate.board.parameters lists them by key
and type. set_parameter holds a colour or a number there each tick, published until it shows, and
the board's own value comes back when the plugin lets go or stops. Integers and switches pick how
the board is drawn, the store's foil looks among them, so plugins only read those. Only your own
screen changes.
2026-10-22 20:17:09 -05:00
AyeZeeBB 1671403500 Plugins: board.motion gives the board's spin, and where the board and its deck are in the world 2026-10-22 19:50:04 -05:00
AyeZeeBB 118c489fdb Plugins: what the Filmer needs as a plugin: carry, who sees a pose, a step in the camera cycle
PR 343's Filmer becomes a Luau plugin mod (kept in contrib/plugins/filmer) on general APIs instead of
its own C++:

- reskate.skater.carry: something held out in one or both hands and aimed, the body crouched (feet
  kept) and hunched over it, turned on the spot after it (Extension/Skater/carry.cpp, from the PR's
  filmer_hold.cpp, with tests)
- shown = "everyone" | "others" | "me" on skater.pose, reach and carry: the pose sent to the other
  players and the one drawn here are split when asked
- reskate.camera.cycle and the camera_cycle event: a plugin's camera as the last step of the camera
  height button's cycle, after first person
- reskate.session.nametags(false) holds the names over the other players off
- board.hide(bone, {others = true}) hides it in the board the others are sent too (a sent-pose filter)
- outfit.set takes hand wear slots; input.bind takes an action with no key of its own
2026-10-22 18:46:49 -05: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
AyeZeeBB 45346b122c Plugins: prop hunt APIs, and plugin commands in the console lookup
- reskate.entities.blueprints lists the game's object blueprints (meshes only if asked),
  and reskate.entities.bounds gives a blueprint's box, so a mod can pick a prop by list or at random
- Attached objects take upright, turn and ground (a floor found within reach below), the "root"
  joint, and a 6th options argument with solid; spawned props' bodies are found and ghosted
- reskate.skater.hide, reskate.world.pick, and skater.get gives right and switch
- reskate.console.command takes an optional 4th table of subcommands; the console lookup
  suggests plugin commands word by word, and plugin commands lists the subcommands
- objbody: a test command for finding which body setter takes a prop out of collision
2026-10-22 00:30:06 -05:00
AyeZeeBB 721ed9e64d Plugins: a general launch API in place of grind_exit; grind exits is all Lua, and 701 is a grind
The SDK knew grind exits: reskate.skater.grind_exit took a toe/heel/left/right wish, and C++ worked
out the rail's direction, toe and heel from the stance and facing, the 1.8 m/s and the strength.
That logic is now the grind-exits mod's own Lua (plugin/exits.lua, kept on this machine). What has
to run on the physics thread is general:
- Extension/Skater/launches: every launch of the local skater (ollie, grind, no_comply, boneless),
  classified by its call site and the state before it, with the board's direction of travel; the
  `launch` event for plugins with events.skater; reskate.skater.shape_launch(from, {across, along,
  up}) sets those speeds against the travel, one plugin a kind.
- reskate.skater.get() gains `right` (the root's right axis) and `switch` (the game's stance flag).
- Extension/Skater/pad_hide: reskate.input.hide's pad filter, out of the old grind exit file.
Removed: reskate.skater.grind_exit, the grind_exit event, GrindExitWish and GrindPop.

Physics state 701 is a grind too (the game checks it with 400 in about a dozen places; the
2026-10-11 measurement only reached the 400s): pops out of it were dropped, and skater_state called
it "other". Launches, skater_state ("grinding") and the trainer's grind pop all count it now.
Tests: the grind-exits plugin test drives the new path (11 checks of its own).
2026-10-21 21:41:04 -05:00
AyeZeeBB 89a97caed7 Plugins: an item grid's own list and marks, items worn on top, keys kept from the game, the menu's category icons
General APIs from pull request 269 (the player's own item tabs and outfit layers), whose tabs,
panels and prompts are now a plugin's (contrib/plugins/item-tabs, kept on this machine):
- reskate.menu.grid_show(keys): a plugin's list in the item grid that has the focus, drawn from
  every grid of the screen; reskate.menu.grid_mark(keys): the game's check on tiles. menu.grid()
  also says whether a list shows, whether it is empty, and where the grid's own prompts end.
- reskate.outfit.on_top(items) and on_top_state(): items worn on top of the outfit in the slots it
  leaves empty, the item given the slot's category, a slot tried and left if the game reports a
  failed load (ReSkate.layer_slots.txt remembers which load where); paid store items refused.
  Part of the shared outfit service, with reskate.outfit.set.
- reskate.input.game_keys(keys): presses the game does not see, by any way it reads the keyboard;
  "Delete" is a key name.
- d:game_image draws the customization menu's 17 category icons ("cas_tops", ...).
dingosdk_plugin_tests skips the test of a contrib plugin that is not on this machine.
2026-10-21 19:18:01 -05:00
AyeZeeBB dce293e25d Fit Check as a plugin: screen capture, the menu's preview turned and read, and what the skater wears
Pull request 326 split into general plugin APIs and contrib/plugins/fit-check:
- reskate.capture (start, stop, discard, state, compare, kept, save): the screen
  recorded before the overlay draws, cut out by the game's depth or by colour,
  saved as GIF, APNG, PNG or WebM with an optional card; the "capture" permission.
- reskate.room.turn: a stand-in pad's stick held over to turn the menu's preview.
- reskate.menu.game and reskate.menu.grid: what the game's menu and its item grid show.
- reskate.outfit.worn, board and title: what the skater wears, by name.
- reskate.files.reveal: a data folder opened in Explorer.
The plugin finds where the turn comes round, eases the stick off, picks evenly
spaced frames and saves them with the board's parts or the outfit on the card.
2026-10-21 17:16:56 -05:00
AyeZeeBB 79df4762c4 Animator Studio: game tricks mirrored to the skater's stance, a steady board, and the room held together
- reskate.animation.mirror makes a clip for the other stance (Left and Right trade across the board's
  length, each joint from its rest; the board mirrored as itself), and info gives a clip's stance. The
  game's trick clips stand goofy: the studio mirrors one for a regular skater, which played half a
  turn round in game.
- The studio no longer holds the skater with noclip: he left his board and the flight pose showed
  through. His board is stopped once instead; while drawn in the room No Bail guards him, and the
  game's own placement goes back into the pose before its physics.
- The whole board is held rigid while a clip moves it, deck mount included.
- The room closes when the game's menu leaves the Skaters page, and the studio closes with it.
- The studio's first camera angle is the PR's, taken once the room's joints are read.
- A log line every 2 s while a clip plays (Clip pose: updates, renders, scale, heights, the joints
  that change most), kept while the room's pose is still checked in game.
2026-10-21 00:31:13 -05:00
AyeZeeBB 75cc241277 Plugins: the game's own clips by name, clips played on the floor, and Animator Studio's tricks from the game
- reskate.animation.game_clips lists the game's animations and "game:<name>" plays one: the
  skater's Eclipse clips decoded from its data (Extension/AnimationStudio/game_clips, ported from
  ReSkate Studio's animation export), matching make_trick_library.py's clips.
- reskate.animation.play's floor stands a clip on the floor where the skater is, its board's lowest
  point on it, as the pull request's studio did; the game's trick clips no longer sink.
- Animator Studio lists the game's tricks from its data; the Python tools are gone.
2026-10-20 18:31:16 -05:00
AyeZeeBB 55d5f70d4f Plugins: touching other players, hiding one on your screen, and a raycast that hits players
reskate.session.touch, touching, hide, hidden and raycast, and the touch and touch_end events.
The session publishes every skater's body as capsules while a plugin reads them; a hidden
player goes through the same path a throwdown's hidden players do.
2026-10-20 18:06:30 -05:00
AyeZeeBB 41b5973896 Plugins: the character room and typing into a drawn field, and Animator Studio on both
- reskate.room.open, leave and state, with the room permission: ReSkate walks the game's menu to the Skaters page (its navigation events and RB on an internal scripted pad, as PR 297 and PR 230 did), draws the local skater on the room's floor and hides the room's own skater and board; other players are not sent the room. Extension/World/character_room, the room placement and hiding in skater_animation, and post_native_ui_event made general.
- reskate.input.text: what is typed while the plugin's screen is open; while it types, Esc is the plugin's.
- Animator Studio opens in its room (the Studio room setting, as the PR's), under its loading screen, or where the skater is when the walk fails; its card's name, trick and numbers are typed into in place.
2026-10-20 17:43:40 -05:00
AyeZeeBB 805cd0d6f5 Plugins: Animator Studio's screen 1:1, on general drawing, screen and pose APIs
- The studio plugin draws PR 297's screen itself: skate.'s Trick List menu and card, the joint timeline with key rows, dragging joints on the skater, keyboard and pad controls with their prompts, the unsaved-changes card, the recording strip and the loading screen. It lists a trick library made with tools/make_trick_library.py (the PR's, here beside it), and checks itself with studio test.
- Drawing: d:rough_rect, d:halftone, d:scribble, d:clip, d:measure, a text wrap width, the title_large font, text up to 400, and the loading screen's kickflipping board as d:game_image("loading_board") with a frame.
- reskate.ui.screen with panel = false: input taken, nothing drawn, the plugin draws it.
- reskate.skater.joint gives each joint's parent; reskate.skater.pose takes an offset.
2026-10-20 17:22:19 -05:00
AyeZeeBB 5f65bcf690 Plugins: Animator Studio as a mod, on clip editing, docked screens and the cursor
- reskate.animation: play's at and paused, seek, pause and time; info, sample, joints, trim, edit (keys baked onto a clip) and save; clips named "data:<path>" from the plugin's data folder, "clip:<n>" and "edit:<name>".
- reskate.ui.screen's dock and width: a panel down one side, the game showing beside it.
- reskate.input.cursor: the mouse over the game while the plugin's screen is open.
- contrib/plugins/animator-studio: the Animator Studio of PR 297 (22sh, Fourth Studio, Norms) as a plugin: record a trick, key joints on a timeline, save it, and the trick plays it in game.
2026-10-20 16:43:46 -05:00
AyeZeeBB b12b904c65 Plugins: joints, physics tuning, velocity, game settings and pose offsets
- reskate.skater.joint and reskate.session.joint: where any joint of your skater or another player's is.
- reskate.physics.tuning, find and tune: the trainer's tuning values, a plugin's set over the player's own and never saved.
- reskate.skater.set_velocity: the board's velocity set or added to at the next on-board physics step, in the air too.
- reskate.settings.set and the settings.write permission: a game setting held while the plugin keeps it, then put back; gameplay settings stay locked in multiplayer.
- reskate.skater.pose: joints turned and scaled on top of the animation, in the pose drawn and sent.
- The mesh tests build anim_core, which the session's joint publishing now uses.
2026-10-20 15:46:54 -05:00
AyeZeeBB cf5165b791 Plugins: the general APIs a filming mode needs
- reskate.input.hide hides the right stick and the stick clicks, and reskate.input.mouse reads the mouse's movement and wheel.
- reskate.skater.cruise: cruise control up to a speed, optionally easing down to it.
- reskate.skater.reach and hand: an arm reaching for a point (two-bone IK, Extension/Skater/arm_reach), in the pose drawn and sent, and where a hand joint is.
- reskate.entities.set's attach: an object kept on a joint of your skater or another player's, moved every frame.
- reskate.screen.look and slap: the Filmer branch's VX1000 post-process as a fixed-parameter camcorder look drawn by the overlay.
2026-10-20 15:24:00 -05:00
AyeZeeBB 847c0df6fe Plugins: shared content, the files other mods ship for a plugin
A plugin names folders in its manifest's "content" (at most 8, with mods.read), and reads them in
every enabled mod: reskate.mods.content(folder) lists each mod's files there (mod, title, path,
size; 1000 at most, four folders down), reskate.mods.read_content(mod, folder, path) reads one (1 MB
at most, never outside that folder). A folder the manifest does not name is refused. Other mods can
then ship data for a plugin with no code: parks for a game mode such as Domination (pull request
279), routes, presets. Checked in the plugin tests, with the manifest's new errors.
2026-10-20 14:32:04 -05:00
AyeZeeBB cf43231b3e Plugins: reskate.tricks.label and record_as, and Rock to Fakie as a mod on them
Two general trick APIs on the hooks TheRealEJR found for his Rock to Fakie mod (pull request 285):
- tricks.label(from, to) ("hud"): the trick ticker shows `to` where the game's label is exactly
  `from`, on the ticker's own call route and in its own buffer only, when it has room; 16 labels a
  plugin, given back when it stops.
- tricks.record_as(from, to, within_ms) ("skater.control"): the next trick the recorder gets whose
  id is one of `from`, within the window, is recorded as `to`, through a changed copy of the packet.
  One ask a plugin, used once; refused while a throwdown runs, as trick replacements are.
The hooks pass everything on unchanged while no plugin asks.

contrib/plugins/rock-to-fakie is his feature in Lua: while the physics state holds a stall (400 or
401) the ticker shows Rock to Fakie for a Board Stall or a Lip Stall, and B pressed in it asks that
the stall be recorded as the game's fakie_rock (187). Off until `rocktofakie on`. Checked in the
plugin tests, with the new functions' permissions.
2026-10-20 14:26:04 -05:00
AyeZeeBB 4d0182eef9 Plugins: a plugin's saved files live in Mods/.reskate_plugin_data, which no merge deletes
reskate.files kept each plugin's folder in Mods/.reskate/data/<plugin>/, inside the merge's own
output, which every full merge deletes: saved Deathrace routes went whenever a mod changed. It is
Mods/.reskate_plugin_data/<plugin>/ now (mod_list.h plugin_data_folder), and what is still in the
old folder moves across the first time the plugin looks for its folder. Deathrace's routes keep
SmokeyDawg58's <map>/<name>.json layout, so routes from his fork copy straight into routes/.
2026-10-20 13:48:21 -05:00
AyeZeeBB 253ba73d67 Merge branch 'plugins' of https://github.com/Dingo-Shenanigans/ReSkate into plugins 2026-10-20 13:30:35 -05:00
AyeZeeBB bf693dbe5c Throwdowns: fixes the docs review found in the kit and its services
- match.teleports lets through only the publishing plugin's own teleports, and only while its
  match runs (its HUD is active, or the native flag is one of its modes); it was merged across
  every plugin and checked no match.
- A mode's timer of 0 or past an hour no longer makes its card do nothing: the native flag takes
  it as 1 to 3600 s. flag.begin's seconds are checked as 1 to 3600, as the flag takes them.
- skater.push and hold(true) return false with a reason without the stock physics, where they
  were dropped unseen.
- telemetry's slam and struck are news since each plugin's own last read; reading them cleared
  them for every plugin.
- A banner or callout of a new match shows whatever serial it starts from, and a document without
  the slot no longer resets its serial.
- SmokeyDawg58's placement no longer divides input.wheel's whole notches by WHEEL_DELTA again.
2026-10-20 13:30:27 -05:00
waguandClaude Opus 5.5 cd36529865 Merge plugins into server-lua-api
The new services and throwdown kit API files use add_functions and the shared
helpers; add_functions opens a read-only parent for reskate.throwdowns.flag.
throwdowns.release_flag stays removed, as plugins has it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 12:13:19 -04:00
waguandClaude Opus 5.5 67e8e439f7 Server: lock ollies for a player
A lock tool like noclip and boosts. The player's game enforces it: the roster
carries guest_ollies (protocol 53), and the jump hook gives a locked ollie no
upward speed. Plugins get player.permissions.ollies.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 09:53:31 -04:00
AyeZeeBB af83281b8d Mods: variants, one of several takes on the same game data; Board Break's decks leave the SDK
A mod's reskate-plugin.json can declare "variants" {folder, order, displaces}: each <folder>/<name>/
is a variant, the one chosen (else the first of its order) loads, and every other mod whose layout
lists a displaced bundle is set aside for the run. Choices are kept in
%LOCALAPPDATA%\ReSkate\variants.json. Plugins read and choose their own mod's variants with
reskate.package.variants and reskate.package.choose (permission "variants"), and fit every board
for a deck that is not the game's own with reskate.board.fit {plates, axle}.

The board-break plugin, which ships inside the Board Break deck pack, declares the pack's decks as
variants, picks the deck on its own page and with `boardbreak deck`, reads each deck.ini and fits
the boards. Gone from the SDK: breakable_deck, the deck catalog, the MODS page's deck card, the
boarddeck command and the Board_Break_<Name> folder naming.
2026-10-20 01:31:50 -05:00
AyeZeeBB 8444553402 Throwdowns: the throwdown kit, so a mode is a plugin and the SDK knows no particular mode
Plugins register modes (card, replaces, order, flag, players) and publish documents through
reskate.throwdowns.ui: the setup page, the waiting card, HUD slots themed on the game's HUD_<theme>_*
widgets, the match panel, flags and match restrictions. SmokeyDawg58's native plumbing
(throwdown_menu.cpp and its .inl files) renders them and posts throwdown_ui events back. kit::flag
is the one native flag registration. General services added for it: reskate.files, reskate.ui.dialog,
reskate.skater push/hold/bone_cam, reskate.camera.pad_flight, reskate.physics competition,
reskate.session.world, reskate.tricks feed/gesture, and world entities.

His ten modes are now Lua in his plugin: the rules, referee and wire (td/rules, referee, wire), and
every page and HUD document (td/ui*.lua). Extension/Modes and reskate.modes are gone, along with
every race and 1-UP branch in the SDK. The plugin test drives each mode through kit events.

A native setup page is never written to while it closes into flag placement: its rows are not
republished, the stock page is put back once the exit is over, and the stock Players slider is left
alone while a plugin flag is out. This fixes the crashes on the Deathrace button and on 1-UP's
Confirm.
2026-10-20 01:04:54 -05:00
vtf 02d34012ae Plugins: server plugins ban, unban; player permissions; reskate.Enums 2026-10-19 20:09:30 -04:00
AyeZeeBB 37516e24fc Throwdowns: a plugin mode's flag is offered to the session, joined with the game's own Join
When a plugin mode's flag goes down in a session, the relay offers it to the other players
as that mode's: a new mode message (kind 17) names it, its flag and its player count, and
its offer's series is one older versions do not show. A player whose plugin has the same
mode gets a copy with the mode's own flag mesh and joins it natively; the copies are held
at ten players so none fills and starts a Spot Battle, and the mode's player count decides
who may still join. throwdown_mode events now carry host, leader, player and players: the
host hears joined and left, a player in another's flag hears joined, left, closed and
start, and start names who plays, the leader first. The plugins run the match from there.

A mode can take a stock throwdown's place on the picker (replaces = "skate", "spot_battle"
or "jam"), so his R.E.S.K.A.T.E. sits where S.K.A.T.E. does.
2026-10-19 19:04:11 -05:00
AyeZeeBB 0ff96018d0 Throwdowns: plugin modes on the native Throwdowns page, which is SmokeyDawg58's logo grid
reskate.throwdowns.mode{...} adds a mode to the game's own Throwdowns page: a card on
the picker, the real Spot Battle setup page relabelled with the mode's name, logo,
description, players, timer and rows (sliders, choices, buttons), and the native start
flag. The plugin hears throwdown_mode events (opened, setting, button, placed with the
flag's position and heading, start, leave, cancelled) and runs the mode itself;
release_flag takes the flag down. The flag's queue never starts a Spot Battle: its
waiting card's Start goes to the plugin, MaxPlayers is held at 10 and it is never
relayed as a drop. After SmokeyDawg58's one_up_menu and one_up_placement
(reskate-custom-mods), generalised over a mode registry.

The page is his 4-column logo grid whether or not a plugin has a mode. Its widgets and
grid records, and the game assets it uses that only some levels load, ship in
ReSkate.dll as the throwdown_menu built-in pack, taken from his asset mod's FBMOD
(dingosdk_ebx_pick trims the asset list in place). A mode's logo is a texture path in
its own mod, so no mod edits the shared list. The FPV drone is no longer a built-in pack.

Native menu data: text initialization, change-only writes, retained array publication,
owned-model rollback. Tests: registry and setup helpers, the plugin API, a test plugin
with two modes.
2026-10-19 18:38:10 -05:00
AyeZeeBB db52508bdb Plugins: Hall of Meat and grind exits are plugin mods now; their C++ is gone
Hall of Meat (contrib/plugins/hall-of-meat) and grind exit triggers
(contrib/plugins/grind-exits) are Lua plugins: the bail model, its Meat card,
each map's best, the trigger rules, settings, console commands and menu panels
are theirs, with their own checks that dingosdk_plugin_tests runs.

What has to run in the game stays in core as plugin services:
- every physics step of the skater (skater_physics, the physics_step event,
  permission events.physics);
- the skater's x-ray (xray, xray_render, xray_skeleton; reskate.skater.xray and
  the draw handler's d:skeleton);
- skate.'s bottom left HUD corner (hud_corner; reskate.hud.corner);
- the game's slow motion, never in a session (game_speed; reskate.time.slow and
  speed, permission game.speed);
- the side of the next pop out of a grind and pad controls kept from the game
  (grind_exit; reskate.skater.grind_exit, the grind_exit event, reskate.input.hide);
- skate.'s own pictures by name (game_images; d:game_image), d:gradient and a
  font for drawn text.

Removed: Extension/HallOfMeat, grind_exit_control and its commands, the HALL OF
MEAT and GRIND EXITS add-on pages, home tile, hub and native menu rows, their
menu models, and the hallofmeat and grindexit built-in commands.
2026-10-19 16:51:28 -05:00
AyeZeeBB 2d3b77701d Plugins: drone, Board Break and Road Rash are plugin mods now; their C++ is gone
The three features are Lua plugins in contrib/plugins (fpv-drone, board-break,
road-rash), built on what this adds to the plugin API: flight input, gamepad and
joystick reads with input capture, a rolled camera, a package's own sounds and a
synthesised motor (plugin_sound, plugin_wave, motor_synth), the skater's physics
events (skater_events), items worn over the outfit (outfit_overlay, skater_items),
the board's bones (board_pose), skater animation (anim_core), plugin images,
throwdowns started for chosen players, and server copies of plugins on a lobby
host and the dedicated server (server_plugins).

Removed from core: Extension/RoadRash, Extension/BoardBreak, the drone's flight,
radio, follow, OSD, beacon, outfit and sound code, its prop models (native_prop),
the DRONE, BOARD BREAK and ROAD RASH menu pages, home tiles and native menu rows,
their console commands, the drone follow debug action, the drone marker packet
(kind 36 stays unused; the roster keeps its byte) and the server's drones setting.

Kept in core, since every board needs it whichever plugins run: the breakable
deck packs (breakable_deck: which deck, its label and wheel spacing, the
boarddeck command and the BREAKABLE DECK card on the Mods page), and board_pose
keeping a deck pack's stretches out of sight, the baseplates on the deck and the
wheels at the deck's spacing on every board.
2026-10-19 16:22:15 -05:00
AyeZeeBB 5c0993afea Plugins: the wider set (phase 3), behind one Game interface the tests fake
- Skater: skater.state() and the skater_state and bail events (events.skater); noclip and boosts
  through the console's own queue, under the host's rules (skater.control); a save point of the
  plugin's own (trainer); the game's HUD hidden while any plugin asks (hud).
- World: park editor objects listed, placed, moved and removed through the editor's own edits and
  the session's object rules (world.objects); time of day, world controls and park rotation as
  the World menu sets them, refused where the host chooses (world.environment); fast travel and
  levels, refused for guests (travel); AI skaters, outside sessions only (world.ai).
- Session: other players' skaters as last heard (session.skaters, a feed the session publishes
  each frame, plugin_session_feed.h); a plugin's tag above a player's nametag (session.nametags);
  voice volume (voice.control); chat lines as events (chat.read) and sending one, one every 3 s
  (chat.send); throwdown state and events (throwdowns).
- Music from outside players (music), progress (progression.read) and game settings
  (settings.read), read only; named actions on keys or pad combos, pressed while the game has the
  input (input); full-screen screens with the input, closed by Esc (ui.screen).
- Libraries and events between plugins: expose, require_plugin, emit, on_plugin; plain data is
  copied across VMs and a plugin in a call cannot be called back into.
- net.http: HTTPS to the hosts reskate-plugin.json's new "domains" lists; no redirects, cookies
  or Windows sign-in; private and local addresses refused; 10 a minute, 4 waiting, 1 MB back.
- Left for engine work (listed in the design doc): respawn and freeze, manuals, the camera, trick
  animations, replays, starting throwdowns, the game's own soundtrack, overlay images, rebinding
  plugin keys in the Binds page, local-only chat lines.
- reskate-test has a wider module (ptest noclip, boost, hidehud, object, night, day, ai, screen,
  bind, music, chat, web by hand); reskate-hostile has chat-spam, edit-spam, travel-spam,
  web-elsewhere, bind-spam and screen-loop.

All host tests pass; not yet tried in game.
2026-10-19 13:49:29 -05:00