3 Commits
Author SHA1 Message Date
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 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 aef269497e Rebuild the launcher's mod manager, settings and status tile
The mod browser was a 960x620 panel inside a 1180x680 window, reached from
a tile the same size as SETTINGS. People could not find it, and once they
did there was room for about six mods.

Window
- The design size is 1440x840. Everything is laid out in design units and
  multiplied by g_scale, which now scales down when that would not fit the
  screen's work area, so a small laptop or a high DPI no longer gets a
  window running off under the taskbar.
- The MODS tile is MOD MANAGER: taller than SETTINGS, directly above PLAY,
  with the pending update count as a pill on its subtitle line.
- background.jpg is 1920x1027, so the bigger window is not upscaling a
  1280x720 photo.

Mod manager, a page rather than a panel
- begin_page fills the window and draws its own minimise and close, since
  it covers the main screen's. BACK or Escape leaves it.
- A nav rail holds MY MODS and GET MODS (count badges, blue for the open
  one), the install actions and BACK. Refresh sits with what it refreshes,
  top right of the content.
- Every mod is a full-width row: icon, name, author, description, version
  and downloads, with a blue INSTALL or UPDATE and a tick box on the right.
  Ticking several installs them in one run.
- Clicking a row opens that mod's overview in a popup, replacing the
  side-by-side details pane that halved the list's width.
- virtual_rows draws only the rows a scrolling child actually shows.
  ImGuiListClipper cannot do this, as it assumes every row is a fixed
  height.
- Installing is a centred panel over a dimmed page with the activity, a
  striped bar and Cancel, instead of a progress bar in the footer.

Settings
- The same page and rail: GAME, DISPLAY, KEYS and ADVANCED are nav tiles
  rather than a row of tab buttons, and the content keeps to a 760 px
  column so the explanations stay a readable measure.
- The Steam sign-in, Steam Guard and QR dialogs stay centred panels. They
  are prompts, not pages.

Status and failures
- The STATUS tile carries its state in a coloured edge and a pill (WORKING,
  READY, ACTION NEEDED, PROBLEM), its headline is 22 pt over muted detail,
  and the standing facts (game build, ReSkate version) sit under a rule
  instead of competing with the live status as equal rows.
- Launcher::fail keeps the raw message for the log, and problem.h turns it
  into a headline and the next thing to try. The injection and PE-identity
  failures ("VirtualAllocEx failed", "Injected ReSkate.dll is not present
  in the child module list") all become "ReSkate could not attach to
  Skate", with the anti-virus and overlay advice that actually fixes it;
  the Steam download, a missing or damaged ReSkate.dll, the content cache
  and a shared menu/console key each get their own. Anything unmatched
  keeps its raw text.
- A failed tile grows Open logs and Copy details. Copy details puts the raw
  message and the versions on the clipboard, ready to paste into Discord.
2026-10-03 16:10:55 -05:00