122 Commits
Author SHA1 Message Date
AyeZeeBB 48d1e245db Outfit layers: an item worn on top keeps its textures, and the log says what the layers do
The game's skater loader builds each recipe slot with that slot's own function, which puts the
item's appearance preset on a material named for the slot's kind ("Outfit_Top_mat"). An item worn
on top sits in another kind's slot, so its mesh found nothing under its own material ("Bottom_mat")
and drew white. The preset lookup guard's addEsShaderPreset hook now also puts the preset of an item
on top on its own kind's material (layer_materials.h: which presets those are, from each item's
catalog folder and AssetPaths; the five native functions checked by their first bytes).
The outfit service logs what goes on top and where, the slot trials, why an item is not worn and
what it waits for.
2026-10-21 19:49:35 -05:00
zeex64 c745d605ae Merge pull request #310 from moelrobi/fix/poll-answer-repeat
Polls: answers no longer refused as repeats, and less chat noise
2026-10-21 18:45:38 -05:00
AyeZeeBB f352179785 Merge main into plugins: the trainer (PR 300), object unlocks (290), server browser sort (302) and export bitrate (322)
Resolved where main's trainer meets the plugin branch:
- Board Break, the drone, Road Rash, Hall of Meat and Grind Exits are plugins here, so their
  built-in code stays deleted: the trainer no longer hands Board Break's wear values back (the
  plugin does not tune physics), its QUICK SETTINGS list no longer names Grind Exits or Board
  Break, and the drone's debug action and menu are not brought back.
- The trainer's pump power, gravity, revert boost and transition help run beside the plugins'
  pushes and velocities on each physics step; both sides' new declarations are kept.
- The game's own pad reads go through game_pad_read (the gamepad filter, Dark Pop's D-pad hiding,
  the grind sticks) and then the plugin branch's menu and hidden-button handling.
- The trainer's forced grind settings are noted as the stance like any other value.
2026-10-21 18:26:55 -05:00
AyeZeeBB b67fe93e55 Crashes: guards for 2.1.1's top crash sites, launcher checks, stuck-load reports, quieter logs
From 2.1.1's Sentry reports (60,000 in three days, 2026-10-21):
- Textures: a stale render texture handle takes the game's default texture instead of reading
  through null (Skate.exe+0x3e897fb, a third of all reports, every one with TheVlixOne-Nike_Pack 2.3.x).
- Physics: the wake pass's bitset is made as long as the world's owner list once indices pass
  20000, after long multiplayer sessions (+0x3d99e2f, +0x3d9ee43, +0x3d9ee47).
- Music: more than 1024 candidates are picked by ReSkate; the game's shuffle wrote past its stack table.
- Streaming: a staged read's piece that reaches past its 64 KB buffer is left unfilled (VCRUNTIME memcpy).
- Multiplayer: a remote skater or board whose parent bus link is damaged is left alive instead of
  destroyed (+0x2b94cd0).
- Mesh pool: on an integrated GPU its budget is capped by the RAM and page file free; the Memory
  line says what the PC has left.
