377 Commits
Author SHA1 Message Date
AyeZeeBB 2e40aeb6e2 Game data of another build: the launcher asks for a verify, and mods are looked at again
After Steam updated skate., some installs had the supported Skate.exe over
the new build's data (a copied game, or a download that stopped part-way).
The launcher called that ready, every mod was left out as "made for game
build 29544144, not the installed 29663206; rebuild it with ReSkate Studio",
and the mods stayed out after the game files were put right.
Launcher
- Ready now also needs the game's data to be the supported build, read from
  Data\layout.toc against supported_build::game_data_changelist (29544144).
  Data of another build, or none, reads "Game files need verifying".
- DOWNLOAD in that state checks every file (-validate) instead of fetching
  only what is missing. A download that fails part-way no longer ends on
  ready because Skate.exe arrived.
- Data whose build cannot be read does not block.
Mods
- A mod left out because the game was of another build is no longer
  remembered in .reskate-excluded.json: it is checked on every launch. One
  already remembered for it is looked at again.
- When it is the game that is not the supported build, the mod's message
  says to verify the game files in the launcher, not to rebuild the mod.
v2.0.8
2026-10-13 16:31:09 -05:00
AyeZeeBB 9124869ba4 Launcher: a failed Steam download writes DepotDownloader's last lines to the log
"The Steam download did not finish" is the launcher's message for any
failed download, and what DepotDownloader said (the account does not own
the game, Steam refused the sign-in, the disk is full) was only written at
the debug level, so Open logs showed nothing to go on.
When a download fails, its last 40 lines are now written to the log as
warnings, after the exit code. The Steam login name is still left out, and
so are the rows of a QR code and the progress lines.
2026-10-13 15:53:55 -05:00
AyeZeeBB 3cc9a8d26a Merge branch 'main' of https://github.com/Dingo-Shenanigans/ReSkate 2026-10-13 15:38:38 -05:00
AyeZeeBB 9b81c821e4 Kicks: a popup for the player who was put out, and vote kicks last 5 minutes
A player kicked or banned only found out why from the status line of the
multiplayer menu, if they opened it.
- What the host or server says as it puts a player out ("You were
  kicked...", "You are banned...", away too long, a mod or cheat it does
  not allow) is now shown in the middle of the screen with an OK button,
  under YOU WERE KICKED, BANNED or REMOVED. The same when they are refused
  on trying to join again early. A link that is simply lost shows nothing
  new.
- Answered with A or B on a controller, Enter or Esc, or a click on OK. The
  game's input is held while it is up, as for the vote for the next map, so
  the button that answers is not also a press in the game.
- Console: "popup test" shows it with a sample message, to try it without
  being kicked.
Server: a kick by a vote has a time of its own, votes.kick_minutes, 5 by
default (1-1440, or 0 for until the server restarts); it no longer goes by
players.kick_minutes, which is now an admin's kick only and is still until
the restart by default. Console: votes kick-minutes <minutes>|restart, and
"votes" shows it. A config without the key takes the 5 minutes.
2026-10-13 15:38:36 -05:00
zeex64 9fb0d7fb40 Merge pull request #216 from Belcross-Dev/grind-exit-pop-out-strength
Grind exits: pop-out strength slider
2026-10-13 15:31:22 -05:00
AyeZeeBB 8cad9f2c13 Launcher: no exception for Proton, it has a folder of its own there too
- The launcher refuses to start from a Steam library folder under
  Wine/Proton as well; the check is no longer skipped there.
- README, Linux (Proton): the launcher and ReSkate.dll go in a new, empty
  folder, and the Steam launch option swaps in the launcher's full path in
  place of EA's anti-cheat launcher. Noted as not yet tested on Proton; the
  earlier test was with the launcher beside Skate.exe.
