#include "runtime_internal.h" #include "Extension/Customization/item_browser.h" #include "bootstrap.h" #include "Engine/Core/Hooks/hooks.h" #include "Engine/Core/Log/logging.h" #include "Engine/Core/Profiling/profiler.h" #include "Extension/Settings/engine_tweaks.h" #include "Extension/Settings/replay_guard.h" #include "Extension/World/load_error_guard.h" #include "Extension/World/mesh_unload_guard.h" #include "Extension/World/shader_permutation_guard.h" #include "Extension/World/light_table_guard.h" #include "Extension/World/stack_check_report.h" #include "Extension/Music/music_inject.h" #include "Extension/Music/spotify_web.h" #include "Extension/Music/spotify_device.h" #include "Extension/Music/spotify_dashboard.h" #include "Extension/Music/youtube_music.h" #include "Extension/Music/spotify_rows.h" #include "Extension/World/texture_handle_limit.h" #include "Extension/Console/commands.h" #include "Extension/UI/ui_pointer_skip.h" #include "Engine/Game/Build/addresses.h" #include "Engine/Game/Build/20260929/profiler_labels.h" #include "Engine/Game/Build/supported_build.h" #include "Engine/Vfs/mod_catalog.h" #include "Extension/Assets/map_download.h" #include "Extension/Boot/offline_boot.h" #include "Extension/HallOfMeat/hall_of_meat.h" #include "Extension/RoadRash/road_rash.h" #include "Extension/BoardBreak/board_break.h" #include "Extension/Skater/grind_exit_control.h" #include "Extension/Skater/camera_observer.h" #include "Extension/Progression/entitlement_request_hook.h" #include "Extension/Skater/skater_observer.h" #include "Extension/UI/NativeMenu/native_menu.h" #include "Extension/UI/NativeMenu/ui_sound.h" #include "Extension/Throwdowns/throwdown_lab.h" #include "Extension/Multiplayer/Session/session.h" #include "Extension/Throwdowns/throwdown_debug_text.h" #include "Extension/Multiplayer/Hud/custom_nametags.h" #include "Extension/Profile/local_profile.h" #include "Extension/Profile/local_profile_runtime.h" #include "Extension/Progression/fixed_stop_entitlement_provider.h" #include "Extension/Progression/mission_progression_override.h" #include "Extension/Progression/neighborhood_unlock_override.h" #include "Extension/Progression/progression_service_guard.h" #include "Extension/Rendering/graphics_labels.h" #include "Extension/Settings/gameplay_settings_override.h" #include "Extension/Settings/named_settings.h" #include "Extension/Skater/client_source_spawn.h" #include "Extension/Skater/no_bail.h" #include "Extension/Skater/skater_slot_override.h" #include "Extension/UI/Startup/startup_window.h" #include "Extension/World/level_loading.h" #include "Extension/World/loading_screen.h" #include "Extension/Customization/preset_lookup_guard.h" #include "Extension/Rendering/replay_export.h" #include "Engine/Vfs/content_catalogs.h" #include "Engine/Vfs/world_layer_scan.h" #include "Engine/Game/World/world_layer_catalog.h" #include #include namespace dingosdk::runtime::detail { namespace { bool exact_environment_one(const wchar_t* name) noexcept { const auto incoming_error = GetLastError(); std::array value{}; const auto length = GetEnvironmentVariableW(name, value.data(), static_cast(value.size())); SetLastError(incoming_error); return length == 1 && value[0] == L'1'; } bool validate_image(std::uintptr_t base) { IMAGE_DOS_HEADER dos{}; IMAGE_NT_HEADERS64 nt{}; if (!read(base, dos) || dos.e_magic != IMAGE_DOS_SIGNATURE || dos.e_lfanew <= 0 || dos.e_lfanew > 0x100000 || !read(base + dos.e_lfanew, nt) || nt.Signature != IMAGE_NT_SIGNATURE || nt.FileHeader.Machine != IMAGE_FILE_MACHINE_AMD64 || nt.OptionalHeader.SizeOfImage != dingosdk::supported_build::game_image_size) return false; if (!matches(base + rt::client_tick, rt::client_tick_prefix)) return false; for (const auto& entry : rt::image_checks) if (!matches(base + entry.rva, entry.bytes)) return false; return true; } } } extern "C" __declspec(dllexport) BOOL WINAPI DingoSDKDebugInitialize() { try { using namespace dingosdk::runtime::detail; auto& r = runtime(); if (r.initialized) return TRUE; r.base = reinterpret_cast(GetModuleHandleW(nullptr)); const auto logging_options = dingosdk::logging::options_from_environment(); const bool files_ready = dingosdk::logging::initialize(logging_options); dingosdk::logging::startup_banner(); if (!files_ready) dingosdk::logging::write(dingosdk::logging::Level::warning, dingosdk::logging::Channel::runtime, "File logging is unavailable; console and debugger output remain active."); if (!validate_image(r.base)) { dingosdk::logging::write(dingosdk::logging::Level::critical, dingosdk::logging::Channel::runtime, "Game image validation failed."); return FALSE; } if (const auto& content = dingosdk::content_cache::catalogs(); content.available) { dingosdk::logging::log(dingosdk::logging::Level::info, dingosdk::logging::Channel::assets, "Game content cache: {} items, {} challenges, {} entitlements.", content.items.size(), content.challenges.size(), content.entitlements.size()); } else { dingosdk::logging::write(dingosdk::logging::Level::warning, dingosdk::logging::Channel::assets, "Game content cache is not installed: item names, challenges and default entitlements are unavailable. " "Start ReSkate from ReSkateLauncher to install it."); } // World layers come from the installed level data. The launcher builds // the per-build cache; without it this scans the level TOCs once here. try { std::wstring executable(32768, L'\0'); executable.resize(GetModuleFileNameW(nullptr, executable.data(), static_cast(executable.size()))); const auto started = GetTickCount64(); auto layers = dingosdk::world_layer_scan::load_or_scan( std::filesystem::path(executable).parent_path(), dingosdk::world_layer_scan::cache_file()); dingosdk::logging::log(dingosdk::logging::Level::info, dingosdk::logging::Channel::world, "World layers: {} layers across {} maps from the level data ({} ms).", layers.layers.size(), layers.anchors.size(), GetTickCount64() - started); dingosdk::install_world_layer_catalog(std::move(layers)); } catch (const std::exception& error) { dingosdk::logging::log(dingosdk::logging::Level::warning, dingosdk::logging::Channel::world, "World layers are unavailable: {}", error.what()); } // The game shows nothing for several seconds yet; the startup window // covers that, and goes by itself once the game's window appears. A // startup that fails takes it down on the way out. dingosdk::startup::open(); struct StartupWindow { bool handed_over{}; ~StartupWindow() { if (!handed_over) dingosdk::startup::close(); } void hand_over() { handed_over = true; dingosdk::startup::status("Starting Skate\xE2\x80\xA6"); } } startup_window; dingosdk::initialize_client_source_spawn(r.base); if (!dingosdk::runtime::initialize_bootstrap(r.base)) return FALSE; // Skate imports its graphics factory from the sibling Streamline // interposer. Load that ordinary dependency while the game is still // suspended so the overlay can hook the provider before first use. HMODULE self{}; #pragma warning(push) #pragma warning(disable: 4191) if (!GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, reinterpret_cast(&DingoSDKDebugInitialize), &self)) { dingosdk::logging::log(dingosdk::logging::Level::error, dingosdk::logging::Channel::runtime, "Cannot locate the runtime module (Windows error {}).", GetLastError()); return FALSE; } #pragma warning(pop) wchar_t self_path[32768]{}; const auto self_length = GetModuleFileNameW(self, self_path, 32768); if (!self_length || self_length >= 32768) { dingosdk::logging::log(dingosdk::logging::Level::error, dingosdk::logging::Channel::runtime, "Cannot resolve the runtime path (Windows error {}).", GetLastError()); return FALSE; } const auto interposer_path = std::filesystem::path( std::wstring(self_path, self_length)).parent_path() / L"sl.interposer.dll"; // Every mod folder may declare destinations, highest priority first, // and the Patch folder keeps working for a single Studio-built map. const auto& mod_catalog = dingosdk::mods::catalog(); const auto patch_level_path = std::filesystem::path( std::wstring(self_path, self_length)).parent_path() / L"Patch" / L"reskate-levels.json"; r.patch_level_manifests = {patch_level_path}; if (!mod_catalog.data_root.empty()) { const auto data_level_path = mod_catalog.data_root / L"Patch" / L"reskate-levels.json"; std::error_code level_path_error; if (!std::filesystem::equivalent(patch_level_path, data_level_path, level_path_error) || level_path_error) r.patch_level_manifests.push_back(data_level_path); } r.custom_levels = read_custom_levels(dingosdk::mods::level_manifest_paths(mod_catalog)); if (r.custom_levels.present) dingosdk::logging::log(dingosdk::logging::Level::info, dingosdk::logging::Channel::level, "Custom-level destinations after merging: {}.", r.custom_levels.levels.size()); auto interposer = GetModuleHandleW(L"sl.interposer.dll"); if (!interposer) interposer = LoadLibraryExW(interposer_path.c_str(), nullptr, LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR | LOAD_LIBRARY_SEARCH_SYSTEM32); if (!interposer) { dingosdk::logging::log(dingosdk::logging::Level::error, dingosdk::logging::Channel::graphics, "Cannot load the game's sl.interposer.dll (Windows error {}).", GetLastError()); return FALSE; } wchar_t interposer_loaded_path[32768]{}; const auto interposer_length = GetModuleFileNameW( interposer, interposer_loaded_path, 32768); std::error_code interposer_error; if (!interposer_length || interposer_length >= 32768 || !std::filesystem::equivalent(interposer_path, std::filesystem::path(std::wstring(interposer_loaded_path, interposer_length)), interposer_error) || interposer_error) { dingosdk::logging::write(dingosdk::logging::Level::error, dingosdk::logging::Channel::graphics, "Loaded graphics provider does not match the game's sibling sl.interposer.dll."); return FALSE; } dingosdk::logging::write(dingosdk::logging::Level::info, dingosdk::logging::Channel::graphics, "Game graphics provider loaded: sl.interposer.dll."); const dingosdk::overlay::CallbacksV3 callbacks{ nullptr, read_model, queue_load, queue_debug, queue_offline_feature, queue_console_command}; auto native_callbacks = callbacks; native_callbacks.read_model = read_native_menu_model; dingosdk::multiplayer::set_native_menu_callbacks(native_callbacks); dingosdk::overlay::set_multiplayer_queue(queue_multiplayer_command); dingosdk::overlay::set_chat_feed(dingosdk::multiplayer::chat); // A map a session needs: hosts say which Thunderstore package theirs is from, and a // guest without it is offered it on a card (Extension/Assets/map_download.h). dingosdk::multiplayer::set_map_package_lookup(dingosdk::map_download::package_of); dingosdk::overlay::set_map_download_feed([]() { const auto view = dingosdk::map_download::view(); using Stage = dingosdk::map_download::Stage; dingosdk::overlay::MapDownloadCard card; card.stage = view.stage == Stage::asking ? 1 : view.stage == Stage::downloading ? 2 : view.stage == Stage::installing ? 3 : view.stage == Stage::applying ? 4 : view.stage == Stage::joining ? 5 : 0; card.map = view.map; card.package = view.package; card.author = view.author; card.version = view.version; card.description = view.description; card.step = view.step; card.steps = view.steps; card.step_name = view.step_name; card.server = view.server; card.moved = view.moved; card.installed = view.installed; card.have = view.have; card.choice = view.choice; card.received = view.received; card.total = view.total; card.yes_bind = view.yes_bind; card.no_bind = view.no_bind; return card; }); dingosdk::overlay::set_map_download_answer(dingosdk::map_download::answer); dingosdk::overlay::set_hub_page_feed(dingosdk::multiplayer::native_menu_page); dingosdk::overlay::set_hub_callbacks(native_callbacks); dingosdk::overlay::set_ui_sound(dingosdk::multiplayer::queue_ui_sound); dingosdk::overlay::set_item_browser(dingosdk::item_browser::overlay_host()); dingosdk::overlay::set_game_text_feed(dingosdk::multiplayer::skate_debug_text); dingosdk::overlay::set_skate_hud_feed(dingosdk::multiplayer::skate_hud); dingosdk::overlay::set_nametag_feed(dingosdk::multiplayer::custom_nametags); // Engine functions the profiler's stack sampler names in its reports. static constexpr dingosdk::profiler::Label engine_labels[]{ {dingosdk::addr::profiler_labels::client_update, "Client game update (ReSkate tick hook)"}, {dingosdk::addr::profiler_labels::client_frame_job.rva, "Client frame job"}, {dingosdk::addr::profiler_labels::expression_vm, "Expression VM"}, {dingosdk::addr::profiler_labels::expression_vm_profiled, "Expression VM (profiled)"}, {dingosdk::addr::profiler_labels::menu_expression, "Menu expression"}, {dingosdk::addr::profiler_labels::job_run_until_done, "Job system: run jobs until done"}, {dingosdk::addr::profiler_labels::job_execute, "Job system: execute job"}, {dingosdk::addr::profiler_labels::job_idle_wait, "Job system: idle wait"}, {dingosdk::addr::profiler_labels::simulation_loop_thread, "GameSimulationLoop thread"}, {dingosdk::addr::profiler_labels::job_worker_loop, "Job system: worker loop"}, {dingosdk::addr::profiler_labels::job_pop, "Job system: look for work (spins when idle)"}, {dingosdk::addr::profiler_labels::job_queue_pop, "Job system: queue pop"}, {dingosdk::addr::profiler_labels::expression_shader_model_build, "Job: expressionShaderModelBuild"}, {dingosdk::addr::profiler_labels::render_bundle_job, "Job: renderBundleJob"}, {dingosdk::addr::profiler_labels::mesh_cull, "Job: meshCull"}, {dingosdk::addr::profiler_labels::render_dispatch_end, "Job: renderDispatchEnd"}, {dingosdk::addr::profiler_labels::input_dispatch, "Input dispatch"}, {dingosdk::addr::profiler_labels::ui_pointer_update, "UI pointer update (mouse hit-test)"}, {dingosdk::addr::profiler_labels::ui_view_pointer, "UI view pointer hit-test"}}; dingosdk::profiler::set_engine_labels(engine_labels); dingosdk::overlay::set_park_surface_queue(dingosdk::queue_local_park_surface); dingosdk::overlay::set_park_preview_queue(dingosdk::queue_local_park_preview); dingosdk::overlay::set_park_selection_queue(dingosdk::queue_local_park_selection); dingosdk::overlay::set_park_paste_queue(dingosdk::queue_local_park_paste); if (!DingoSDKOverlayStartV3(&callbacks)) { dingosdk::logging::write(dingosdk::logging::Level::error, dingosdk::logging::Channel::graphics, "Overlay startup failed."); return FALSE; } // Install the offline boot hooks before the passive observers and other // native hooks, while Skate's primary thread remains suspended. The // launcher always sets the global-offline variable; install the dependent // guard first in forwarding-only mode. Launches without it do not // install this hook. const bool global_offline_requested = exact_environment_one( L"RESKATE_DEBUG_TEST_GLOBAL_OFFLINE"); const bool progression_guard_prepared = global_offline_requested && dingosdk::prepare_progression_service_guard(r.base); record("{\"event\":\"progression_service_guard_prepared\",\"requested\":" + std::string(global_offline_requested ? "true" : "false") + ",\"prepared\":" + std::string(progression_guard_prepared ? "true" : "false") + "}"); const bool global_offline_hook = global_offline_requested && progression_guard_prepared && dingosdk::start_offline_boot(r.base); record("{\"event\":\"global_offline_experiment_initialized\",\"active\":" + std::string(global_offline_hook ? "true" : "false") + ",\"requested\":" + std::string(global_offline_requested ? "true" : "false") + ",\"progression_guard_prepared\":" + std::string(progression_guard_prepared ? "true" : "false") + "}"); const auto global_offline = dingosdk::offline_boot_observation(); record(global_offline.json); const bool progression_guard_armed = global_offline_hook && dingosdk::arm_progression_service_guard(r.base); record("{\"event\":\"progression_service_guard_initialized\",\"prepared\":" + std::string(progression_guard_prepared ? "true" : "false") + ",\"armed\":" + std::string(progression_guard_armed ? "true" : "false") + ",\"global_offline_prerequisite\":" + std::string(global_offline_hook ? "true" : "false") + "}"); const auto progression_guard = dingosdk::progression_service_guard_observation(); record(progression_guard.json); if (global_offline_requested && (!global_offline_hook || !progression_guard_armed)) { record("{\"event\":\"launcher_readiness\",\"ready\":false," "\"reason\":\"authored_offline_hooks\"}"); return FALSE; } const bool graphics_labels = dingosdk::initialize_graphics_labels(r.base, global_offline_hook && progression_guard_armed); record("{\"event\":\"graphics_labels_initialized\",\"active\":" + std::string(graphics_labels ? "true" : "false") + "}"); if (global_offline_hook && progression_guard_armed && !dingosdk::initialize_local_profile(r.base, true, dingosdk::profile::default_path())) { record("{\"event\":\"launcher_readiness\",\"ready\":false,\"reason\":\"local_profile\"}"); return FALSE; } if (global_offline_hook && progression_guard_armed) { dingosdk::set_local_location_travel_queue(&queue_location_travel); start_menu_entry(); } start_frame_timing(); (void)dingosdk::ui_pointer::install(r.base); (void)dingosdk::engine_tweaks::install(r.base); (void)dingosdk::replay_guard::install(r.base); (void)dingosdk::mesh_unload_guard::install(r.base); (void)dingosdk::shader_permutation_guard::install(r.base); (void)dingosdk::light_table_guard::install(r.base); (void)dingosdk::load_error_guard::install(r.base); (void)dingosdk::texture_handle_limit::install(r.base); (void)dingosdk::stack_check_report::install(r.base); (void)dingosdk::music_inject::install(r.base); (void)dingosdk::spotify_rows::install(r.base); dingosdk::spotify_device::start(); // (the game as a device in the player's Spotify app) dingosdk::spotify_web::start(); dingosdk::youtube_music::start(); // (the player's YouTube playlists, read before the music screen is built) dingosdk::spotify_dashboard::start(); // (the page in the browser that sets Spotify up) // (the player's playlists, fetched before the music screen is built) const bool fixed_stop_provider = (global_offline_hook && progression_guard_armed) && dingosdk::prepare_fixed_stop_entitlement_provider(r.base); record("{\"event\":\"fixed_stop_entitlement_provider_initialized\",\"prepared\":" + std::string(fixed_stop_provider ? "true" : "false") + ",\"requested\":" + std::string(global_offline_requested ? "true" : "false") + "}"); const auto fixed_stop_provider_observation = dingosdk::fixed_stop_entitlement_provider_observation(); record(fixed_stop_provider_observation.json); r.last_fixed_stop_entitlement_provider_observation = fixed_stop_provider_observation.json; const bool entitlement_trace = (global_offline_hook && progression_guard_armed) && dingosdk::prepare_entitlement_request_trace(r.base); record("{\"event\":\"entitlement_request_trace_initialized\",\"active\":" + std::string(entitlement_trace ? "true" : "false") + ",\"requested\":" + std::string(global_offline_requested ? "true" : "false") + "}"); const auto entitlement_trace_observation = dingosdk::entitlement_request_trace_observation(); record(entitlement_trace_observation.json); r.fixed_stop_entitlement_route_ready = fixed_stop_provider && entitlement_trace; dingosdk::set_fixed_stop_entitlement_ownership(dingosdk::local_profile_owns_entitlement); dingosdk::set_fixed_stop_entitlement_provider_enabled( r.fixed_stop_entitlement_route_ready && dingosdk::local_profile_access().bus_stops); record("{\"event\":\"fixed_stop_entitlement_route_initialized\",\"ready\":" + std::string(r.fixed_stop_entitlement_route_ready ? "true" : "false") + ",\"provider_prepared\":" + std::string(fixed_stop_provider ? "true" : "false") + ",\"trace_prepared\":" + std::string(entitlement_trace ? "true" : "false") + "}"); const bool neighborhood_unlock_provider = (global_offline_hook && progression_guard_armed) && dingosdk::prepare_neighborhood_unlock_override(r.base); if (neighborhood_unlock_provider) dingosdk::set_expression_binder_observer(&observe_player_card_expression); if (neighborhood_unlock_provider) (void)dingosdk::set_neighborhood_unlock_override_enabled(dingosdk::local_profile_access().neighborhoods); record("{\"event\":\"neighborhood_unlock_provider_initialized\",\"prepared\":" + std::string(neighborhood_unlock_provider ? "true" : "false") + ",\"requested\":" + std::string(global_offline_requested ? "true" : "false") + "}"); const auto neighborhood_unlock_provider_observation = dingosdk::neighborhood_unlock_override_observation(); record(neighborhood_unlock_provider_observation.json); r.last_neighborhood_unlock_override_observation = neighborhood_unlock_provider_observation.json; const bool named_settings = dingosdk::initialize_named_settings(r.base); record("{\"event\":\"named_settings_initialized\",\"ready\":" + std::string(named_settings ? "true" : "false") + "}"); const bool gameplay_settings = dingosdk::initialize_gameplay_settings_override( r.base, global_offline_hook && progression_guard_armed); const bool skater_slots = dingosdk::initialize_skater_slot_override( r.base, global_offline_hook && progression_guard_armed); const bool main_missions = (global_offline_hook && progression_guard_armed) && dingosdk::prepare_main_mission_override(r.base); const auto gameplay_settings_observation = dingosdk::gameplay_settings_override_observation(); const auto skater_slot_observation = dingosdk::skater_slot_override_observation(); const auto main_mission_observation = dingosdk::main_mission_override_observation(); record(gameplay_settings_observation.json); record(skater_slot_observation.json); record(main_mission_observation.json); r.last_gameplay_settings_override_observation = gameplay_settings_observation.json; r.last_skater_slot_override_observation = skater_slot_observation.json; r.last_main_mission_override_observation = main_mission_observation.json; { std::lock_guard lock(r.mutex); r.offline_model = gameplay_settings_observation.model; merge_skater_slot_observation(r.offline_model, skater_slot_observation); merge_main_mission_observation(r.offline_model, main_mission_observation); merge_progression_provider_observations(r.offline_model, fixed_stop_provider_observation, neighborhood_unlock_provider_observation, r.fixed_stop_entitlement_route_ready); ++r.offline_revision; } record("{\"event\":\"gameplay_settings_override_initialized\",\"active\":" + std::string(gameplay_settings ? "true" : "false") + ",\"authored_offline_prerequisite\":" + std::string(global_offline_hook && progression_guard_armed ? "true" : "false") + "}"); record("{\"event\":\"skater_slot_override_initialized\",\"active\":" + std::string(skater_slots ? "true" : "false") + ",\"authored_offline_prerequisite\":" + std::string(global_offline_hook && progression_guard_armed ? "true" : "false") + "}"); record("{\"event\":\"main_mission_override_initialized\",\"prepared\":" + std::string(main_missions ? "true" : "false") + ",\"authored_offline_prerequisite\":" + std::string(global_offline_hook && progression_guard_armed ? "true" : "false") + "}"); const bool skater_hooks = dingosdk::start_skater_observer(r.base); record("{\"event\":\"skater_hooks_initialized\",\"active\":" + std::string(skater_hooks ? "true" : "false") + "}"); const bool camera_hook = dingosdk::start_camera_observer(r.base); record("{\"event\":\"camera_observer_initialized\",\"active\":" + std::string(camera_hook ? "true" : "false") + "}"); (void)dingosdk::start_no_bail(r.base); const bool meat = dingosdk::hall_of_meat::start(r.base); record("{\"event\":\"hall_of_meat_initialized\",\"active\":" + std::string(meat ? "true" : "false") + "}"); const bool rash = dingosdk::road_rash::start(r.base); record("{\"event\":\"road_rash_initialized\",\"active\":" + std::string(rash ? "true" : "false") + "}"); const bool board_break = dingosdk::board_break::start(r.base); record("{\"event\":\"board_break_initialized\",\"active\":" + std::string(board_break ? "true" : "false") + "}"); const bool grind_control = dingosdk::grind_exit_control::start(r.base); record("{\"event\":\"grind_exit_control_initialized\",\"active\":" + std::string(grind_control ? "true" : "false") + "}"); const bool noclip_velocity = dingosdk::start_client_noclip_velocity(r.base); record("{\"event\":\"noclip_velocity_initialized\",\"active\":" + std::string(noclip_velocity ? "true" : "false") + "}"); const bool loading_screens = dingosdk::loading_screen::start(r.base); record("{\"event\":\"map_loading_screens_initialized\",\"active\":" + std::string(loading_screens ? "true" : "false") + "}"); const bool preset_guard = dingosdk::preset_lookup_guard::start(r.base); record("{\"event\":\"preset_lookup_guard_initialized\",\"active\":" + std::string(preset_guard ? "true" : "false") + "}"); const bool replay_export = dingosdk::replay_export::start(r.base); record("{\"event\":\"replay_export_initialized\",\"active\":" + std::string(replay_export ? "true" : "false") + "}"); void* original{}; auto* address = reinterpret_cast(r.base + rt::client_tick); auto hook_status = dingosdk::hook_prepare(address, reinterpret_cast(&tick), &original); if (hook_status == dingosdk::HookOk) { r.original_tick = reinterpret_cast(original); hook_status = dingosdk::hook_enable(address); if (hook_status != dingosdk::HookOk) dingosdk::hook_remove(address); } if (hook_status != dingosdk::HookOk) { // The renderer is already installed. Keep it available for diagnostics // and report successful optional loading without claiming native control. { std::lock_guard lock(r.mutex); r.model.state = "Native controller unavailable"; r.model.load_block_reason = "The engine update hook could not be initialized."; r.offline_model.available = false; r.offline_model.status = "Gameplay settings require the native game update hook."; ++r.model_revision; ++r.offline_revision; r.initialized = !global_offline_requested; } record("{\"event\":\"native_hook_failed\",\"status\":" + std::to_string(hook_status) + "}"); if (global_offline_requested) { record("{\"event\":\"launcher_readiness\",\"ready\":false," "\"reason\":\"native_tick_hook\"}"); return FALSE; } startup_window.hand_over(); return TRUE; } { std::lock_guard lock(r.mutex); r.native_tick_ready = true; } r.native_loading_logging = dingosdk::start_level_loading_logging(r.base, [](std::uintptr_t base, unsigned next) noexcept { dingosdk::local_profile_before_level_transition(next); dingosdk::multiplayer::native_menu_before_level_transition(base, next); dingosdk::multiplayer::throwdown_lab_before_level_transition(next); }); if (!r.native_loading_logging) dingosdk::logging::write(dingosdk::logging::Level::warning, dingosdk::logging::Channel::ui, "Native ReSkate menu disabled: shutdown cleanup hook is unavailable."); r.initialized = true; if (global_offline_requested) record("{\"event\":\"launcher_readiness\",\"ready\":true}"); record("{\"event\":\"debug_initialized\",\"overlay\":true,\"native_load\":\"guarded_local_only\"}"); activity_line(dingosdk::ConsoleSource::runtime, "Offline runtime initialized. Waiting for the game."); startup_window.hand_over(); return TRUE; } catch (const std::exception& error) { dingosdk::logging::log(dingosdk::logging::Level::critical, dingosdk::logging::Channel::runtime, "Runtime initialization failed: {}", error.what()); return FALSE; } catch (...) { dingosdk::logging::write(dingosdk::logging::Level::critical, dingosdk::logging::Channel::runtime, "Runtime initialization failed with an unknown exception."); return FALSE; } } BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID) { if (reason == DLL_PROCESS_ATTACH) DisableThreadLibraryCalls(instance); return TRUE; }