Map downloader
- A host or dedicated server now tells joiners which Thunderstore package
its map comes from (the Mods folder name plus manifest.json).
- A player without the map gets a card: icon, name, author, version and
description, with DOWNLOAD and CANCEL. It works with mouse, keyboard and
controller.
- Only packages listed as Maps in the ReSkate community are offered, and
never deprecated, rejected or NSFW ones.
- On yes the package is downloaded, installed into Mods and applied as a
live mod, then the session loads the map. A small card on the right
shows the progress, so the player can keep skating.
- The player stays connected while it downloads: the host gives a player
who says they are fetching the map up to 45 minutes instead of the
usual load time.
- When the server changes map with the player in it, the card says so.
- Protocol version 47: map package on map_offer and world_state, and a
"fetching the map" flag on map_request and world_ready.
Joining
- The pause-menu server browser shows a CONNECTING card over the page
while a join is under way, and a COULDN'T CONNECT card with the reason
when it does not get in.
- The session and voice tabs no longer show before the player is in.
- Leaving without the map (declined or cancelled download) no longer
counts towards the failed-join limit, on servers and player hosts.
Input
- A card that asks something holds the game's input until the buttons
are released.
- Steam's overlay hooks XInput in front of ReSkate and answers the game
itself, so a controller reached the game behind menus. ReSkate now
hooks that hook as well.
Mod merging
- Mods are read on several threads, at launch and for live merges. A live
merge runs below the game's priority.
- The paid-cosmetics check reads the game's files and the mods on several
threads.
- A live merge reuses the paid-cosmetics verdicts it already has and
reports its progress and timings.
Launcher
- NSFW mods and their categories are not shown in the mod browser.
After 10 bails the leg of the side that took more of them shows road dust
and a graze, its arm one bail later; at 14 the marks are bigger and the
other side starts; at 20 they are raw wounds and the face is bruised. A
mark never gets smaller until the player heals. The worst wounds bleed,
or are dry and scabbed with the blood switch off.
The marks are cosmetic items of a content mod (tattoo items for the limbs,
moles items for the face, named RoadRash_<Set>_[<design>_]<level>). Road
Rash puts them into the local skater's recipe with the game's own recipe
copy, after the validation the multiplayer code runs on a peer's outfit.
Nothing is written to the outfit or the profile's skater, and without the
item pack nothing shows and nothing is changed.
A bail is the physics state selector choosing Wipeout (No Bail's watch).
Its side comes from the ragdoll's contacts through Hall of Meat's reader:
impact and slide of the arm and leg bodies that touch something other than
the skater's own board, summed per side while the body is a ragdoll.
Outfit menus. The game feeds a skater's items either from the player's
outfit or from a recipe of the skater's own: after the recipe copy the
skater in the world no longer gets what the player changes in the menus.
So the skater is given back to the game while a game menu is up, with
nothing to show, on healing, when a switch changes and when switched off:
the four words of the item component the copy had changed go back to what
they were and the component is told its feed changed, and the game puts
the outfit's own items back and feeds the skater again. The marks go back
on, over the outfit as it is by then, a second after the menu has gone.
Whose recipe a skater wears is read from the skater at every look: a
respawn hands over the same skater, items and all, as if it were new.
The player's own tattoos and moles stay unless roadrashtattoos is on, and
come back the same way.
The recipe handed to the copy names no item, only hashes, like the game's
own for the local skater: the game changes that skater's items where they
lie, and a name left beside one would stop every later read of the
recipe, the multiplayer code's too.
Console: roadrash, roadrashblood, roadrashtattoos, roadrash heal,
roadrash bails <count>. Menus: Road Rash, Road Rash blood and Heal Road
Rash beside Hall of Meat (Mod Options > Player, the overlay's skater page,
the native tools view). The three choices are saved with the profile.
No new hooks. The rules (side of a fall, levels per count, item names,
decal placement, comparing parameters the game has rounded) are in
road_rash_model.h with their own test target,
DINGOSDK_BUILD_ROAD_RASH_TESTS. Notes and what is not tried yet:
contrib/road-rash.md.
In the skater's item grids (Apparel, Accessories, Board, Gestures) F favorites
the highlighted item, - (or Ctrl+F) opens a search box that filters as you
type, and X steps a filter (All, Favorites, Mods, Game items). Favorites sit
right after the worn item, carry the game's star where the tile shows its
rarity icon, and are kept in ReSkate.favorites.json beside Skate.exe.
The grids stay the game's own: their tile rows are reordered and filtered
through the native model functions, as the music screen's Mods shelf does.
Nothing is hooked for it and no file of the game or of a mod is changed.
See contrib/native-item-browser.md for how it works and what is not tried yet.
This is the Item Favorites mod done natively, so it no longer needs a DLL
loaded through a custom script.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Player list. A player on the developer, staff or homie list sees each
player's Steam ID in the overlay's PLAYERS list for the session they are
in, after "Host" / "Guest" and the distance, on their own row too. A click
copies it. The lists are the backend's, the same ones the tags come from;
every client in a session already knew the IDs, so this changes who is
shown them and nothing else.
Custom scripts. Nothing in scripts/Custom is read or run any more, whatever
the launcher's "Loose files" setting says: nothing used them, and a mod was
using the folder to load a DLL into the game (package.loadlib from its
init.lua). The loader is kept behind one switch (custom_scripts_enabled in
custom_script_loader.cpp) for the day they come back.
For that day, the loader now also takes Lua's ways of running native code
away before the first custom script runs: package.loadlib, require through
the two C searchers and package.cpath, os.execute and io.popen. If that
does not hold, no custom script runs.
The overlay's Mods page no longer has the INSTALLED / SCRIPTS tabs; it is
the installed mods. Editing the game's own Lua and config through loose
files is unchanged.
Changelogs. The launcher's main screen has a CHANGELOGS tile in the
bottom-left corner. It opens a panel with the newest GitHub release: its
tag, title, date and notes. The notes are the release's description, read
as markdown and drawn like a mod's README (headings, bullets, code, rules).
A release published without a description shows what its GitHub page shows,
the tagged commit's message, taken from the releases feed. Fetched once,
the first time the panel opens; "Open on GitHub" goes to the releases page.
Download total. On GET MODS, the bar for ticked mods now gives the size of
what installing them downloads: "3 mods selected / 1.27 GB to download".
It is the sum of each mod's newest version as Thunderstore lists it.
Discord joins. The command the game registers for Discord to start ReSkate
now passes --no-gui, so pressing Join with the game closed goes straight
into the game instead of stopping at the launcher window.
--no-gui with no other launch flags now starts the game with the launcher's
saved settings (window size, menu and console keys, loose files, GPU
diagnostics, Discord status, offline, log level, extra launch options), as
pressing PLAY does. With flags of its own it behaves as before.
Mod Options. The pause menu's "Custom Stuff" page is renamed "Mod Options",
in the menu, the READMEs and the comments.
Not tested in game: the Discord join with the game closed, and the renamed
page. The changelog panel has only been seen with the earlier API-only
fetch.
The Multiplayer and Custom Stuff pages of the game's pause menu were
built from the game's own menu widgets: a button, a text box and a line
of text, which cannot make a list with columns. The game now keeps only
the frame around each page (top bar, title, Back prompt) and ReSkate
draws everything in it, tabs included. The native page is one empty
body.
Multiplayer
- Server browser: a list with name, map and skaters columns that sort,
search, filters (all, servers, lobbies, friends, hide full, my map),
and a panel for the session pointed at. Pressing a row joins it; the
row says JOIN while pointed at. Join by code is in the panel, and its
own tab is gone.
- Host lobby, as before.
- Current session (only in one): who is here, leave, map, join code,
party.
- Voice chat (only in a session).
- Session settings (only for a lobby's host or a server's admin). They
are sent as explicit values, which a dedicated server needs.
Custom Stuff
- Official maps and Custom maps: pressing a map loads it.
- World: traffic, pedestrians, time of day.
- Parks: a card for each lot with its style, layout and load.
- Player: noclip, no bail, Hall of Meat, board wear, the camera views,
flight speed and the boosts.
- Online: player and nametag distances, nametags, chat, chat bubbles,
Discord status, and showing your tag and items.
- Visuals: camera effects, challenges, shuffle playlists.
- Binds: record or clear the button for each action.
- The player card name is no longer on the page (cardname in the
console still sets it).
Input: the game keeps the mouse and controller while its menu is up,
so the pages only watch them. They have their own focus, moved with
the D-pad or arrow keys and pressed with A or Enter, with LT/RT or Z/C
for tabs; lists remember the row the focus left. Typing in a text box
or recording a bind takes the keyboard and controller for that long,
as chat does. Nothing is taken while the game is not the window in
front, and the overlay's own menu draws on top.
Layout follows the game's menu at any window shape: scaled to fit
whole, 192 units clear at the sides, centred past 4704 units wide.
Sounds: the pages raise the game's own UI one-shot event for moving
the focus, pressing and changing tab.
The game shows on the player's Discord profile where they are skating.
It talks to the Discord app on the same PC over its local pipe, with no
SDK; without Discord running nothing happens.
- Solo: "On <map>", "Solo skating", and how long they have been in.
- In a session: "On <map>", "Server: <name>" or "Lobby: <name>", the
player count, and how long since they joined. A session with a
password shows "Private server" or "Private lobby" and no name.
Joining: a status carries the session's join code when anyone may walk
in (no password, not full, a dedicated server or a publicly listed
lobby). Discord shows that as "Ask to Join"; the game answers yes for
the player at once, and the other player's game is handed the code and
joins. If their game is not running, Discord starts the ReSkate
launcher, which the game registers for under the player's own
discord-<application id> URL scheme.
Switches: "Discord status" in the launcher's settings (off starts the
game with --no-discord, and the game never opens Discord's pipe), and
the same in the in-game Multiplayer settings, kept in the profile.
The model gains join_code: the code of the session a player is in as
host or guest (invite was a host's only).
The cards drew their text plainly, so ":Catato:" showed as written. The
announcement text, the poll question and each answer now go through the
chat's emote layout (chat_rich.h); text without a known emote is drawn as
before.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NYHTXYAUyibUbfztfcriYB
Costume crash: the skater scripts' item:addEsShaderPreset uses the
preset it is handed without checking that it is loaded, and the game
crashed in the material's construction shortly after arriving on a
server's map while wearing a modded costume. The call is now checked
first: an item whose preset is not there is shown without it, and the
log says so.
Stuck close: once the player closes the game, a watch starts. If the
window has gone or stopped answering and the process is still there
8 seconds later, the process is ended. A window that still answers
(the close was turned down) is left alone, and the watch stands down
after two minutes.
Level unload guard: switched off. Skipping the entry that crashed left
its reference registered, so leaving the level never finished and the
game hung with the world unloaded. The crash it covered is back until
the reference is released properly.
A dedicated server's poll could only be answered by clicking a row on its card
or by typing /1, /2... in chat.
While a poll is running, the top-row number keys 1 to 6 give that answer (as
many keys as the poll has answers). They are read only while a poll is open,
so they stay the game's own the rest of the time, and not while the menu, the
console or the chat box has the keyboard, as with the Yes and No keys.
On the card each row's number is now a white keycap, blue for the player's own
answer, and the hint reads "Press 1 to N on the keyboard, or click an answer."
Clicking and /1, /2... still work.
Not covered: the numpad (the bind system does not read it), controller
buttons, and rebinding; these keys are fixed.
Builds on the 2.0.0 vote card. Protocol 46: a server's vote can now be a
poll, and the roster carries who may start polls, the owner's own votes
and the current announcement.
Custom votes (votes.custom): the server owner defines /vote <name> [choice]
in ReSkateServer.json. When one passes, the server runs its command as the
console; {map} is the current map and {arg} the player's choice, which must
be one of the vote's "choices", so players never put free text into a
command. They show in /help, /vote list and the "/" menu.
Polls: /poll <question> | <answer> | ... with 2 to 6 answers. A poll runs
nothing. Players answer by clicking a row on the vote card or with /1, /2...;
the card shows each answer's count, then the result for a few seconds.
votes.polls says who may start one (off, admins, everyone), poll_seconds how
long it runs, and /poll end ends it early (its starter or an admin).
More vote settings: each vote may have its own seconds, cooldown_seconds and
min_players; starter_votes_yes says whether starting a vote counts as a yes.
The "votes" admin command sets all of them.
Announcements: "announce <text>" posts a chat line and shows a card at the
top of every player's screen. The new "announcements" section holds messages
the server posts in turn every interval_minutes while players are on;
"card": false keeps them to chat. Managed with the "announcements" command.
Older configs gain the new settings with their defaults on first start.
Server/README.txt documents them.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WbSRfNf5T9wX4XMMQ5kwia
Linux and Steam Deck. 2.0.0 did not start under Proton: the launcher said
"ReSkate could not attach to Skate". The block on EA's online services hooks
five of Windows' name lookups and took any failure as fatal, and Wine's ws2_32
has no GetAddrInfoExA. Only getaddrinfo, the one Skate.exe resolves names
through, is required now. The other four are extra cover for anything else in
the process: one that is missing or cannot be hooked is left as it is, with a
line in the log. A function the system does not have cannot be called, so
nothing is left unblocked. On Windows all five are hooked as before.
Vote card. It sat on top of chat and looked like neither the menu nor the
notices. It is now on the middle of the screen's right edge, whatever chat is
doing, as a flat dark tile with a strip of colour down its left: blue while
running, green passed, red failed, grey cancelled. The question is in the
heading font, the bar is under it with the tally below, and Yes and No are
menu tiles with their binds on white keycaps. The server's line that starts a
vote says "the card at the right of your screen".
Hall of Meat. Its row in the Insert overlay now says when No Bail (or noclip,
which includes it) is stopping the bails it scores. The tab it is on,
MOVEMENT, is now GAMEPLAY, and the card FLIGHT & BAILS.
Overlay. Hall of Meat could only be switched from the game's own menu and the
console. The Insert overlay's skater page now has a "Hall of Meat" switch on
the Movement card, under No Bail. It runs the same "hallofmeat 0|1" command, so
both menus agree and the choice is saved with the profile. It is greyed out
when Hall of Meat did not start.
Server. A player who is not an admin and places more than twice the object
limit plus 100 in a minute (a modified game animating objects by respawning
them) had their objects held as they were for a minute. They are now deleted
for everyone, and nothing that player places is shared for the next minute:
without that their game would upload them again at once. The log names the
player once with their SteamID and how many objects went, and they are told in
chat. After the minute only what they place anew is shared.
The server cannot delete the objects in that one player's own game, so they
still see them there; nobody else does.
The badge a content creator gets before their name, in chat, on their nametag
and on their own tag in the menu, said "Creator". It now says
"Content Creator". Tests and comments that quoted the old text follow.
As in skate. 3: when the local skater bails, the bones it hurt show over
the world through the body, yellow where a hit bruised one and red where
one broke it, with the bail's Meat card in the bottom left corner in the
place of skate.'s own HUD there: its time, hits (head hits double,
vehicles half again), broken bones, road rash, airtime, fall, top speed
and rotations, each scoring, and the map's best. A bone breaking pulses
the screen's edges red and, in single player, slows the game down a
moment. Off until switched on, as in skate.: in skate.'s menu (Custom
Stuff > Player) or with `hallofmeat 0|1`, saved with the profile.
Everything it draws is skate.'s own, read from the installed game: its
skeleton mesh (the Dem Bones costume) posed with the renderer's own
skinning matrices, its scoring icons, the THRASHER wordmark and its UI
brush strokes. Nothing is shipped.
How it works: No Bail already hooks the skeleton response, which runs
once a physics step right after the body contacts; it now hands that step
on, with the local skater it follows, but only while Hall of Meat is on.
Each step reads what every ragdoll body hit and how hard, and whether the
skater is a ragdoll; the bail runs on the game's own clock so slow motion
measures what the body did. The feature's own hooks, on the renderer's
skinned draw packets and main view and on the UI model's write, are
prepared at startup and switched on only with the feature, and off again
once the HUD corner and the game's speed are given back: switched off, the
game never calls them and the physics step pays nothing. The skeleton mesh
is read the first time it is on; only the images are read at startup,
since the overlay builds its atlas once. The renderer's picture of the
skater is read only while a bail shows. The menu's switch reads the
overlay model like the others. Every address is in the build table with a
fingerprint checked before use. Extension/HallOfMeat/README.md describes
the parts; its tests build with DINGOSDK_BUILD_HALL_OF_MEAT_TESTS.
The slow motion changes SimulationTime's rate, frame cap and time scale as
a session override and steps the local skater along, since skate. sets a
skater's step only when it builds its core. It runs the same at every
break, but never faster than the game ran: with the trainer's game speed
below 1 it only takes the part that is slower still. Afterwards it writes
back what it found, each setting only while it still holds what the slow
motion wrote, so the trainer's speed comes back as it was; a setting
changed from elsewhere meanwhile is left as it is and ends that slow
motion. named_setting_value reads a setting's value for it.
Tuned in play: a bruise from 7 m/s and a break from 12 m/s along the
contact normal (raised twice: a hard fall on flat ground broke bones), a
break worth ten of the lightest hits (a heavy bail's hits and breaks
outweighed the rest of the card) and a fall half of skate. 3's rate.
Fix: the overlay now draws in the back buffer's pixels, not the window's,
so it lines up on displays Windows scales (1920x1080 borderless on 4K).
The skater's render hooks, its skeleton and its body maps were first
found by gBGYo's ReSkate fork (github.com/gBGYo/ReSkate).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Binds for first person, the HUD, voice chat, time of day, No Bail, challenges, nametags and dots
Eight more actions can be put on a keyboard key, a chord or a controller
combo, in the binds list beside the others. None is bound until the player
binds it.
- First person, Hide HUD, Voice chat on / off, Next time of day, No Bail,
Show / hide challenges, Player nametags, Player dots.
- Each bind runs the console switch for it, so it follows the same rules as
typing it: No Bail still answers to a server that has it off, and the time
of day goes to the server for an admin where the server sets it.
- They are one table (action_binds): a bind is its name in the profile, the
name "bind <name>" takes, its label and its command.
- "bind firstperson|hidehud|voicechat|tod|nobail|challenges|nametags|
nametagdots <n>" sets one from the console; 0 clears it.
- They are not read while the menu, the console or the chat box is open.
Console, which the binds use and anyone can type:
- Every on/off switch takes "toggle" ("nobail toggle", "hideui toggle").
- "firstperson 0|1", which was only in the menu.
- "tod next": the time of day after the current one.
- "mp voice-chat on|off|toggle": the player's own voice chat, leaving the
rest of their voice settings; it says which way it went in their chat.
Server: object scaling can be turned off
A dedicated server can stop players resizing the objects they place.
- "allow_object_scaling" in the config's "players" section (default true),
and "object-scaling on|off" from the console or an admin. A change is
saved and applies at once.
- Off: the server shares every player's objects at their own size, whatever
that player's game sent. Admins can still resize theirs, as with the
object limit.
- The roster tells each game. In the park editor of a player on such a
server the SCALE mode is not offered, its Y shortcut does nothing, the
scale box is disabled with a note saying why, and what is placed or edited
is its own size.
- An object resized before the setting was turned off is its own size for
everyone else straight away; its owner sees it resized until they edit it.
Votes on a dedicated server show as a card above chat instead of being
followed through chat lines.
- The card has what is voted on, the Yes and No counts, how many are needed,
a bar of how far Yes has got, and the seconds left. When the vote ends it
shows Passed, Failed or Cancelled for four seconds.
- Yes and No are two buttons, labelled with the player's binds. The answer
given is highlighted and can be changed. They can be clicked whenever the
cursor is free (chat, menu or console open).
- Two new binds, "Vote yes" and "Vote no", in the binds list: F1 and F2
unless changed, to keys or controller combos like the others. They are
read only while a vote is running, and not while typing.
- /yes and /no still work and show on the card. The player a kick vote is
about sees the card and has no vote in it.
- Console: "mp vote yes|no", "bind voteyes <n>", "bind voteno <n>".
Server:
- The roster carries the running vote (id, kind, tally, seconds left,
starter, target, label) and the one just finished with how it ended.
- A chat line is no longer sent for each change of the tally; the lines for
a vote starting and ending stay.
Fix: a dedicated server's roster may list more players than its limit.
The extra slots for reserved players and admins (33 of 32) made a roster the
protocol refused to encode, so with one in use the server logged
"Server error" every pass and stopped part-way through each one until
somebody left. Lobbies hosted by a player are still held to their size.
The reader's input-access counter was defined in input_capture.cpp. Built on
its own, as the launcher's controller support (#63) builds it, the reader
then failed to link with an unresolved overlay_input_access. The counter is
now defined beside the reader; the overlay uses the same one as before.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Server: its chat lines in colours the owner chooses; protocol 45
A dedicated server's own lines in chat (its welcome, console messages and
answers) were made violet in #129. The owner can now pick the colours.
- "chat_color": the "Server" badge and name, as "#RRGGBB" (default
"#8E5CFF", violet).
- "chat_text_color": the text of those lines (default "#D9C8FF", lavender).
- Both are in the config's "server" section; a value that is not a colour
stops the server from starting and names the setting.
- Console: chat-color <#badge> [<#text>]. Saved, and sent to everyone on
the server, so the next line uses it.
- With the defaults, chat looks as it did.
The colours travel in the roster, so this is protocol 45: servers and
games must both update. Lobbies hosted by a player are unchanged.
A dedicated server's own chat lines (its console, welcome message and
answers to this player) get a violet "Server" badge and name and
lavender text, in the open chat and the fading lines.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MzTrhiZ2cNYyJgMHqTp1kf
Poses and skater sound between a dedicated server and its players use new
formats. Lobbies and the links between games are unchanged.
Poses (pose_codec.h, pose_batch.h):
- A pose is rounded once (rotations to 0.08 degrees, positions to a
millimetre) and sent as its differences from a pose of the same player
the receiver has acknowledged. Several players' poses share one message.
- The receiver acknowledges messages once a tick; the sender builds only on
acknowledged poses, or on the whole pose it sent reliably. Loss costs the
poses in that packet and nothing more.
- Fingers are not sent to players further than "finger_distance" (25 m).
- Games upload their own poses the same way, and the server acknowledges.
- About 300 B a pose at full rate against about 660 B before.
- The server no longer rounds rotations by distance: it saved little.
Sound (sound_codec.h):
- Each sample is sent as what changed since the one before, numbers rounded
to 1/1024. One reliable message a tick carries every skater a player can
hear. A stream is sent whole at its start and every two seconds.
- About 106 B a message against 368 B before, on a recording of real play.
Direct connections:
- "connection": "relay" (default) or "direct", with "direct_address" and
"direct_port". A direct server listens on UDP and is listed with its
address; players still sign in through Steam.
- Games connect straight to servers that offer it and fall back to the
relays after 5 s. Setting and "mp direct-connections" to turn it off.
Server:
- "bone_scale_limit" is 1 by default: resized body parts are off unless a
server allows them.
- Logs Steam's relay network status at start-up and in "net", and watches
the Steam sign-in.
- "pack_ms" (10): how long Steam may hold a message to pack it with others.
- "steam_debug": logs what Steam's networking says, for connection faults.
- "relay_everything": sends poses and sound through the server even between
games that have linked, for testing with few players.
- "net" shows pose sizes by rate, the share sent without fingers, and whole
poses sent.
Game:
- Only ReSkate's nametags are shown; the game's own are removed.
- "mp pose-dump <seconds>" records the local skater's poses and sound.
Tests: pose_codec_tests covers exact round trips, chains of differences,
held fingers, damaged input, the sender and receiver over a link that
delays, loses and reorders, and the sound format; with a recording as its
argument it prints sizes on real play.
Protocol 44: servers and games must both update.
Game
- Player distance (Settings > Interface, "player-distance"): how far
away another player is still built as a skater, 50 to 1000 m, default
120. Past it they keep their nametag or dot. All the way up shows
everyone. A player already shown stays until 15% further out, so one
skating along the edge is not built and taken down over and over. The
game ran a full skater for every player on the server wherever they
were, which is most of a frame on a full one
- Nametags are always ReSkate's own. The "ReSkate nametags" toggle, the
"Nametag style" button and the nametag-style command are gone; the
game's own nametags are never shown
- Nametag distance ("nametag-distance"): how far away a name still
shows before it becomes a dot, 10 to 500 m. Default 120, was a fixed
150, so by default the name and the skater go at the same distance
- Nametag dots ("nametag-dots"): off hides the dots for far players and
the ones at the screen's edge for players off screen
- Friends' nametags only ("nametags-friends"): only Steam friends get a
name or dot; chat bubbles still show for everyone
Server
- A player out of sight of another (half as far again as the low rate
starts, 255 m by default) is sent to them once a second instead of
five times. On a full server most players are out of each other's
sight, and at five a second each they were most of what was sent
- Rotations are rounded before a pose is passed on, more coarsely the
further away the recipient is: 0.04 degrees within the full rate's
reach, 0.16 within the half rate's, a third of a degree past that,
about 5 degrees out of sight. The pose is still an ordinary one. A
bone that turned by less than a step is the same bytes as before, so
the difference from the reference leaves it out, and the low bits of
the ones that did turn pack away. By distance only: a player the
crowd limit slowed keeps the fine rotations
- A recipient crossing from one precision to another is sent a whole
state of that player, since a difference from a reference of another
precision would carry every bone again
- "net" shows the size of the poses sent at each precision
Profiler
- A function in ReSkate.dll is reported by its address when the DLL has
no symbols. A release build named every one of ours as the nearest of
three exports, so a report could not say which was slow; the
release's symbols name the address afterwards
Limit how many objects each player can place (protocol 43)
- Servers and lobby hosts set how many objects each player may have
placed: object_limit in ReSkateServer.json and the "objects" command,
"Objects per player" in the host options. Default 100; 0 is no limit
- The host and a server's admins are not limited
- At the limit a player's game refuses another object, from the native
object tool and the park editor, and the menu shows how many they have
placed
- Enforced by the host or server, which shows everyone no more than the
limit of each player's layout; objects already shown keep their place
- The limit travels in the roster, which takes the protocol to version
43: builds before this cannot join sessions with builds after it
- The protocol tests link again (the server browser needs the identity
lists since the official servers change)
- The server browser opens sorted by most players, in the overlay and
the native menu; official and friends' servers still come first
- Dedicated server names may contain "/" (builds before this hide a
server whose name has one)
Server browser
- Official servers (the backend's "official_servers") sort first and are
drawn in ReSkate blue
- Servers Steam friends are skating in sort next, drawn in green with the
friends' names; searching a friend's name finds their server
- A player in a session they joined can join another server straight from
the list; hosts still end their session first, and a Steam friend's join
offer never replaces a session
- Joining a dedicated server from the list records it as the player's
public session, so friends see it and the row shows HERE
- Blocked servers (the backend's "blocked_servers") are hidden and cannot
be joined, by code either
- When the backend sets "server_tokens_required", dedicated servers that
signed in without a login token are hidden, except on the player's own
network
- A search that gets no internet list from Steam keeps the last list for
two minutes, and waits six seconds before treating it as empty
Roles
- New Staff tag from the backend's "staff" list: green name, badge and
item animation, ranked after Dev
- Staff can pick a rainbow for their items on the Special page; it is sent
as a solid colour older builds can show, so the protocol is unchanged
Dedicated server
- steam_token: sign in with a Steam game server login token and keep the
same Steam ID every start; empty signs in anonymously as before
- A listed server without a token says so at startup, and when the token
rule starts or stops hiding it
- Linux servers update themselves from the release's "server_linux"
tarball, with the machine's curl and tar, pinned by SHA-256, and carry
on in the same process
Launcher
- Only create the MiniDumpWriteDump API-set shim under Wine/Proton
Each built its text with path::string(), which throws for a character outside the ANSI code page, so the real error or message was replaced by a code-page error.
- Mod merge: rebuild a merged bundle's chunk metadata the way the game
writes it (one record per chunk, in chunk GUID order), so costumes
from different mods built on the same game costume keep their
textures and meshes
- Merge audit checks that layout, and there is a new unit test for it
- Server names: only letters, numbers, spaces and - _ [ ] ( ),
1 to 64 characters; the server browser hides servers with other names
- New Centrix tag from the backend's "centrix" list: blue and white
name, badge and item animation, ranked after Dev and before Creator
A player's recent chat lines show as speech bubbles above their skater: newest nearest the head, older lines stacking upward, each popping in with a slight overshoot before it fades. Emotes render as their images, a message that is nothing but a few emotes shows them jumbo, and a message longer than a handful of lines is cut with an ellipsis so one line can never wall the screen off.
Local display options live under Settings > Interface > Multiplayer (on/off, own messages, distance, duration and how many recent lines stack) and the console gains mp chat-bubbles, chat-bubbles-own, chat-bubbles-distance, chat-bubbles-duration and chat-bubbles-history.
The chat panel and the bubbles now share one rich-text module (chat_rich), and a filtered message keeps its emote names: the bad-word mask is applied, but emote tokens are put back from the original before they are parsed.
- Mods that add copies of store items under new names are no longer
loaded. The launcher, mod manager and game say why.
- A chat line passed on by the host only shows a Dev/Creator/Homie
badge when the player's own copy of it arrives too, so a host
can't put one on a line that player never wrote.
In offline mode, closing the pause menu on Social or Custom Stuff and
opening it again showed an empty Social page, and Back did nothing until
the player switched tabs. The game reopens the page at the last position
in its own tab list (Social at position 4, the Store at position 3)
before insert() swaps the Store for Custom Stuff. Offline that swap
leaves the tab count at 5, so the menu never redraws the page.
Keep a copy of the Store tab last for a moment so the count changes and
the right page is drawn, then drop it again (trim_store). Online, and
reopening on Map, Hub or Skaters, nothing changes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>