2026-10-13 15:14:51 -05:00
AyeZeeBB 375605b9fe Launcher: ReSkate lives in a folder of its own, not Steam's skate. folder
Launcher: ReSkate lives in a folder of its own, not Steam's skate. folder
- The launcher refuses to start from a Steam library folder
  (...\steamapps\common\<game>): it shows an error saying to move
  ReSkateLauncher.exe and ReSkate.dll to a new, empty folder, then closes.
  Checked before anything is read or written there. Not under Wine: on
  Proton, Steam starts the launcher from the game's folder.
- The "not in your skate. folder" error no longer tells players to put the
  files beside Skate.exe in Steam's folder; it now says to keep them together
  in a folder of their own.
- README: Getting started says to extract into a new, empty folder, where the
  launcher installs its own copy of the game, so a Steam update cannot break
  it. The Proton section says why it is the one exception.
2026-10-13 15:00:19 -05:00
AyeZeeBB 28118efc27 Objects: other players' objects are ghosts by default, and their card is a visitor's
Objects other players place are spawned locally, so the game took every one
for the local player's own: all were solid, and their card offered the
owner's buttons and named the wrong player.
- Other players' objects are ghosts the skater passes through, as in the
  game's own sessions. Each player's row in the session menu has an
  "Objects: solid / ghost" switch, remembered by Steam ID; a dedicated
  server's own objects (its parks) are solid unless switched off.
  `mp objects-solid <SteamID64|server> on|off` does the same.
- The card's own Disable and Enable on one object stand over that player's
  setting until the setting is changed.
- The card on an object someone else placed no longer offers Edit or
  Delete: the game's "is this mine" and "may this be edited" checks answer
  for who really placed it. It offers Disable instead.
- The card names the owner of the object it is for, read from the card's
  own script, instead of the owner of the object nearest the skater.
- A dedicated server has a player card of its own, "Server", shown on what
  it placed.
Server: the Mods folder is kept when the configuration is reloaded. A park
mod was reported as not being in the Mods folder after a reload.
2026-10-13 03:37:45 -05:00
Belcross 883bdb985f Grind exits: a trigger pressed up to 1 s before a grind counts
The window in which a trigger pressed before the grind connects still
picks the exit side goes from 0.4 s to 1 s. Pressing it as you ollie up
to a rail often came more than 0.4 s before landing on it, and the
trigger was then ignored for that grind. The console's limit goes up to
2 s to match (grindexit prewindow <0-2>).
2026-10-13 08:54:24 +01:00
Belcross 64bfefbf68 Grind exits: pop-out strength slider
A Pop-out strength setting (10-100%, kept) scales the sideways speed of
trigger-set grind exits, for rails next to a wall, where the full exit
carries the skater into it. 100% is the default and exactly the previous
behaviour.

- ReSkate menu: a slider in the GRIND EXITS card, sent when it is let go,
  in steps of 5.
- skate.'s Mod Options and the tools menu: a row stepping 100 / 75 / 50 /
  25%.
- Console: grindexit strength <10-100>; kept in control.txt with the
  other grind exit settings.
- Below 100%, an exit the game was already sending toward the chosen side
  is scaled too, so the setting applies to every trigger-set exit.
2026-10-13 07:59:13 +01:00
AyeZeeBB 30a320ff62 Throwdowns: a grouped line score is no longer cut at its first separator
A Jam Session takes the score of the line just landed from the score HUD's
text, with the script native ParseInt, which is the C library's atoi. atoi
stops at the first character that is not a digit, so a line shown as 5,432
was read as 5 and added 5 to the player's total. Reported for Jam Sessions
and Spot Battles: lines of 5,000 and more adding one or two points.

ParseInt now reads groups of three digits whole, set apart by a comma, a
full stop, an apostrophe or a space: "5,432" is 5432. Text that is not a
grouped number is read exactly as before. The first few grouped scores are
logged, to confirm the cause in play.
2026-10-13 01:14:01 -05:00
AyeZeeBB 180cdc9c85 Objects: the placed-object prompt names who placed the object 2026-10-13 01:04:13 -05:00
AyeZeeBB 0e542fc5a2 Server: kicks can be timed, by a setting and for one kick 2026-10-13 00:58:35 -05:00
AyeZeeBB 2e186b9839 Launcher: mod profiles, sharing them by code or file, and Thunderstore dependencies
The Mods page has a third tab, PROFILES. A profile is a saved list of which
mods are on, in what order and at what version; every mod stays installed
once, in the one Mods folder. Loading a profile rewrites mods.json, switches
off what it does not name, and downloads from Thunderstore what it names
that is missing. Profiles live in Mods/profiles.json.

