mirror of
https://github.com/Dingo-Shenanigans/ReSkate.git
synced 2026-10-23 21:05:58 +02:00
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.
45 lines
2.0 KiB
C++
45 lines
2.0 KiB
C++
#pragma once
|
|
#include <Windows.h>
|
|
#include <cstdint>
|
|
#include <filesystem>
|
|
#include <format>
|
|
#include <string>
|
|
|
|
// One game at a time in a folder. A second Skate.exe started over the same folder merges the mods
|
|
// again into the Mods\.reskate patch the first one has open, and the first then crashed reading
|
|
// it (Skate.exe+0x41e0f81 with "Cannot place ...cas_02.cas" and "Save is already in use"; two
|
|
// launchers started within the same millisecond in one log; 2026-10-21). A running game's
|
|
// ReSkate.dll holds a named mutex for its folder (Runtime/runtime_init.cpp) and the launcher
|
|
// will not merge or start a game while it is held (Launcher/gui_launcher.cpp, main.cpp).
|
|
namespace dingosdk::game_instance {
|
|
// The mutex's name for a game folder: the folder's path, ignoring case, hashed.
|
|
inline std::wstring mutex_name(const std::filesystem::path& folder) {
|
|
auto text = folder.lexically_normal().wstring();
|
|
while (!text.empty() && (text.back() == L'\\' || text.back() == L'/')) text.pop_back();
|
|
if (!text.empty()) CharLowerBuffW(text.data(), static_cast<DWORD>(text.size()));
|
|
std::uint64_t hash = 0xcbf29ce484222325ull;
|
|
for (const auto c : text) {
|
|
hash ^= static_cast<std::uint16_t>(c);
|
|
hash *= 0x100000001b3ull;
|
|
}
|
|
return std::format(L"Local\\ReSkate.Game.{:016x}", hash);
|
|
}
|
|
// Whether a game holds the folder's mutex now.
|
|
inline bool running(const std::filesystem::path& folder) {
|
|
const auto handle = OpenMutexW(SYNCHRONIZE, FALSE, mutex_name(folder).c_str());
|
|
if (!handle) return false;
|
|
CloseHandle(handle);
|
|
return true;
|
|
}
|
|
// Takes the folder's mutex for the rest of this process. False when another process holds it.
|
|
inline bool claim(const std::filesystem::path& folder) {
|
|
const auto handle = CreateMutexW(nullptr, FALSE, mutex_name(folder).c_str());
|
|
if (!handle) return true; // (no mutex to be had: nothing is refused for it)
|
|
if (GetLastError() == ERROR_ALREADY_EXISTS) {
|
|
CloseHandle(handle);
|
|
return false;
|
|
}
|
|
return true; // (kept open until the process ends)
|
|
}
|
|
}
|