Commit Graph
13 Commits
Author SHA1 Message Date
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
AyeZeeBB 0ae0e71f0f Map downloads on join, faster mod merging, connect cards in the server browser
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.
2026-10-10 13:15:04 -05:00
zeex64 3db9045d23 Merge pull request #151 from AlexanderPuglisi/fix/merge-progress-and-times
Mod merge: steps for the material grid and asset overrides instead of a frozen "Linking"; each step's time in the log
2026-10-09 23:06:10 -05:00
AlexandeeerandClaude Opus 5.5 3e76d285f1 Mod merge: report the steps after linking and log each step's time
With many mods the launcher kept showing "Linking <last mod>" while the
material grid, a live merge's load screens and the asset overrides ran,
since none of them reported a step (#138). Each now does, and the total
is counted again once the superbundles are known: a disabled map that
ships the root level has it merged too, and the first count left it out.

The merge also notes how long each step took. The note is added after
the stamp is written, so a reused patch does not report the times of the
merge that built it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VNYF3aYa2q3MkFXc5xYnDd
2026-10-10 03:49:37 +02:00
Digital-YetiandClaude Opus 5.5 2573a0ceec Reuse the mod merge while a mod is disabled
Each disabled mod was added to the merge fingerprint after a newline, so
the stamp held the fingerprint across several lines and previous_merge,
which reads the stamp a line at a time, compared only the first of them
with the whole fingerprint. They never matched, and every launch with a
mod disabled merged every mod again. A space keeps the fingerprint on one
line.

Co-Authored-By: Claude Opus 5.5
2026-10-09 18:38:27 -05:00
AyeZeeBB 0f38a9fdeb faster mod merging 2026-10-09 15:42:23 -05:00
xThrasherrr e1e09e438e Leave out a mod whose TOC cannot be read instead of every mod
The merge read each mod's superbundle TOC without a catch, so one damaged file stopped the whole merge and the game started with no mods at all.
2026-10-06 10:29:44 -06:00
xThrasherrr a0c1224df2 Leave out a mod whose archive number does not fit in 16 bits
The launch merge truncated cas_65537 to archive 1 while a live apply rejected it, and any misnamed archive stopped the whole merge instead of just that mod.
2026-10-06 10:29:44 -06:00
AyeZeeBB a9742673da log changes 2026-10-05 17:27:50 -05:00
AyeZeeBB de631ad9e6 leave out mods that copy store items, chat badge check
- 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.
2026-10-05 16:29:37 -05:00
DeckardDetribineandClaude Opus 5.5 e715b9bf75 Mod merge: carry the assets a mod adds into the copies maps carry
Maps ship their own copy of game bundles such as
bam_levelroot/bam_coregameassets, and that copy loads instead of the game's
on their levels. Changes an asset mod makes to the game's EBX already
propagate into those copies; assets it adds did not. A mod that appends a new
song to the master music playlist therefore left the playlist naming a song
the map's copy never contained, so the song was missing on custom maps.

collect_asset_overrides now also records what an asset mod adds to a game
bundle, and combine inserts it into other mods' copies of the same bundle,
after their own assets, unless the copy already has that name:
- an added EBX is carried only when one of the mod's recorded changes imports
  it, or another carried addition does (the playlist names the song, the song
  imports its wave), so an addition never travels without the change that
  needs it;
- a resource the mod adds under the same name as a carried EBX goes with it
  (a wave's sound-bank resource registers the wave; without it the game
  crashes instantiating the wave);
- TOC chunks the mod adds that its carried EBX name are listed in each
  superbundle those assets go into, pointing at where the mod's archive
  landed (a map's superbundle resolves chunks from its own TOC).

A copy in the TOC the adding mod ships its own bundle in (cosmetic mods share one)
merges with that mod's bundle and already has the asset, so only copies in other
superbundles, i.e. maps' level TOCs, receive additions.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-04 17:44:00 +01:00
AyeZeeBB abdda77946 Give each mod archive its own index; unblock launches and saves
Mod archives (Engine/Vfs/mod_merge*)
- A free archive index no longer has to sit at or below the highest index
  the layout already declares. The engine keeps archives in a table keyed
  by layer, install chunk and a 16-bit index, with no range to stay
  inside; what it cannot survive is a reference to an archive the layout
  never declared. Indices are taken lowest first, per package directory.
- So a mod that collides takes an index of its own and its file is hard
  linked rather than concatenated, and no two mods share one archive's
  4 GB of addressable bytes. Sharing is left for a mod added while the
  game runs, which has no declared index to take, and for a directory
  with no index left.
- A placement addresses its payload with a 32-bit offset, so both append
  paths now refuse to cross 4 GB instead of wrapping round and pointing
  the game at some other payload: CasStore::write fails with the archive
  that is full, and the live-apply path checks archive 1's size plus the
  mod's before appending and asks for a restart, which gives the mod an
  archive of its own anyway.

Injection through a hooked LoadLibraryW (Engine/Core/Platform)
- A player could not launch at all: "Child LoadLibraryW entry bytes match
  neither Windows' kernel32 file nor this process". Anti-virus and
  overlays hook the entry with a jump to a per-process trampoline, so the
  bytes differ in the launcher and in the child and neither comparison
  could match. The guard already allowed the same hook when both
  processes carried it identically, so it refused on an accident of how
  the hook was written rather than on intent.
- inline_jump_length recognises the forms a hooking engine writes (rel32
  jmp or call, push/ret, jmp [rip], mov rax/jmp rax, short jmp). When one
  is present and every byte after it still matches the clean kernel32
  file, the launch goes ahead: the body is Windows' own, and the provider
  image already matched on timestamp, checksum and size. A wholesale
  replacement is still refused, and now says so.
- The failure names the modules loaded into Skate that came from neither
  Windows nor the game folder, instead of guessing at "security
  software". An accepted hook is logged as a warning with the same list.

Launching (Launcher/launch.cpp)
- Exporting loose scripts is a convenience, and a folder that would not
  take it was failing the whole launch: fs::create_directories threw and
  nothing caught it. The export is skipped, RESKATE_LOOSE_FILES goes to
  0 so the runtime does not look for files that are not there, and Skate
  starts. Someone whose install is under Program Files can play; only
  editing loose scripts is lost.

Failures worth reading (Launcher/problem.h)
- A hooked LoadLibraryW, a refused write and ERROR_ELEVATION_REQUIRED
  each explain themselves now. Windows reports the last two in the user's
  own language -- "Zugriff verweigert", "La operación solicitada requiere
  elevación" -- so the rules key on the operation names and the error
  number, which are never translated.

Saved skaters (Extension/Customization, Extension/Profile)
- Outfits stopped saving and every slot showed the standard skater. The
  load hook marks a preset blocked on entry and clears it only on a full
  success, so a load refused for a catalog that was not ready yet left
  the preset blocked for the session and every later save was refused as
  previous_load_rejected. The game asks once per level load and does not
  ask again, so one lost race cost a skater until a restart. Logs show
  the catalog arriving three seconds after the refused load, at startup
  and again on a map switch 17 minutes later.
- The record is remembered in CosmeticRuntime::pending_loads and applied
  by retry_pending_cosmetic_loads from the customization pump, which
  already waits for refresh_cosmetic_catalog. The preset stays blocked
  until a load really succeeds, so nothing is written over the outfit on
  disk.
- Those records belong to the loadout manager's array, which can be
  replaced in between, so each pointer is checked against the live array
  exactly as a save checks one -- manager current, begin/end sane, 0x48
  stride, at most 10 records, in range and aligned. A record that no
  longer belongs is dropped as retry_record_moved rather than written
  through.
2026-10-03 18:30:28 -05:00
AyeZeeBB ca1d82f636 1.0.0 Release! 2026-10-02 14:40:41 -05:00