A profile travels the way r2modman's do, so the two managers read each
other's: export.r2x inside a .r2z file, and a code on Thunderstore's
profile service. Config files in an r2modman profile are ignored.

Installing or updating a Thunderstore package now brings the packages it
depends on, needed ones first, leaving out any already installed at a new
enough version. A mod pack is a package that is nothing else.

A kick, by an admin or by a passed vote, used to keep the player out until
the server restarted. "kick_minutes" in the players section of the config
(1-1440; 0, the default, is still until the restart) and the console
command "kick-time <minutes>|restart" now set how long it lasts.

The player is told how long when they are kicked, and how many minutes are
left if they try to join early. A kick keeps the time it was given, so
changing the setting is for later kicks. Bans are unchanged.
2026-10-13 00:55:29 -05:00
zeex64 242ac11814 Merge pull request #207 from Frumpy9/fix/proton-oodle-release-paths
Fix Proton Oodle DLL paths and add portable release ZIP packaging
2026-10-12 23:54:34 -05:00
AyeZeeBB 28231c0df2 Typing dots: none for commands and private messages, and no flood of stop notices
A line that starts with "/" is a command, a whisper or party chat, so typing
one no longer shows dots to the whole server. Dots already showing are cleared
when the line becomes one.

A "stopped typing" notice was relayed every time it arrived, while "typing"
was held to one per 200 ms, so a modified client could flood everyone through
the host. A lobby's host and a dedicated server now pass a stop on only when
that player's dots are up, which is at most once per accepted "typing".
2026-10-12 23:45:27 -05:00
zeex64 eb038d5797 Merge pull request #214 from wilu222/typing-dots
Add typing indicator above a user while they are typing a message
2026-10-12 23:40:38 -05:00
zeex64 58231d4ead Merge branch 'main' into typing-dots 2026-10-12 23:40:24 -05:00
AyeZeeBB 4ac1343b95 Crash reports: self-hosted Sentry instead of Backtrace, and opt-in performance timings
Crash dumps now go to the project's own Sentry server. The launcher's
out-of-process helper is unchanged; only where it posts and what it expects
back are:

- The default endpoint is the Sentry project's minidump URL. Report
  attributes travel as Sentry tags, with the release as reskate@<version>.
- An upload counts as accepted when the server answers with an event ID.
- "backtrace" is "crash_report" throughout: the namespace, files, CMake
  targets, DINGOSDK_CRASH_REPORT_URL, DINGOSDK_BUILD_CRASH_REPORT_TESTS and
  the RESKATE_CRASH_REPORT_URL override.

Performance timings are new, and off unless "Send performance timings" is
ticked in the launcher's settings (RESKATE_TRACING=1). A small tracer
(Engine/Core/Debug/trace.h) posts each finished step to Sentry as a
transaction from a background thread; the launcher and the game it starts
share one trace. Timed: the update check, the Steam download, Thunderstore
installs, the mod merge, starting the game, the launch up to the first
playable level, each level load, joining a session, fetching the identity
lists, and the time spent in each level with its average frame rate and
long frames. Turning crash reports off turns timings off too.
2026-10-12 23:24:33 -05:00
wilu222 149da6f72e Show dots above a skater while they are typing a message 2026-10-12 19:50:45 -04:00
Frumpy9 5a1b11ddb9 Remove README changes from Proton path fix 2026-10-12 18:15:39 -04:00
Frumpy9 c813104252 fix: validate original ZIP names on Windows 2026-10-12 17:18:15 -04:00
Frumpy9 d0985ffcfd fix: anchor Oodle lookup and write portable release ZIPs 2026-10-12 17:14:21 -04:00
AyeZeeBB 86aa8d38fb Music: local files, online radio, equaliser, queue, and a Music page in the menu
Sources
- Local Files: add a folder of music from the setup page (MP3, M4A, AAC, Ogg,
  FLAC, WAV; up to 200 songs a folder, 12 folders). Names and covers come from
  the files' tags. Each folder is a tile in its own row.
