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.
56 lines
2.7 KiB
C++
56 lines
2.7 KiB
C++
#pragma once
|
|
#include <Windows.h>
|
|
#include <array>
|
|
#include <string>
|
|
|
|
namespace dingosdk::crash_report {
|
|
inline constexpr DWORD protocol_version = 6;
|
|
// Who asked for the dump: ReSkate's last-chance filter, the game's own fatal handler about to
|
|
// write its dump (which it does without ever reaching that filter), or a level load that has sat
|
|
// in one stage for minutes while the game runs on (capture_stuck_load: the game is not ending, so
|
|
// the helper goes on waiting afterwards).
|
|
enum class CaptureSource : DWORD { unhandled_exception, game_fatal_handler, stuck_load };
|
|
inline constexpr DWORD capture_timeout_ms = 15000;
|
|
// A stuck load's dump holds every thread as it was; its exception, made up by the thread that
|
|
// asked, says only that this is not a crash.
|
|
inline constexpr DWORD stuck_load_exception = 0xe0535455;
|
|
inline constexpr DWORD stuck_capture_timeout_ms = 30000;
|
|
struct SharedReport {
|
|
DWORD version{protocol_version};
|
|
DWORD thread_id{};
|
|
EXCEPTION_POINTERS* exception{}; // Address in the parent; MiniDumpWriteDump uses ClientPointers=TRUE.
|
|
std::array<wchar_t, 4096> url{};
|
|
std::array<wchar_t, 32768> directory{};
|
|
std::array<wchar_t, 260> application{};
|
|
std::array<wchar_t, 32768> native_directory{};
|
|
// What the game was doing, for the report's tags: the level it loaded last, and the graphics
|
|
// card it renders on with its driver's version. Written by the game as they change, read by
|
|
// the helper after a crash (a torn read only spoils a tag).
|
|
std::array<wchar_t, 512> destination{};
|
|
std::array<wchar_t, 128> gpu_name{};
|
|
std::array<wchar_t, 32> gpu_driver{};
|
|
CaptureSource source{};
|
|
// Whether D3D12's record of the GPU's work (DRED) is on for this launch (gpu_breadcrumbs()).
|
|
DWORD gpu_breadcrumbs{};
|
|
// A stuck load's stage ("Starting level load") and how long it had been in it.
|
|
std::array<wchar_t, 64> stuck_stage{};
|
|
DWORD stuck_seconds{};
|
|
};
|
|
// Explicitly inherited unnamed handles; no token or paths on the command line.
|
|
enum HandleIndex : std::size_t { mapping, requested, captured, stopping, ready, parent, handle_count };
|
|
struct Handle {
|
|
HANDLE value{};
|
|
Handle() = default;
|
|
explicit Handle(HANDLE handle) : value(handle) {}
|
|
~Handle() { if (value && value != INVALID_HANDLE_VALUE) CloseHandle(value); }
|
|
Handle(const Handle&) = delete;
|
|
Handle& operator=(const Handle&) = delete;
|
|
HANDLE release() { const auto result = value; value = nullptr; return result; }
|
|
};
|
|
inline std::wstring environment(const wchar_t* name) {
|
|
std::array<wchar_t, 32768> buffer{};
|
|
const auto size = GetEnvironmentVariableW(name, buffer.data(), static_cast<DWORD>(buffer.size()));
|
|
return size && size < buffer.size() ? std::wstring(buffer.data(), size) : std::wstring{};
|
|
}
|
|
}
|