Launcher:
- A folder with non-ASCII letters is a hard stop (the boot crash +0x18df4cf came after "Start anyway").
- The game's data files are checked against the supported build's sizes (from Steam's manifest);
  missing, cut-short or online-only files send the player to verifying.
- One game per folder: the launcher will not merge or start while one runs there, and ReSkate.dll
  holds the folder's mutex.
- Advice on the ready screen for PCs short of RAM and page file; reports carry pc.ram_gb and
  pc.commit_free_gb.
Stuck loads:
- A load in one stage for two minutes sends a stuck-load report (every thread's stack and the log,
  error.type stall, load.stage, load.seconds) while the game goes on (crash protocol 6).
- A load the player closes sends its timing with the stage it was in.
Logs: the PanelTrace diagnostics and the neighborhood unlock override's observation lines are gone.
2026-10-21 18:10:58 -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 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
zeex64 f365914dfe Merge pull request #322 from DreadHeadHippy/default-export-bitrate
Replay export: use the export dialog's 8/12/18 Mbps choices instead of forcing 100 Mbps
2026-10-20 14:15:04 -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
wagu ded49756ea Docs: project structure for clarity 2026-10-20 09:59:50 -04:00
DreadHeadHippyandCopilot 5728a91e7f Replay export: the export dialog's 8, 12 and 18 Mbps choices apply again
Every export was forced to 100 Mbps, about 750 MB per minute of replay, whichever quality
was chosen. The bitrate patch is removed; the frame pacing fix stays.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-10-20 09:56:30 -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 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
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
andrewnakasandClaude Opus 5.5 14cc8b17b1 Boosts start at 0 (off), so RESET EVERYTHING reads STOCK
The forward, up and off-board up boost speeds defaulted to +20, which counted as not
stock. They now default to 0: the boost adds nothing until a speed is set, and resets
(RESET EVERYTHING, the console resets, restore_debug) put them back to 0.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-18 11:29:09 -06:00
andrewnakasandClaude Opus 5.5 5f0b2de4af Cheats: boosts past the sliders; cheats and addons in QUICK SETTINGS and on the MODIFIED line
Forward, up and off-board up boosts take a typed value up to 10000 (sliders still end
at 300 / 25), Revert Boost strength up to x100. Noclip, No Bail, Dark Pop, a boost
that is not +20, Revert Boost, grind exit triggers and Board Break are listed at the
top of QUICK SETTINGS with their values (Go to, Reset), make the SANDBOX line say
MODIFIED, and RESET EVERYTHING turns them back.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-18 10:42:29 -06:00
andrewnakasandClaude Opus 5.5 0bcb0ba2ac Merge ReSkate v2.1.0 into the trainer, in its new menu layout
The trainer keeps upstream's page and naming (SANDBOX; noclip, No Bail and
the boosts on Skater > Cheats; the full screen controller menu) with its own
TUNE sections, presets card and search inside. The MOVEMENT tab is gone:
`trainer open movement` opens Skater > Cheats, where the Revert Boost rows
now sit. Upstream's Hardcore preset sits beside Realistic; saving
trainer.json and reading the map file stay off the client thread.

Board Break's wear and the trainer no longer undo each other: wear writes
four tuning values itself, and every trainer write used to put them back to
the trainer's copy (and a level loaded on a worn board took them as stock).
board_break::handling_value() tells the trainer what wear wants; values the
player has not changed are handed back to it, their stock is the game's own.