- Online Radio: find stations by name (radio-browser.info) or add a stream's
  address (MP3, AAC, .pls, .m3u; no HLS). Each station is a tile in its own
  row; the track name follows what the station sends. Up to 24.
- Both are decoded by the library built into the DLL (SpotifyHelper), which
  now plays files and HTTP streams as well as a program's output, reads tags
  and embedded pictures, and accepts MPEG-2 ADTS from AAC stations.

Sound
- Five-band equaliser (60 Hz, 250 Hz, 1 kHz, 4 kHz, 12 kHz) and loudness
  levelling, applied to every source on its way into the game.
- Loudness, the speakers option, the equaliser and levelling are now kept in
  music-settings.json between sessions.

Setup page
- Remade in the mod's own colours and type, with numbered steps per source.
- Queue pinned to the right: now playing, the playlist's songs with covers,
  find, and press to jump. Spotify's own queue shows once signed in.
- Cards for Local files and Online radio; equaliser and levelling under Sound.

In game
- MUSIC page in the menu: player and queue, sound settings, source status and
  a button for the setup page.
- "Loading song..." notice in the corner for songs that take a moment, with a
  switch to hide it. Presses made while a song is loading no longer restart it.
- The Spotify row is hidden when Spotify is not in use.
- Console: "spotify ..." is now "music ..." (music, music setup, music gain,
  music through, music spotify client|login|logout).

Logs
- The music sources' working lines (traces, per-song and per-bind lines,
  librespot's own) are debug only; stack captures are skipped unless debug
  logging is on. Grind exits: the per-pop line is debug only too.
- A "Pace:" line when the game takes the sound faster or slower than real
  time, to find why music sounds fast after tabbing back in.

Chat filter
- A run of digits is a number, not a word spelled with look-alikes: a race
  time such as 2:55.0 is no longer masked.
2026-10-12 16:03:35 -05:00
zeex64 ea17559e3d Merge pull request #192 from Belcross-Dev/independent-grind-exit-triggers
Add independent grind exit direction
2026-10-12 15:58:05 -05:00
ReGlitched 22758a789e Merge branch 'main' of https://github.com/Dingo-Shenanigans/ReSkate 2026-10-12 14:55:32 -06:00
zeex64 c5d8456369 Merge pull request #194 from xThrasherrr/fix/headless-piped-output
fix(server): keep piped output when started headless on Windows
2026-10-12 15:33:53 -05:00
zeex64 158ba857dd Merge pull request #201 from pookatv/main
Missing commands fix
2026-10-12 15:33:29 -05:00
Belcross 837bea4c40 Grind exit triggers: pick the grind exit side with LT / RT
LT / RT pressed during a grind pick the side the skater pops out to,
independently of the trick and the body's rotation (both come from the
left stick in skate.'s own controls). Only the sideways part of the
grind pop's launch is replaced, with the game's own sideways speed; the
trick, spin, pop height and along-rail speed are untouched.

- Input Mode: Toe / Heel (character relative, needs the stance) or
  Left / Right of the direction of travel.
- Grab guard: a trigger used to pick the side is hidden from the game
  until released, so it never starts a grab.
- Lean guard: while a claimed trigger is held in a grind, the left
  stick's left/right reaches the game at the pop, so the game's lean
  exit cannot drag the board into the rail.
- Off by default; switches in Mod Options > Player, the ReSkate skater
  page, the tools menu and the console (grindexit ...). Kept between
  sessions.
- Listener slots on existing hooks only: No Bail's physics step, the
  trainer's set_trajectory detour, and the overlay's XInput capture.
  No new detours. Build-locked to 20260929 through the trainer's byte
  check.

Measured on build 25414733: 48 vanilla grind pops, 144 trigger-set
pops. See Extension/Skater/GRIND_EXITS.md.
2026-10-12 19:33:50 +01:00
ReGlitched a61f82c46a Shader crash fix 2026-10-12 11:58:42 -06:00
AyeZeeBB 48a9cb8f5b Music: Spotify, YouTube Music and External Audio through the in-game player
Three outside sources can now be played through the game's own music
player. Each has its own row in the music screen, shown only when it is
set up, with tiles that behave like the game's playlists: track name,
cover, pause, next, and pressing a row to start that track.

How the sound gets in
- The game's song decoder is hooked. While one of these tiles is on, the
  audio of the game song behind it (its "carrier") is replaced, block by
  block, with the outside source's audio. The game's volume, fades and
  pausing still apply.
- Rows are songs of our own registered with the game's music registry
  (copies of a real song's asset with their own artist and title), so no
  game song is borrowed or renamed to list a track.

Spotify
- The game is a Spotify Connect device ("ReSkate"), built on librespot
  and linked into ReSkate.dll (SpotifyHelper/, Rust). Audio, track info
  and controls come straight from Spotify. Needs Premium.
- Optional sign-in through the Web API lists the player's playlists and
  Liked Songs as tiles with their tracks.
- librespot can no longer end the process (it does so on a free account
  and on playback errors); only its thread is stopped.

YouTube Music
- Videos and playlists added by link. yt-dlp is fetched on request into
  <Local AppData>\ReSkate\bin and checked against its published sums;
  decoding is done in the DLL, so no ffmpeg.
- Private and age-restricted songs: cookies.txt or a browser's sign-in,
  with QuickJS fetched as the JavaScript runtime yt-dlp then needs
  (Node.js is used instead when installed).

External Audio
- Any app's sound, captured per process from Windows, with the app's own
  output turned down while it plays through the game.

Setup page
- "spotify setup" opens http://127.0.0.1:8421/: device status, sign-ins,
  YouTube links and tools, the external app, loudness. Loopback only;
  changes are accepted from its own page only.

Also
- Speakers in the world play the tile's audio; grabbing one keeps the
  player on their tile.
- Playlists added while the game runs are sent to the music screen live.
- MUSIC-SETUP.md: setup guide for players.

Building the Spotify device and the YouTube decoder needs cargo; without
it ReSkate.dll builds without them.
2026-10-12 03:16:36 -05:00
Pooka 670fab085a Missing commands fix
Adds missing WorldRender commands
2026-10-11 21:53:26 -07:00
AyeZeeBB 1c5da074cc readme 2026-10-11 21:55:51 -05:00
AyeZeeBBandClaude Opus 5.5 d2b8e18097 2.0.7 hotfix: map updates, vote bar, ReSkate Admin tag, servers on the newest map version
Map updates
- A map the game already has, being replaced by the host's version,
  could load as soon as the new files were in Mods, while the mods
  were still being applied: it ended on "This map is not loading". The
  session now holds the load while a map is downloading, installing or
  applying, as it waits for one that is missing.
- A player whose version of a map is later than the host's keeps it and
  loads. Only an older one is replaced by the host's. Versions are
  compared number by number (1.10.0 is later than 1.9.2).

Dedicated servers
- maps.latest_versions (off by default): the server asks Thunderstore
  for the newest version of each of its custom maps, at start and every
  maps.latest_check_minutes (5-1440, default 60), and writes it into
  the mod's manifest.json. Nothing is downloaded: the server reads only
  a map's level list and version, and players, who are held to the
  server's version, fetch it as they join. The map being played waits
  until nobody is on it. A folder that is not a Thunderstore package is
  not touched, and the level list is left as it is.
- Console: maps update, maps latest on|off, maps latest every <minutes>.

Overlay
- Vote card: the pass mark is always in the middle of the bar. Green
  grows over the left half up to the yes votes needed and over the
  right half past them, whatever share the vote needs.
- The "Staff" tag is "ReSkate Admin", shimmering from #2500FF to
  #B2F9FF.

No protocol change. Tests cover the version comparison and the
manifest write; the Thunderstore lookup was checked against the site.
The map update flow, the vote bar and the tag were not seen in game,
and the server setting has not run on a live server.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 21:19:49 -05:00
AyeZeeBB 0f8af62710 Entity limit 2x
The entity and pending-update pages are twice the game's own size
(262,144 slots), down from four times. Every page set the game keeps
is that many times its normal size whether a map uses the room or not,
and the largest map load seen needs about 150,000 slots.

A page is a power of two entries, found by a shift, so the steps are
two, four and eight times; there is nothing between. The 434 patch
lines are the same instructions as before, each with the number for a
page of 0x800 entries. The render-instance pool and the spatial
buckets stay at eight times, which still covers the capacity.
v2.0.7
2026-10-11 20:12:59 -05:00
AyeZeeBB 06ff1278a2 Console: "textures" prints the streamed textures in use 2026-10-11 19:37:02 -05:00
AyeZeeBB 8f2c456a39 Merge branch 'main' of https://github.com/Dingo-Shenanigans/ReSkate 2026-10-11 19:26:25 -05:00
AyeZeeBB a83cb83bb4 Raise the streamed texture limit to 32764, and warn when it is close
The game can stream 20480 textures at once. When a map and its mods
need one more, it takes a slot past the end of its table and waits for
ever on a byte that is part of a counter: a hang, then a crash in the
hang's own report (crash reports of 2026-10-11).

The limit is raised to 32764, the most a texture's 16-bit handle can
index, before the game makes its texture streaming manager:

- The manager is allocated longer (6.0 MB, was 2.3 MB) and its slot
  table and per-slot floats moved behind its end. Each of the 226
  instructions that hold one of those offsets or sizes gets another
  number; no code is added. Its four fixed lists are pointed at longer
  storage once the constructor has run.
- The renderer keeps a block of floats per slot for each of four
  layers. Its object grows to match (27 instructions), and the two
  places that index a layer's block as layer * 20480 become a multiply
  by the new count, in the same twelve bytes.
- Three functions keep 20480 entries on their own stack. Two list
  filters go through a longer list a stretch at a time, and the sort
  is given scratch room of its own past that many. Up to 20480 they
  run as the game wrote them.

Every instruction is checked byte for byte first, and nothing is
changed if any differs or the manager already exists. An empty
texture_limit_stock.txt beside the game leaves the limit as it is.

Players are told when they come close: a notice at 90% of the limit
in force and an error at 100%, each once until use falls below 80%.
The log records each new high in steps of 5%.

Also: when a function of the game finds its stack written over, the
game ends itself with exit code 0xc0000409 and no crash report. The
log now names that function and its callers first.

The site table (texture_streaming_sites.inc) is generated from a sweep
of the supported build; texture_streaming.h describes the layout.

Tested in game below 20480 textures only. Nothing has run above the
old limit, where the three stack guards and the longer lists first
matter. At 32764 the game still hangs; the notice is the protection.
2026-10-11 19:26:23 -05:00
zeex64 794d757dc3 Merge pull request #196 from FourthStudio/board-break/deck-packs
Board Break: one package for all decks, a button for each deck, baseplates on a broken board HOTFIX + TRUCK FIX
2026-10-11 18:21:55 -05:00
AyeZeeBB 3df1a3cdfc Performance settings: turn off the game's ad system
The in-game advertising (billboards from EA's ad service, with a
render pass that measures how long each was on screen) has nothing to
serve offline and still costs frame time. Its three switches are now
set to 0 with the other performance settings:

  AdTech.AdTechEnable
  AdTechService.AdTechEnable
  DingoAdTech.EnableAdTech

Suggested by a player who measured about 5% more fps; not measured
here. All three names are in this build's settings registry.
2026-10-11 18:10:47 -05:00
Fourth Studio 3d8a5fc8c7 Board Break: the trucks' baseplates stay on a broken board
The game's truck model has its hangers on the trucks' bones and its
baseplates on the deck's bone. A broken board hides the real deck by moving
that bone away, so its trucks lost their baseplates.

The decks inside a deck pack bring a truck model with the baseplates on the
trucks' effectors, bones under the trucks' own that no model uses. The render
pose hook writes each effector from its truck's bone, so that the baseplate
sits on the deck of a whole board however the truck steers, and goes with the
truck when a piece carries it off. With the game's own truck model nothing is
on those bones and nothing changes.
2026-10-12 01:10:34 +02:00
Fourth Studio 0c8add27a4 Board Break: a button for each deck in the overlay
The deck was only stepped through, one press for the next one. The overlay
now has a card BOARD BREAK DECK with a button for each deck: on the Mods page
above the installed mods, and under the feature's switch on the Skater page.
A deck that is not installed is greyed out, the one in the game is marked, and
a press asks for that deck by name: the mods are applied and the level loads
again with it.
2026-10-12 01:10:33 +02:00
Fourth Studio 1668488cd0 Board Break: a deck pack brings several decks in one mod folder
The launcher installs one mod folder per package, and the game takes one
mod's deck at a time, so a package could only bring one deck. A mod folder
may now hold a deck in each decks/<name>/, laid out like a mod folder. When
the mods are put together each of them becomes a mod of its own for the run,
listed as <folder>#<name>: it is chosen, set aside and switched like a deck in
a folder of its own. mods.json and the mod list only know the pack, which
counts as loaded when one of its decks is.

A pack's own layout is not one of its decks, whatever the folder is named,
and is set aside like any other deck model. It is what an older ReSkate
loads from the pack: 2.0.6 knows a deck by its folder's name only, so a pack
in a folder named Board_Break_<Name> with a breakable deck as its own layout
breaks boards there with that one deck.
2026-10-12 01:10:33 +02:00
AyeZeeBB 9b79fd7829 Guard a crash when the game describes a failed load
Guard a crash when the game describes a failed load

When a load fails, the game writes "load <address> failed with error:"
and describes each part of the load's error in turn. That list can
hold parts that were never set, and the game calls through them: six
crash reports from one player on 2.0.5 and 2.0.6 all end at
Skate.exe+0x2e3ab9c, after eight parts that read "no error".

The guard hooks that one function. Before the game describes the
list, every part that is not one of the game's own objects is emptied,
so it reads "no error" as an empty part does; the description also
runs under an exception handler. The failed load is then the game's to
deal with, as it meant to.

What the game wrote goes to the log as a warning ("The game described
the error of a load that failed"), with how many parts were emptied,
so content that does not load can be traced. The game's message names
no asset, only an address.
2026-10-11 18:00:30 -05:00
AyeZeeBB e344d585f4 Vote for the next map when a map's time is up
A dedicated server that rotates its maps can now ask players where to
go next instead of taking the pool's next map.

Server
- maps.rotation_vote: when the timer runs out, a vote between three
  maps drawn at random from the pool, "Random map" and "Stay here".
  The most votes wins, a tie is drawn, and with no votes it is the
  pool's next map. It ends early once everyone has voted.
- maps.rotation_vote_seconds (10-120, default 30) and
  maps.rotation_extend_minutes (0-240, default 15; 0 leaves "Stay
  here" out).
- maps.rotation_announce: a card when the map has 10, 5 and 1 minutes
  left.
- The vote's maps are drawn a minute ahead and sent to games
  (PacketKind::next_maps), so their pictures are ready when it opens.
- /vote extend: a built-in vote that gives the map in play
  rotation_extend_minutes more. On by default (votes.extend_map), and
  only runs while the maps are on a timer. "extend" is now a reserved
  vote name.
- Console: rotation vote on|off, rotation announce on|off,
  rotation stay <minutes>|off, rotation extend [minutes],
  votes extend ..., vote extend.

Game
- The vote opens as a popup in the middle of the screen: a tile per
  answer with its picture, name, share of the votes and count. It
  holds input as the map download card does, and works with a
  controller (D-pad, A, B), the keyboard and the mouse.
- Pictures: a mod map's icon from its folder, or from Thunderstore
  when it is not installed; the game's own maps show their loading
  screen picture, cut to its middle square. "Random map", "Stay here"
  and a map without a picture are drawn as shapes.
- Older servers and polls are unchanged: the vote is a poll, so it can
  still be answered with /1, /2... in chat.

Protocol 50: games and servers both need this build.
2026-10-11 17:21:27 -05:00
AyeZeeBB 8351654222 Votes by those who vote, map versions, maps reload, and a crash leaving a map
Votes: a vote is decided by the votes cast, not by everyone on the server. It
passes when yes is its percentage of them, at the end of its time, or sooner
once the players still to vote could not change it. A kick still needs two
yes. The card's bar is yes in green from the left and no in red from the
right, with a mark where yes has to reach. No protocol change.

Map versions: a map installed at another version than the host's is no longer
loaded as it is. The download card offers the host's version (MAP VERSION,
UPDATE), which replaces the installed one and is applied while the game runs.
For that the live merge keeps each mod's fingerprint with where its archives
were placed, and places a mod again when its files have changed since: before,
a mod replaced while the game ran was read where the old one lay. When the
host's version is gone from Thunderstore, or the old one's files are in use,
the player is told and leaves the session.

Dedicated server: "maps reload" reads the Mods folder again, so a map copied
in while the server runs can be switched to at once. The server window reads a
copy of the map list.

Map names: a custom map's level is dingolevel_reskate_<map>, and "reskate" was
left in its name ("/map reskate badlands"). The map's own name is shown and
typed now; the old spelling still finds it.

as a level unloads, the game takes each mesh variation out of its registry by the
entry's mesh and reads it unchecked, and this map's meshes unload before
their databases. A guard on that one function has the read of a mesh that is
gone go on with the next entry, and logs how many were passed over.
2026-10-11 16:12:57 -05:00
xThrasherrr f6b4ef2bcd fix(server): keep piped output when started headless on Windows
Reopening CONOUT$ closed the pipes or file a manager or service gave the
server, so nothing it wrote or was sent got through.
2026-10-11 14:27:29 -06:00
AyeZeeBB 1b15a04e29 Two hitches on the game thread, and profiler names without symbols
A 30 s profile on a 77-player server had four frames of 20 to 30 ms against a
usual 7.8 ms, from two things:

- The Park Editor read every mod's manifest every five seconds to list park
  mods, on the game's thread and whether or not its list was showing (the
  switch for that is never set): about 11 ms each time. The look every few
  seconds now runs on a thread of its own and is taken up when it is done;
  the one after making, renaming or removing a park is still at once.
- Connecting to a player asked Steam for their name, and waited on the Steam
  client for 7 to 10 ms each time a player came into reach. The link takes
  the name already read, if any: it only labels the link in diagnostics.

Profiler: a release ReSkate.dll has no symbols, and its functions were all
named after the nearest export. The check for that looked at the symbol's
size, but DbgHelp gives an export a size up to the next one. It now asks
whether the module's own symbols were loaded, and writes ReSkate.dll+0x<offset>
when they were not, to be named from the release's symbols afterwards
2026-10-11 14:50:27 -05:00
AyeZeeBB 314d31fe7b Update main.cpp v2.0.6 2026-10-11 14:09:29 -05:00
AyeZeeBB 6f1dae531c Server browser: favorite servers
A dedicated server can be marked as a favorite: F on the chosen server, or
ADD TO FAVORITES in the panel beside the list (the same to take it away).
Favorites carry a star, are listed first whatever the sort, and have a
FAVORITES filter beside FRIENDS.
2026-10-11 13:56:50 -05:00