Tests: Hardcore's check follows the sections (topic, not the old lists);
the session test pokes a flip speed past the trainer's own limit (100).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-18 00:13:49 -06:00
Robin MoellerandClaude Opus 5.5 07cd31b8aa Votes: the same answer in the next poll is no longer turned away as a repeat
Chat's flood control refuses a line identical to the one before it within 15 s, which also
caught /2 in a poll right after /2 in the last one. An answer to the running vote or poll is now
exempt from that one rule, on the server and in the game; the pace still holds, and the vote
still counts one answer per player.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 02:02:56 +02:00
AyeZeeBB 7676c1d5ea Shader registry guard: no registration of a destroyed database, no lookup index past its records
The shader expression registry registers a database from a queued job, and builds its per-key item
lists from the database's lookup without a bounds check. A database destroyed before its job ran,
or a lookup index past its items, left the registry holding pointers that crash it later
(Skate.exe+0x3f7cf33, +0x3f7ceed, +0x20960b in Sentry). The guard skips a registration for a
database already destroyed and points an out-of-range index at a valid item of the same key,
logging each.
2026-10-17 14:27:20 -05:00
zeex64 8bed866f92 Merge pull request #221 from tsullivan13/park-object-sets
Park editor: saved object sets, plus fixes for multi-object edits
2026-10-17 13:18:42 -05:00
AyeZeeBB d75d34614b Keyframe smoothing: key slots built once per rebuild, no playback hook, smoothness in the menus
A rebuild builds one segment per key and each needed every key's slot, so a long replay built
them once per segment: the game's rebuild is hooked too and the slots built for its first segment
are kept for the rest of it (per Behaviour and Subject). The segment player is no longer hooked
(it only counted plays for keysmooth status, every frame). The smoothness is a slider beside the
switch in the overlay (sent when let go, as each change rebuilds the open replay's camera) and
Keyframe smoothness (100, 75, 50, 25%) in the pause menu and Mod Options > Visuals. The startup
line logs on the runtime channel.
2026-10-17 12:29:53 -05:00
samitakkulaandClaude Opus 5.5 51dddf3d91 Keyframe smoothing for the replay editor's free camera
The game plays the replay camera's framing keys as cubic Hermite segments whose speed changes at
every key (the acceleration jumps there, and it brakes where a channel slows or turns back), so a
free-camera shot surges and settles around each key. keysmooth on rewrites each segment as the game
builds it, so that the game's own player plays the natural cubic spline through every key: speed
and acceleration carry on through the keys, and every key is still met exactly, at its time.

- keysmooth on|off (off by default), keysmooth amount 0..1 (1 by default; 0 is the game's curve)
  and keysmooth status; kept in %LOCALAPPDATA%\ReSkate\KeySmooth.settings. Only the free camera
  (Behaviour 1) is smoothed; the other camera modes keep the game's curve.
- A switch in Mod Options > Visuals and in the overlay's Skater > Freecam.
- The curve apart from the game, with tests (DINGOSDK_BUILD_REPLAY_KEYFRAMES_TESTS); the hooked
  functions are fingerprinted, and a build that differs gets no hook.
- contrib/keyframe-smoothing.md: what it does, how, and what was seen in game.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 08:33:32 -07:00
AyeZeeBB 1456c1fa51 Customization: a preset with a parameter type the game cannot read is left out, not applied
Scrolling shirts onto Yudi-Yuddispack's philippleinshirt_ap crashed the game (Skate.exe+0x3dc07ed):
one of the preset's set parameters has a type of 0x0c07010304040502 (null in another crash). The
game type-checks every set parameter when it next applies a preset to a material, reading the
type unchecked, and catching that crash inside addEsShaderPreset was too late: the preset was on
the material already and the next update crashed on it.

addEsShaderPreset's guard now checks the preset first, as that type check reads it: the TypeInfo,
its data, a word at +4. A preset with a parameter whose type cannot be read is left out as a
preset that is not loaded is (the item shows without it), and named in the log once with that
parameter's key. Many of the game's own types are built at run time, so the test is that the
type reads, not that it lies in the game's image.
2026-10-17 00:48:40 -05:00
AyeZeeBB 4c07f2493b Menu: a full screen layout for controllers beside the window, and the pages regrouped
The ReSkate menu now has two styles, switched with View / F11 or the buttons in its top bar
and saved with the profile (`ui fullscreen`):
- Window: the mouse menu as before, with a side rail of pages in groups.
- Full screen: made for a controller, in the pause menu's look. Pages across the top (LB / RB),
  each page's sections as the ONLINE page's tabs (LT / RT), button prompts at the bottom, the
  pause menu's sounds, and the pause menu's own Multiplayer pages as ONLINE.

The pages are regrouped: HOME (quick switches and a tile for each page), MAP, BUILD, SKATER
(freecam, first person, cheats), SANDBOX (once Trainer), ADDONS (drone, Board Break, Road
Rash, Hall of Meat, grind exits, music), ONLINE, PROGRESS, MODS, SETTINGS, DEVELOPER.

Full screen, every shared control is drawn for a pad: switches and option rows changed with
left / right one step a press, sliders as steppers that repeat when held, rows of buttons,
and pages that scroll with the right stick. Search boxes and typed values stay in the window.
A pad press takes the menu's focus back and hides the pointer until the mouse moves.

Also: map pictures in the map picker (official loading screens, a mod's icon) with a search
box in the window, Splash and Tutorial Island left out of it; number boxes beside the
window's sliders; the binds in groups, with an action bind to open the menu (`menu`); a menu
size for each style (`ui scalefull`); the time of day stepping from the one last asked for.
2026-10-16 23:37:33 -05:00
zeex64 20d58a4b73 Merge pull request #262 from Kalmarv/pr/tod-v3
Time of day: the new one loads only after the old one has unloaded
2026-10-16 20:35:04 -05:00
AyeZeeBB 290089e16d crash fix 2026-10-16 17:34:06 -05:00
AyeZeeBB 0dcbcb3a89 Drone: other players' drones shown as a 3D model
A model is spawned at each other player's flying drone and moved every frame. It is the drone's
own model (FPV Drone by PinaPipe, CC BY 4.0, credited on the DRONE page), built by ReSkate Studio
into a pack that ReSkate.dll carries and unpacks into Mods/.reskate-builtin before the merge.
Without the pack the game's traffic cone stands in. dronemodeltest spawns one in front of you.
2026-10-15 22:39:49 -05:00
AyeZeeBB 3249f747dc Crash reports: the game's own fatal crashes come with the memory their stacks point at
Most crashes are caught by the game's own fatal handlers, which write a
dump of thread stacks only; the launcher could only copy it after the
game had exited. A crash on a freed or overwritten object then showed
the faulting registers but not the object or the list it came from.

- game_fatal_dump: the game's MiniDumpWriteDump import points at
  ReSkate. Before the game writes its dump, the crash reporter takes its
  own of the still-running game for the faulting thread; the game's dump
  follows as before. Reports say capture.source "game-fatal-handler".
- The reporter's dumps include the memory the stacks point at
  (MiniDumpWithIndirectlyReferencedMemory), a few MB more a report.
- The shared report says who asked for the dump (protocol version 4).
- Tests: a game-handler crash is captured with a heap block only its
  stack points at; ReSkate's own capture keeps it too.
2026-10-15 20:01:55 -05:00
AyeZeeBB ea3f081367 World: big maps no longer run out of spatial cull IDs while loading
A spatial transaction queue gives every object it tracks a cull ID from a
free list made once, when the queue is, at the game's
InitialCullIdListSize (40,000 in its config), and never grown. A custom
map with more objects (Cardiff) emptied it while loading and the next
insert read entry 0xffffffff of the list (crash at 0x489cfe9).

- spatial_cull_ids: as each queue makes its list, its size setting is
  raised to 262,144, one ID for every entity slot the entity pages hold;
  a larger configured value is kept. 12 bytes an ID per queue.
- The contract checks the list maker and how it reads the setting; it is
  installed at startup with the other world pools.
2026-10-15 20:01:48 -05:00
AyeZeeBB 3faa58bb42 Render-resource pool: the other renderer is allocated room for its metadata pointers
719cba1 stopped writing the metadata pointers into the other renderer
(0x2daa00 bytes, Skate.exe+0x30c64cc, kept at 0x75f2700), taking them for
the state owner's alone. They are not: the other renderer's own code reads
them through the patched view (0x030e6bff, called from 0x30a7e18) and
append (0x03e94fe6, called from 0x30d8ebb). Without the write, it read
whatever lay 18 MB past its end. With it, as in every release before, that
memory was overwritten, or the write faulted when nothing was mapped there
(the store_field crash).

- The other renderer's allocation is patched to the state owner's
  0x11ab080 bytes (0x030c64cc, mov ecx), so +0x11aae28/+0x11aae30 are
  inside it.
- Both renderers' metadata pointers are written again, before and after
  the native constructor. The resource-state and relation-mask vectors stay
  the state owner's alone: the other renderer keeps fields of its own at
  +0x2da920.
- The contract's comment says which renderer reads what, and where.
2026-10-15 18:16:22 -05:00
AyeZeeBB 719cba1166 Freezes and crashes: the game's threads no longer wait on ReSkate's slow work
Players reported the game hanging for about a second while skating. A
profile showed the memory line in the log walking every heap
(HeapSummary) on the client thread, 0.5 to 2 s every two minutes. An
audit of everything that runs on the game's update and render threads
found more of the same, and Sentry's top crashes had causes of ours.

Freezes:
- Memory log line: no heap walk or thread snapshot; the GPU part and the
  write happen on a thread of their own.
- Profile database: synchronous=NORMAL in WAL mode. A save is still kept
  when the game crashes; every play event no longer waits for the disk
  inside the game's hooks.
- ReSkate's own preferences and values (menu clicks, session sliders,
  Discord) are saved by a background writer in order; reads see a value
  until it is saved.
- Input: the foreground window and the keyboard are sampled on a thread
  of their own (GetAncestor and GetAsyncKeyState stalled the client tick
  40-50 ms when another program held Windows' lock); flight input uses
  the sample; ClipCursor at most twice a second while a menu has the
  pointer.
- Hooks installed while the game runs go in one transaction per place
  (HookBatch): throwdowns, remote players, the party, Hall of Meat.
- Off the update thread: the host's map package lookup (one table read in
  the background, not the Mods folder per offer), the trainer's map file
  and settings save, Board Break's settings save, mod music playlists and
  their covers, the Spotify station covers.
- Off the render thread: the Modding page's and the deck card's Mods
  folder reads. The overlay's three startup waits share five seconds.
- Less work per frame: Steam names reused while one a frame is asked
  again, 2 friends a tick, steam_api64.dll checked once per process,
  cosmetic names read in place rather than a system call per character,
  an outfit load no longer copies the inventory per slot, the throwdown
  type scan runs at background priority over resident memory, the Board
  Break deck label is kept a minute.

Crashes:
- Render-resource pool: the metadata fields are written to the state
  owner only. The other renderer is 0x2daa00 bytes, and +0x11aae28 is far
  past its end (store_field crash; heap corruption in every release).
- Other players' skateboard effects: a stale skateboard component is no
  longer followed, and the joint lookup is walked with a bound first (an
  endless loop in reused memory ended in GameStall).
- Launcher: Oodle decodes into the buffer it asks for with corrupt data
  possible, and its assertions no longer stop the process (heap corruption
  in the store-copy scan; a breakpoint in oo2core).

Timings (Send performance timings):
- A frame of half a second or more in a level is sent as game.freeze:
  where the time went (ReSkate's tick, the game's frame, or outside it),
  whether the renderer kept presenting, and ReSkate's busiest zones.
- Closing the game sends the level session it was in.

Music after a connection drop:
- Spotify device: an account Spotify could not be reached with is kept and
  tried again (3 s doubling to a minute); a session that drops is taken
  up again. Only an account Spotify refuses is asked for anew.
- YouTube playlist pictures that could not be fetched are tried again,
  from 30 s to 10 minutes apart.
2026-10-15 18:10:53 -05:00
andrewnakasandClaude Opus 5.5 7234243462 Trainer 0.7.0: wallies, on-foot moves, late flips, Dark Pop 3.1, built on ReSkate 2.0.9
Merges ReSkate v2.0.9.
- Wallies (the game's own switch) with their measured numbers; double / triple jump, jump
  on release and wipeout bounce on foot; foot flip / spin speeds; no speed limit on foot.
- Flip speed and the per-trick Late flip speed now change late flips; Late flip start /
  buffer rows.
- The trainer never changes the game's own settings (GAME SETTINGS rows only show them).
- Dark Pop 3.1 (Sivaes/darkpop, GPL-3.0), saved on and off like No Bail; Revert Boost 2.0.
- The search for the game's values walks memory once and shows in the panel.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-15 14:13:26 -06:00
KalmarvandClaude Opus 5.5 e7786068ce Time of day: the new one loads only after the old one has unloaded
Switching time of day could load the new layer while the old one was
still loaded: the apply loop goes through the layers in catalog order
and sends one event a pass, so going to an earlier time (WeatherDay ->
Evening) sent the load first, and nothing waited for an unload to finish.
Two times of day at once carry both times' lights, and a level with many
lights overflowed the engine's light tables.

A time-of-day layer is now asked to load only once every sibling time of
day that is to be off reports requested and loaded both false; until then
its row says "Waiting for the old time of day".

An unload is no longer sent while the engine is still loading the layer
itself. The engine ignored it, so at a level load the level's own time of
day could stay loaded beside the saved one, and with the wait above the
saved one never loaded.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 13:50:51 -06:00
AyeZeeBB 164fdffbd0 Descriptor heaps: dense custom maps no longer overflow the GPU's descriptor heap and crash it
The renderer gives each frame 131,072 shader-visible descriptors past a persistent 120,000, in
heaps of 333,333. Dense custom maps (the Los Santos City sublevels, San Andreas) draw more than
that in a frame, and the renderer wrote past the end of the heap: shaders read garbage
descriptors, which faulted or hung the GPU (page faults at nonsense addresses, in draws, texture
fetches and ray tracing alike). ReSkate now patches the device setup at boot so each heap is
D3D12's 1,000,000 and a frame may use 524,288; heaps are 644,288 descriptors. LS-B2, LS-B3 and
San Andreas (210,000 a frame at its peak) now hold.

Also in this change:
- Memory: perf memory owners/heap/gpu/report, a ledger of who commits the game's RAM; the
  render-resource pool no longer allocates its 115 MB twice; the EadpErrorsData arena is
  capped at 32 MiB (EA's error reporting is blocked anyway).
- Crash reports: tagged with the map, destination, graphics card and driver version (protocol
  v3), so Sentry can group GPU hangs by map and card.
- GPU diagnostics (--gpu-diagnostics): a fuller DRED report, the device-removal and video
  memory watches, a large-draw watch, a record of which game code made and freed each GPU heap
  and resource, checks of every GPU address bound, and a meter of each descriptor heap's use.
- World pools: peak use of entity pages, render instances and spatial blocks in the log.
- dingosdk_mod_mesh_check: checks every MeshSet a mod ships against its geometry; the MeshSet
  reader now knows static meshes' layout.
2026-10-15 13:57:11 -05:00
zeex64 dc43a50a47 Merge pull request #243 from Kalmarv/pr/lights-v2
Lights: a level with more lights of one kind than the game holds no longer crashes
2026-10-15 13:17:39 -05:00
AyeZeeBB 6df4f9a7bd Replay export: videos are encoded at 100 Mbps whichever quality is chosen
he export dialog's quality setting picks 8, 12 or 18 Mbps for the H.264
encoder (three mov eax immediates at Skate.exe+0x62c24f, +0x62c256 and
+0x62c25d in the 20260929 build). All three are now 100000 kbps.
- The code around them must match the supported build's bytes, and each
  value must be the game's own or already 100000; otherwise nothing is
  written and the log says the change was skipped.
- The log says whether the bitrate change or the frame-pacing hook was
  skipped. start() reports success if either one is in place, so
  replay_export_initialized can say active while the hook is off.
- The fix that encodes every rendered frame is unchanged.
2026-10-14 20:11:01 -05:00
KalmarvandClaude Opus 5.5 3468f556b0 Lights: a level with more of one kind than the game's table holds no longer crashes it
The game keeps each kind of light (PbrSpotLight, PbrSphereLight, ...) in a
table of 8,192 and crashes at Skate.exe+0x4ea4094 when a level makes more.
- Each kind's light factory is hooked: once the kind's table is nearly full
  it gives no entity, as the game's own factory does for a light it should
  not make. The light is not drawn and the game goes on.
- Said in the log: the kind of light and how many were left out.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 09:40:06 -06:00
AyeZeeBB 6c45e9666d World layers: a server's catalog must be the supported build's, and a player is not put out over one that is not
2.0.8's dedicated server was released with a world-layers.json scanned from
a game Steam had updated: 263 layers, where every player's game has 261. A
server that shares its layers (world_layer_sync) sends one choice for each,
the player's game turned the message down as unreadable, and nobody could
join such a server ("Join code, sender identity, or multiplayer protocol
did not match", and "Disconnected." in the server's log).
- supported_build::world_layer_count (261): how many layers the supported
  build's levels have.
- Server: a world-layers.json of another count is not used; the log says
  why and layer sync stays off, where before every player was turned away.
- --export-world-layers refuses a game folder whose count differs, so a
  release cannot be built from an updated game again.
- Player's game: a layer list of another length is left unread and every
  layer stays as the player has it; the rest of the message is taken and
  they join.
2026-10-13 18:45:37 -05:00
AyeZeeBB 9f93c3cbb2 Shader tables: mods' are merged as in 2.0.7 again, and the game's song scorer stays within its list
Shader tables
- Reverts a61f82c ("Shader crash fix"). Since 2.0.8 a mod's own shader
  programs were copied into the merged table, and the tables that cosmetic
  bundles carry were merged across mods. Each such bundle then held other
  mods' programs, and the game built them as the bundle loaded, before the
  files with their compiled variants were there. That was 2.0.8's most
  reported crash (Skate.exe+0x3f86da6, some forty machines in ten minutes).
  2.0.9's guard passed such a program over, and the same players then
  crashed a little later in cosmetic loading (+0x3f7bb65, +0x16fe1a6,
  +0x3dc07ed).
- Whatever crash a61f82c fixed comes back with this for the mods that
  needed it.
- The guard stays.

Music
- The game's read of one song for its scorer (0x14f23a0) is replaced by the
  same read with the check it lacks: a place past the end of the playlist
  asset's songs has no song, which the game already answers with 0. 2.0.9's
  check in music_select_next_hook looked at what the queue held before the
  game was asked and did not see these; the game asked for places such as
  0xd570 and crashed reading them (7 reports on 6 machines).
- Said in the log the first eight times.

Not confirmed in game: neither change has been run by a player who was
crashing.
2026-10-13 18:44:15 -05:00
AyeZeeBB f356c1eafd Music screen: large playlists no longer empty it, and two logs say why things fail
Music screen: large playlists no longer empty it, and two logs say why things fail
Music screen
- The screen's list was turned down whole, and came up empty (the game's own
  Featured row too), once it held more than 1,024 songs: a few large YouTube
  Music, Spotify or local playlists went over that. The most is now 2,000
  songs and 16,384 places in playlists (music_ui_most_songs,
  music_ui_most_places); 2,000 because the screen's own table of songs is
  read only up to 2,048.
- The rows of the player's playlists are counted as they are registered and
  held under that: with no room left, the rest of a playlist is left out of
  its list (it still plays) and the screen is never empty for it.
- A row whose "artist - title" is longer than the screen takes is left out;
  one such row turned the whole list down as well.
- Said in the log: how many songs were left unlisted, and, should the list
  still be turned down, what it held.
Logs
- Spotify device: librespot's own warnings and errors are written at the
  warning level again; only the rest of what it says stays at debug. A
  player whose Spotify connects and stays silent had nothing to send.
- Multiplayer: a message turned down with "Join code, sender identity, or
  multiplayer protocol did not match" now says which of the three it was,
  its size and first bytes, and whether it came from a dedicated server.
2026-10-13 17:38:50 -05:00
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.
2026-10-13 16:31:09 -05:00
tsullivan13andClaude Opus 5.5 d9bac524db Park editor: saved object sets; duplicate selections; group local axes
Sets: save a selection under a name and place it again anywhere, on any map.

- The library gets an OBJECTS / SETS switch. SETS saves the selected
  objects as a set and lists the saved sets to place or delete (Delete asks
  for a second press).
- A set is a park file in <profile>/object_sets/<name>.park.json, so it
  shares the park format, its 2 MB limit and its name rules. Positions are
  relative to the set's anchor: the middle of its footprint, at its lowest
  origin.
- Placing follows the cursor as one wire cube per object, on surfaces or
  the grid plane; the mouse wheel turns it by the angle step. A click
  pastes the whole set: one undo step, under the paste path's object and
  session limits. Sets with objects missing from the catalog cannot be
  placed.
- A placed or pasted group is then selected with the move gizmo.

Editing groups:

- Local axes work for multi-selections. A placed set's axes are the
  rotation it was placed with, plus every later turn; any other group uses
  its last selected object's rotation. Applying a moved group does not snap
  its own rotation to the angle grid.
- Duplicate (button or Ctrl+D) copies every selected object at its saved
  position, rotation and scale, one grid step along X, as one paste.
- On a server with object scaling off, pastes (sets, duplicates, Ctrl+V)
  are made at 1x.

Tests cover set storage (anchor, round trip, replace, names, damaged files,
delete), saving and placing a set through the UI (surface, wheel, one
paste, no live preview), selecting it with its own axes, moving it along
them, and duplicating with and without scaling.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 09:02:41 -07:00
tsullivan13andClaude Opus 5.5 2a1b8530b7 Park editor: keep scale and links in multi-object edits; delete selections
Fixes in the stock park editor that a multi-object edit (a paste, an undo,
a loaded park mod) runs into:

- Pasted objects lost their world link. A paste creates its objects one by
  one and saves them when the whole edit completes, but the placements
  runtime reconciles after every create and unlinked rows whose id was not
  saved yet. Every create unlinked the ones before it: only the last pasted
  object could be selected, moved or deleted, and deleting the others
  removed them from the layout but left them standing in the world. The
  reconcile now counts the editor's pending layout as saved.
- Scale was lost on paste, undo and park-mod load. The native create recipe
  has no scale lane, so a created object spawns at 1x. Only the placement
  preview resized it afterwards; a create step with a scale now becomes a
  move, verified by the server tick's readback like any move.
- Scale was lost on level reload. Restored objects spawn at 1x and the
  pose poll then saved 1x over the saved scale. Restores with a scale are
  resized on the next server tick, and the poll leaves them alone until the
  resize is read back.
- Delete did nothing with several objects selected. Delete (key or button)
  now removes the whole selection as one edit and one undo step.

Tests: the transaction fixture's create now spawns at 1x like the game and
reconciles after every create like placement_finish_batch; new checks
cover pasting a scaled group, every pasted object keeping its link, moving
and rotating a pasted group, and multi-delete with undo.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 09:02:41 -07: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
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 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
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
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
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
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