102 Patches: Detours to the Rescue
C reference for DttR maintainers and modders.
Loading...
Searching...
No Matches
entrypoint.c
Go to the documentation of this file.
1#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4#include <windows.h>
5
6#include "dttr_crashdump.h"
9#include <dttr_config.h>
10#include <dttr_log.h>
11#include <dttr_path.h>
12#include <sds.h>
13
14#include <SDL3/SDL.h>
15
16#include "audio/hooks_private.h"
17#include "dttr_errors.h"
18#include "dttr_hooks.h"
19#include "game/hooks_private.h"
25#include "sidecar_private.h"
26#include <dttr_pcdogs.h>
27#include <dttr_runtime.h>
28#include <xxhash.h>
29
30#ifdef DTTR_MODS_ENABLED
32#include "mods/mods_private.h"
33#endif
34
36char dttr_loader_dir[MAX_PATH];
38
39static HMODULE pc_dogs_module;
41
42static bool dttr_sidecar_store_sds(char *dst, size_t dst_size, sds src) {
43 if (!src) {
44 return false;
45 }
46
47 if (dst_size > 0) {
48 size_t copy_len = sdslen(src);
49 if (copy_len >= dst_size) {
50 copy_len = dst_size - 1u;
51 }
52 memcpy(dst, src, copy_len);
53 dst[copy_len] = '\0';
54 }
55
56 sdsfree(src);
57 return true;
58}
59
63) {
64 if (!request || !report
66 || report->struct_size != sizeof(DTTR_Mods_ExceptionReport)
67 || request->exception_record.ExceptionCode == 0) {
68 return false;
69 }
70
71 memset(report, 0, sizeof(*report));
72 report->struct_size = sizeof(*report);
73
74 EXCEPTION_RECORD exception_record = request->exception_record;
75 CONTEXT context = request->context;
76 EXCEPTION_POINTERS exception_pointers = {
77 .ExceptionRecord = &exception_record,
78 .ContextRecord = &context,
79 };
80 const DWORD current_thread_id = GetCurrentThreadId();
81 const DWORD thread_id = request->thread_id ? request->thread_id : current_thread_id;
82
83 sds dump_path = DTTR_CrashDump_Write(
84 GetCurrentProcess(),
85 GetCurrentProcessId(),
86 thread_id,
87 &exception_pointers
88 );
90 report->dump_path,
91 sizeof(report->dump_path),
92 dump_path
93 );
94 if (!report->dump_written) {
95 report->win32_error = GetLastError();
96 }
97
98 HANDLE thread = GetCurrentThread();
99 bool close_thread = false;
100 if (thread_id != current_thread_id) {
101 thread = OpenThread(
102 THREAD_GET_CONTEXT | THREAD_QUERY_INFORMATION,
103 FALSE,
104 thread_id
105 );
106 close_thread = thread != NULL;
107 if (!thread && report->win32_error == ERROR_SUCCESS) {
108 report->win32_error = GetLastError();
109 }
110 }
111
112 sds stack_trace = DTTR_CrashDump_FormatStackTrace(
113 GetCurrentProcess(),
114 thread,
115 &context
116 );
117 if (close_thread) {
118 CloseHandle(thread);
119 }
120
122 report->stack_trace,
123 sizeof(report->stack_trace),
124 stack_trace
125 );
126
127 return report->dump_written || report->stack_trace_written;
128}
129
130static const DTTR_Mods_API MOD_API = {
131 .log = DTTR_Log,
132 .log_is_enabled = DTTR_Log_IsEnabled,
133 .log_unchecked = DTTR_Log_Unchecked,
134 .struct_size = sizeof(DTTR_Mods_API),
135 .abi_version = DTTR_SDK_ABI_VERSION,
136 .write_exception_report = dttr_sidecar_write_exception_report,
137};
138
141 .hook_function = DTTR_Core_HookAttachFunction,
142 .hook_pointer = DTTR_Core_HookAttachPointer,
143 .patch_bytes = DTTR_Core_HookPatchBytes,
144 .unhook = DTTR_Core_HookDetach,
145 .hook_is_active = DTTR_Core_HookIsActive,
146 .unhook_checked = DTTR_Core_HookDetachChecked,
147 .struct_size = sizeof(DTTR_Core_API),
148 .abi_version = DTTR_SDK_ABI_VERSION,
149};
150
151// Exposes the single sidecar context shared by hooks, mods, and runtime calls.
155
157 return &sidecar_ctx.runtime;
158}
159
160// Captures module handles and APIs before callbacks expose sidecar state.
161static void init_sidecar_context(HMODULE game_module, HMODULE sidecar_module) {
163 .abi_version = DTTR_SDK_ABI_VERSION,
164 .runtime =
166 .game_module = game_module,
167 .api = &RUNTIME_API,
168 .struct_size = sizeof(DTTR_Core_Context),
169 .abi_version = DTTR_SDK_ABI_VERSION,
170 },
171 .sidecar_module = sidecar_module,
172 .window = NULL,
173 .loader_dir = dttr_loader_dir,
174 .exe_hash = dttr_exe_hash,
175 .config = &dttr_config,
176 .api = &MOD_API,
177 .struct_size = sizeof(DTTR_Mods_Context),
178 };
179}
180
181// Initializes subsystems that own required hooks. The order mirrors cleanup_runtime().
183 bool ok = true;
184 ok = dttr_game_hooks_init(ctx) && ok;
185
187 ok = dttr_inputs_hooks_init(ctx) && ok;
188 ok = dttr_graphics_hooks_init(ctx) && ok;
189 ok = dttr_audio_init(ctx) && ok;
190
192 ok = dttr_movies_hooks_init(ctx) && ok;
193
194 return ok;
195}
196
197// Falls back to a stable unknown hash when the executable cannot be read during startup.
198static void set_default_exe_hash() {
199 memcpy(dttr_exe_hash, "0000000000000000", sizeof(dttr_exe_hash));
200}
201
202// Hashes the launched game executable for config, logs, and mods.
203static void compute_exe_hash() {
204 char exe_path[MAX_PATH];
205 GetModuleFileNameA(pc_dogs_module, exe_path, sizeof(exe_path));
206
207 HANDLE file = CreateFileA(
208 exe_path,
209 GENERIC_READ,
210 FILE_SHARE_READ,
211 NULL,
212 OPEN_EXISTING,
213 0,
214 NULL
215 );
216 void *buf = NULL;
217 if (file == INVALID_HANDLE_VALUE) {
218 DTTR_LOG_ERROR("Failed to open exe for hashing: %s", exe_path);
219 goto fail;
220 }
221
222 DWORD file_size = GetFileSize(file, NULL);
223 if (file_size == INVALID_FILE_SIZE && GetLastError() != NO_ERROR) {
224 DTTR_LOG_ERROR("Failed to get exe size for hashing: %s", exe_path);
225 goto fail;
226 }
227
228 buf = malloc(file_size);
229 if (file_size != 0 && !buf) {
230 DTTR_LOG_ERROR("Failed to allocate %lu bytes for exe hashing", file_size);
231 goto fail;
232 }
233
234 DWORD bytes_read = 0;
235 if (!ReadFile(file, buf, file_size, &bytes_read, NULL)) {
236 DTTR_LOG_ERROR("Failed to read exe for hashing: %s", exe_path);
237 goto fail;
238 }
239
240 CloseHandle(file);
241 file = INVALID_HANDLE_VALUE;
242
243 XXH64_hash_t hash = XXH3_64bits(buf, bytes_read);
244 free(buf);
245 buf = NULL;
246
247 snprintf(dttr_exe_hash, sizeof(dttr_exe_hash), "%016llx", (unsigned long long)hash);
248 return;
249
250fail:
251 if (file != INVALID_HANDLE_VALUE) {
252 CloseHandle(file);
253 }
254
255 free(buf);
257}
258
259// Resolves the sidecar directory used as the base for config files and mod loading.
260static sds get_loader_dir() {
262 if (!loader_dir) {
263 return NULL;
264 }
265
266 const size_t len = sdslen(loader_dir);
267 if (len >= 8 && _stricmp(loader_dir + len - 8, "modules\\") == 0) {
268 sdsrange(loader_dir, 0, (ssize_t)len - 9);
269 }
270
271 return loader_dir;
272}
273
274// Builds the sidecar config path beside the loader.
275static sds get_config_path() {
276 const char *config_env = getenv("DTTR_CONFIG_PATH");
277 return sdsnew(config_env ? config_env : DTTR_CONFIG_FILENAME);
278}
279
280// Applies the runtime fullscreen toggle to the active graphics window.
281static void toggle_fullscreen() {
282 SDL_Window *const window = dttr_backend.window;
283 const bool is_fullscreen = (SDL_GetWindowFlags(window) & SDL_WINDOW_FULLSCREEN) != 0;
284 if (!SDL_SetWindowFullscreen(window, !is_fullscreen)) {
285 DTTR_LOG_WARN("SDL_SetWindowFullscreen failed: %s", SDL_GetError());
286 }
287}
288
289#ifdef DTTR_MODS_ENABLED
290// Sends post-dispatch SDL events to mods after the sidecar and game handlers run.
291static void after_sdl_event(const SDL_Event *event, bool consumed) {
292 dttr_mods_after_event(event, consumed);
293}
294#else
295#define after_sdl_event(event, consumed) \
296 do { \
297 } while (0)
298#endif
299
300static bool require_pcdogs_call(const char *name, DTTR_Result result) {
301 if (!DTTR_ResultOK(result)) {
303 "Required PCDOGS operation failed: %s (%s)",
304 name,
306 );
307 return false;
308 }
309
310 return true;
311}
312
313#define REQUIRE_PCDOGS_CALL(expr_) require_pcdogs_call(#expr_, (expr_))
314
315// Routes SDL events through sidecar handlers before game input observes them.
317#ifdef DTTR_MODS_ENABLED
319 after_sdl_event(event, true);
320 return;
321 }
322
324 after_sdl_event(event, true);
325 return;
326 }
327
329 after_sdl_event(event, true);
330 return;
331 }
332
333#endif
334
336 after_sdl_event(event, true);
337 return;
338 }
339
340 switch (event->type) {
341 case SDL_EVENT_QUIT:
344 );
345 after_sdl_event(event, true);
346 return;
347
348 case SDL_EVENT_GAMEPAD_ADDED:
349 case SDL_EVENT_GAMEPAD_REMOVED:
351 after_sdl_event(event, true);
352 return;
353
354 case SDL_EVENT_AUDIO_DEVICE_ADDED:
355 case SDL_EVENT_AUDIO_DEVICE_REMOVED:
357 after_sdl_event(event, true);
358 return;
359
360 case SDL_EVENT_KEY_DOWN:
361 if (event->key.scancode == SDL_SCANCODE_F11) {
363 after_sdl_event(event, true);
364 return;
365 }
366
367 break;
368
369 case SDL_EVENT_WINDOW_RESIZED:
370 case SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED:
371 dttr_graphics_handle_window_resize(event->window.data1, event->window.data2);
372 after_sdl_event(event, true);
373 return;
374
375 default:
376 break;
377 }
378
379 after_sdl_event(event, false);
380}
381
382// Drains SDL events through the sidecar event bridge.
385
386 while (SDL_PollEvent(&event)) {
388 }
389}
390
391// Releases modding runtime hooks and mod state before graphics and audio shutdown.
413
414// Runs required PCDOGS startup calls after the game window exists.
427
428// Moves the modding runtime into its started state after initialization succeeds.
429static bool start_pcdogs_runtime(const DTTR_Core_Context *ctx, HWND hwnd) {
430 int32_t ret = 0;
431 int32_t config_ret = 0;
432 return REQUIRE_PCDOGS_CALL(DTTR_PCDOGS_F_Display_SetMode->Call(ctx, hwnd, &ret))
436 );
437}
438
444
445// Runs per-frame sidecar systems before yielding back to the original game loop.
446static bool tick_main_loop() {
449 return true;
450 }
451
452 SDL_DelayNS(1);
453
454 int32_t rendering_enabled = 0;
457 )) {
458 return false;
459 }
460
461 if (rendering_enabled) {
462#ifdef DTTR_MODS_ENABLED
464 uint8_t frame_status = 0;
467 &frame_status
468 ))) {
469 return false;
470 }
471
473 } else {
477 }
478
479#else
480 uint8_t frame_status = 0;
483 &frame_status
484 ))) {
485 return false;
486 }
487#endif
488 }
489
490#ifdef DTTR_MODS_ENABLED
492#endif
493 return true;
494}
495
496// Plays startup movies through the normal sidecar tick loop.
498 if (dttr_config.skip_intro_movies) {
500 }
501
502 const char *const prefix = DTTR_PCDOGS_D_Video_PlayMovieIntro_PathPrefix->Ptr();
503 char **const names = (char **)DTTR_PCDOGS_D_Video_PlayMovieIntro_FileNames->Ptr();
504 if (!prefix || !names) {
505 DTTR_LOG_WARN("Startup movie metadata unavailable; skipping intro movies");
507 }
508
509 for (int i = 0; i < 4; i++) {
510 if (!names[i]) {
511 break;
512 }
513
514 sds path = sdsnew(prefix);
515 if (!path || !DTTR_Path_AppendSegment(&path, names[i], '\\')) {
516 sdsfree(path);
517 break;
518 }
519
520 dttr_movies_start(path);
521 sdsfree(path);
522
523 while (dttr_movies_is_playing()) {
525 if (!tick_main_loop()) {
528 }
529 }
530
532
533 if (ret == DTTR_MOVIE_QUIT) {
536 )) {
538 }
539
541 }
542
543 if (ret != DTTR_MOVIE_ENDED) {
544 break;
545 }
546 }
547
549}
550
551// Hooks Window_RunWinMain so sidecar initialization can wrap game startup and shutdown.
553 // DllMain installs this bootstrap hook before init_sidecar_context() creates a
554 // DTTR_Mods_Context.
555 const uintptr_t site = DTTR_Core_HookSigscan(
557 "\x83\xEC\x40\x53\x8B\x5C\x24",
558 "xxxxxxx"
559 );
560 if (!site) {
561 return;
562 }
563
564 dttr_hook_win_main_site = site;
565 const int32_t rel = (int32_t)((uintptr_t)DTTR_Hook_WinMainCallback - (site + 5));
566
567 uint8_t jmp[5] = {0xE9};
568 memcpy(jmp + 1, &rel, 4);
569 dttr_hook_win_main_handle = DTTR_Core_HookPatchBytes(site, jmp, sizeof(jmp));
570}
571
572// Wraps the game Window_RunWinMain so the sidecar can initialize hooks before the
573// original loop runs.
575 HINSTANCE hInstance,
576 HINSTANCE hPrevInstance,
577 LPSTR lpCmdLine,
578 int32_t nCmdShow
579) {
580 int exit_code = 0;
581 bool should_exit_process = false;
582 FILE *log_file = NULL;
583 sds loader_dir = get_loader_dir();
584 sds config_path = NULL;
585 sds log_path = NULL;
586
587 if (!loader_dir
588 || !DTTR_Path_CopySds(dttr_loader_dir, sizeof(dttr_loader_dir), loader_dir)) {
589 goto cleanup;
590 }
591
593 OutputDebugStringA("DTTR_SIDECAR_ENTRYPOINT");
594
596
597 config_path = get_config_path();
598 if (!config_path || !DTTR_Config_Load(config_path)) {
600 "Failed to load configuration file at %s",
601 config_path ? config_path : DTTR_CONFIG_FILENAME
602 );
603 }
604
606 if (!log_path) {
607 goto cleanup;
608 }
609
610 log_file = fopen(log_path, "a+");
611 if (!log_file) {
612 DTTR_FATAL("Could not open log file at %s", log_path);
613 }
614
615 DTTR_LOG_INFO("Starting DttR sidecar");
616 DTTR_LOG_INFO("Loaded configuration file at %s", config_path);
617
618 const int level = dttr_config.log_level;
619 DTTR_Log_SetLevel(level);
620 DTTR_Log_AddFP(log_file, level);
621 DTTR_LOG_INFO("Log level set to %s", log_level_string(level));
623
626
627 HWND hwnd = dttr_graphics_init();
628
629 if (!hwnd) {
630 DTTR_LOG_ERROR("Failed to initialize - aborting");
631 exit_code = 1;
632 goto cleanup;
633 }
634
635 DTTR_LOG_INFO("Resolving sidecar SDK game symbols...");
636 DTTR_PCDOGS_ResolveAll(&ctx->runtime);
638
640 DTTR_LOG_ERROR("Failed to install required sidecar hooks - aborting");
641 exit_code = 1;
642 goto cleanup_sidecar_runtime;
643 }
644
645#ifdef DTTR_MODS_ENABLED
649 dttr_backend.backend_type
650 );
655 const DTTR_Mods_InputContext input_ctx = {
656 .overlay_visible = false,
657 .game_input_enabled = true,
658 };
659
662#endif
663
666 )
668 exit_code = 1;
669 goto cleanup_sidecar_runtime;
670 }
671
672 if (!initialize_pcdogs_runtime(&ctx->runtime, hwnd)) {
673 exit_code = 1;
674 goto cleanup_sidecar_runtime;
675 }
676
678 if (startup_movies == DTTR_STARTUP_MOVIES_FAILED) {
679 exit_code = 1;
680 goto cleanup_sidecar_runtime;
681 }
682
683 if (!start_pcdogs_runtime(&ctx->runtime, hwnd)) {
684 exit_code = 1;
685 goto cleanup_sidecar_runtime;
686 }
687
688 void *audio_driver = NULL;
691 )) {
692 exit_code = 1;
693 goto cleanup_sidecar_runtime;
694 }
695
696 if (audio_driver == NULL) {
697 DTTR_LOG_WARN("No audio device available - audio disabled");
698 }
699
700 if (!dttr_inputs_late_init()) {
701 exit_code = 1;
702 goto cleanup_sidecar_runtime;
703 }
704
705#ifdef DTTR_MODS_ENABLED
707#endif
708 if ((startup_movies != DTTR_STARTUP_MOVIES_QUIT
711 ))
715 )) {
716 exit_code = 1;
717 goto cleanup_sidecar_runtime;
718 }
719
720 DTTR_LOG_INFO("Ready!");
721
722 for (;;) {
723 int32_t should_quit = 0;
726 )) {
727 exit_code = 1;
728 break;
729 }
730
731 if (should_quit != 0) {
732 break;
733 }
734
736 if (!tick_main_loop()) {
737 exit_code = 1;
738 break;
739 }
740 }
741
742cleanup_sidecar_runtime:
743 DTTR_LOG_INFO("Cleaning up hooks");
745
746 DTTR_LOG_INFO("Exiting DttR sidecar");
747 should_exit_process = true;
748
749cleanup:
750 sdsfree(log_path);
751 sdsfree(config_path);
752 sdsfree(loader_dir);
753
754 if (log_file) {
755 fclose(log_file);
756 }
757
758 if (should_exit_process) {
759 ExitProcess((UINT)exit_code);
760 }
761
762 return exit_code;
763}
764
765// Captures process attach so the sidecar can bootstrap runtime state.
766BOOL APIENTRY DllMain(HMODULE module, const DWORD reason_for_call, LPVOID reserved) {
767 if (reason_for_call == DLL_PROCESS_ATTACH) {
768 dttr_sidecar_module = module;
769
770 pc_dogs_module = DTTR_UNWRAP_WINAPI_EXISTS(GetModuleHandleA("pcdogs.exe"));
771
773 }
774
775 return TRUE;
776}
bool dttr_audio_init(const DTTR_Mods_Context *ctx)
Definition hooks.c:125
void dttr_audio_handle_device_event(const SDL_Event *event)
Definition hooks.c:111
void dttr_audio_cleanup(const DTTR_Mods_Context *)
Definition hooks.c:162
static void cleanup(DTTR_BackendState *state)
DTTR_Graphics_COM_Direct3DDevice7 DWORD block DTTR_Graphics_COM_Direct3DDevice7 DWORD block DTTR_Graphics_COM_Direct3DDevice7 void void void void DWORD f BOOL
void void * ctx
DTTR_Graphics_COM_Direct3DDevice7 DWORD block DTTR_Graphics_COM_Direct3DDevice7 DWORD block DTTR_Graphics_COM_Direct3DDevice7 void void void void DWORD f FALSE
DTTR_Graphics_COM_Direct3DDevice7 DWORD block DTTR_Graphics_COM_Direct3DDevice7 DWORD block DTTR_Graphics_COM_Direct3DDevice7 void * dst
const uint8_t * src
void DWORD DWORD * free
void void DWORD HANDLE event
DTTR_Graphics_COM_DirectDrawSurface7 DWORD flags void NULL
void dttr_pcdogs_crash_symbols_clear()
Definition crash.c:126
void dttr_pcdogs_crash_symbols_register(const DTTR_Core_Context *runtime)
Definition crash.c:117
#define DTTR_CONFIG_FILENAME
DTTR_Config dttr_config
Definition defaults.c:53
bool DTTR_Config_Load(const char *filename)
Loads config values from a strict JSON file into the global config object.
Definition io.c:259
sds DTTR_CrashDump_Write(HANDLE process, DWORD pid, DWORD tid, EXCEPTION_POINTERS *exception_info)
Definition crashdump.c:428
void DTTR_CrashDump_Init(const char *dump_dir)
Definition crashdump.c:636
sds DTTR_CrashDump_FormatStackTrace(HANDLE process, HANDLE thread, const CONTEXT *context)
Formats a stack trace from a thread context. Caller frees the returned sds.
Definition crashdump.c:496
#define DTTR_UNWRAP_WINAPI_EXISTS(result)
Definition dttr_errors.h:79
#define DTTR_FATAL(error_message,...)
Definition dttr_errors.h:30
int32_t _stdcall DTTR_Hook_WinMainCallback(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int32_t nCmdShow)
Callback target for the patched game Window_RunWinMain routine.
Definition entrypoint.c:574
void DTTR_Log(int level, const char *file, int line, const char *fmt,...)
Definition log.c:125
bool DTTR_Log_IsEnabled(int level)
Definition log.c:79
void DTTR_Log_SetLevel(int level)
Definition log.c:143
#define DTTR_LOG_WARN(...)
Definition dttr_log.h:30
void DTTR_Log_Unchecked(int level, const char *file, int line, const char *fmt,...)
Definition log.c:136
#define DTTR_LOG_INFO(...)
Definition dttr_log.h:29
int DTTR_Log_AddFP(FILE *fp, int level)
Definition log.c:161
#define DTTR_LOG_ERROR(...)
Definition dttr_log.h:31
union SDL_Event SDL_Event
Definition dttr_mods.h:20
struct SDL_Window SDL_Window
Definition dttr_mods.h:19
bool DTTR_Path_CopySds(char *out, size_t out_size, sds value)
Definition path.c:72
sds DTTR_Path_ResolveRelativeTo(const char *base_dir, const char *path)
Definition path.c:228
sds DTTR_Path_ModuleDir(void *module)
Definition path.c:201
bool DTTR_Path_AppendSegment(sds *path, const char *segment, char separator)
Definition path.c:276
DTTR_PCDOGS_API const struct dttr_pcdogs_function_accessor_PKG_InitializeResourceGameEngine *const DTTR_PCDOGS_F_PKG_InitializeResourceGameEngine
Accessor object for PKG_InitializeResourceGameEngine.
DTTR_PCDOGS_API const struct dttr_pcdogs_function_accessor_PKG_InitializeSystem *const DTTR_PCDOGS_F_PKG_InitializeSystem
Accessor object for PKG_InitializeSystem.
DTTR_PCDOGS_API const struct dttr_pcdogs_function_accessor_Graphics_RenderFrame *const DTTR_PCDOGS_F_Graphics_RenderFrame
Accessor object for Graphics_RenderFrame.
DTTR_PCDOGS_API const struct DTTR_PCDOGS_D_Video_PlayMovieIntro_PathPrefix_type *const DTTR_PCDOGS_D_Video_PlayMovieIntro_PathPrefix
DTTR_PCDOGS_API const struct dttr_pcdogs_function_accessor_Config_LoadAlternateFromINI *const DTTR_PCDOGS_F_Config_LoadAlternateFromINI
Accessor object for Config_LoadAlternateFromINI.
DTTR_PCDOGS_API const struct DTTR_PCDOGS_D_Video_PlayMovieIntro_FileNames_type *const DTTR_PCDOGS_D_Video_PlayMovieIntro_FileNames
DTTR_PCDOGS_API const struct dttr_pcdogs_function_accessor_PKG_FindAndOpenFile *const DTTR_PCDOGS_F_PKG_FindAndOpenFile
Accessor object for PKG_FindAndOpenFile.
DTTR_PCDOGS_API const struct DTTR_PCDOGS_D_Window_ProcessGameProc_Initialized_type *const DTTR_PCDOGS_D_Window_ProcessGameProc_Initialized
DTTR_PCDOGS_API bool DTTR_PCDOGS_ResolveAll(const DTTR_Core_Context *ctx)
DTTR_PCDOGS_API const struct dttr_pcdogs_function_accessor_Input_ResetState *const DTTR_PCDOGS_F_Input_ResetState
Accessor object for Input_ResetState.
DTTR_PCDOGS_API const struct DTTR_PCDOGS_D_Window_RunWinMain_SecondaryWindowHandle_type *const DTTR_PCDOGS_D_Window_RunWinMain_SecondaryWindowHandle
DTTR_PCDOGS_API const struct dttr_pcdogs_function_accessor_D3D_InitializeGraphicsSubsystem *const DTTR_PCDOGS_F_D3D_InitializeGraphicsSubsystem
Accessor object for D3D_InitializeGraphicsSubsystem.
DTTR_PCDOGS_API const struct DTTR_PCDOGS_D_Window_RunWinMain_RenderingEnabled_type *const DTTR_PCDOGS_D_Window_RunWinMain_RenderingEnabled
DTTR_PCDOGS_API const struct dttr_pcdogs_function_accessor_Display_SetMode *const DTTR_PCDOGS_F_Display_SetMode
Accessor object for Display_SetMode.
DTTR_PCDOGS_API const struct DTTR_PCDOGS_D_Audio_InitializeSystem_DigitalDriver_type *const DTTR_PCDOGS_D_Audio_InitializeSystem_DigitalDriver
DTTR_PCDOGS_API const struct DTTR_PCDOGS_D_Window_MainHandle_type *const DTTR_PCDOGS_D_Window_MainHandle
DTTR_PCDOGS_API const struct DTTR_PCDOGS_D_Input_ProcessWindowMessages_ShouldQuit_type *const DTTR_PCDOGS_D_Input_ProcessWindowMessages_ShouldQuit
bool DTTR_ResultOK(DTTR_Result result)
Definition core.c:78
DTTR_Core_Hook * DTTR_Core_HookAttachPointer(uintptr_t addr, void *new_value, void **out_original)
bool DTTR_Core_HookIsActive(DTTR_Core_Hook *hook)
DTTR_Core_Hook * DTTR_Core_HookAttachFunction(uintptr_t addr, int prologue_size, void *handler, void **out_original)
DTTR_Core_Hook * DTTR_Core_HookPatchBytes(uintptr_t addr, const uint8_t *bytes, size_t size)
void DTTR_Core_HookCleanupAll()
Detach all remaining hooks and free the sigscan cache.
uintptr_t DTTR_Core_HookCachedSigscan(HMODULE mod, const char *sig, const char *mask)
void DTTR_Core_HookDetach(DTTR_Core_Hook *hook)
uintptr_t DTTR_Core_HookSigscan(HMODULE mod, const char *sig, const char *mask)
bool DTTR_Core_HookDetachChecked(DTTR_Core_Hook *hook)
#define DTTR_SDK_ABI_VERSION
const DTTR_Mods_Context * dttr_sidecar_context()
Definition entrypoint.c:152
static HMODULE pc_dogs_module
Definition entrypoint.c:39
static DTTR_Mods_Context sidecar_ctx
Definition entrypoint.c:40
static bool initialize_pcdogs_runtime(const DTTR_Core_Context *ctx, HWND hwnd)
Definition entrypoint.c:415
HINSTANCE dttr_sidecar_module
Definition entrypoint.c:35
static sds get_config_path()
Definition entrypoint.c:275
const DTTR_Core_Context * dttr_sidecar_runtime_context()
Definition entrypoint.c:156
BOOL DllMain(HMODULE module, const DWORD reason_for_call, LPVOID reserved)
Definition entrypoint.c:766
static const DTTR_Core_API RUNTIME_API
Definition entrypoint.c:139
static void install_win_main_hook()
Definition entrypoint.c:552
static void compute_exe_hash()
Definition entrypoint.c:203
static bool dttr_sidecar_store_sds(char *dst, size_t dst_size, sds src)
Definition entrypoint.c:42
#define after_sdl_event(event, consumed)
Definition entrypoint.c:295
char dttr_exe_hash[DTTR_EXE_HASH_LENGTH+1]
Definition entrypoint.c:37
char dttr_loader_dir[MAX_PATH]
Definition entrypoint.c:36
#define REQUIRE_PCDOGS_CALL(expr_)
Definition entrypoint.c:313
static bool dttr_sidecar_write_exception_report(const DTTR_Mods_ExceptionReportRequest *request, DTTR_Mods_ExceptionReport *report)
Definition entrypoint.c:60
static dttr_startup_movies_result attempt_play_startup_movies()
Definition entrypoint.c:497
static bool start_pcdogs_runtime(const DTTR_Core_Context *ctx, HWND hwnd)
Definition entrypoint.c:429
static bool install_required_sidecar_hooks(const DTTR_Mods_Context *ctx)
Definition entrypoint.c:182
dttr_startup_movies_result
Definition entrypoint.c:439
@ DTTR_STARTUP_MOVIES_FAILED
Definition entrypoint.c:442
@ DTTR_STARTUP_MOVIES_QUIT
Definition entrypoint.c:441
@ DTTR_STARTUP_MOVIES_CONTINUE
Definition entrypoint.c:440
static void set_default_exe_hash()
Definition entrypoint.c:198
static sds get_loader_dir()
Definition entrypoint.c:260
static void init_sidecar_context(HMODULE game_module, HMODULE sidecar_module)
Definition entrypoint.c:161
static void toggle_fullscreen()
Definition entrypoint.c:281
int32_t _stdcall DTTR_Hook_WinMainCallback(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int32_t nCmdShow)
Callback target for the patched game Window_RunWinMain routine.
Definition entrypoint.c:574
static const DTTR_Mods_API MOD_API
Definition entrypoint.c:130
void dttr_sidecar_handle_sdl_event(const SDL_Event *event)
Definition entrypoint.c:316
static bool tick_main_loop()
Definition entrypoint.c:446
static void cleanup_runtime(const DTTR_Mods_Context *ctx)
Definition entrypoint.c:392
void dttr_sidecar_poll_sdl_events()
Definition entrypoint.c:383
static bool require_pcdogs_call(const char *name, DTTR_Result result)
Definition entrypoint.c:300
void dttr_game_hooks_cleanup(const DTTR_Mods_Context *)
Definition hooks.c:41
bool dttr_game_hooks_init(const DTTR_Mods_Context *ctx)
Definition hooks.c:10
void dttr_game_data_cleanup()
Definition game_data.c:23
void dttr_game_data_init()
Definition game_data.c:27
void dttr_graphics_hooks_cleanup(const DTTR_Mods_Context *ctx)
Definition hooks.c:236
bool dttr_graphics_hooks_init(const DTTR_Mods_Context *ctx)
Definition hooks.c:190
SDL_Window * dttr_graphics_get_window()
Definition graphics.c:578
SDL_GPUDevice * dttr_graphics_get_device()
Definition graphics.c:583
HWND dttr_graphics_init()
Definition graphics.c:482
void dttr_graphics_handle_window_resize(int width, int height)
Definition graphics.c:588
void dttr_graphics_begin_frame()
Definition graphics.c:599
void dttr_graphics_cleanup()
Definition graphics.c:638
void dttr_graphics_end_frame()
Definition graphics.c:610
static void dttr_graphics_mod_device_restored(DTTR_BackendState *)
static void dttr_graphics_mod_device_created(DTTR_BackendState *)
DTTR_BackendState dttr_backend
Definition util.c:8
static void dttr_graphics_mod_window_created(DTTR_BackendState *)
void dttr_imgui_cleanup()
bool dttr_imgui_process_event(const SDL_Event *event)
void dttr_imgui_init(SDL_Window *window, SDL_GPUDevice *device, DTTR_BackendType backend)
void dttr_inputs_hooks_cleanup(const DTTR_Mods_Context *ctx)
Definition inputs.c:168
bool dttr_inputs_hooks_init(const DTTR_Mods_Context *ctx)
Definition inputs.c:76
bool dttr_inputs_late_init()
Definition inputs.c:155
void dttr_inputs_handle_device_event(const SDL_Event *event)
Definition inputs.c:107
void dttr_inputs_init()
Definition inputs.c:66
void dttr_inputs_cleanup()
Definition inputs.c:172
void dttr_mods_input_mode_changed(const DTTR_Mods_InputContext *ctx)
Definition mods.c:712
void dttr_mods_tick()
Definition mods.c:605
void dttr_mods_overlay_visible_changed(bool visible)
Definition mods.c:654
void dttr_mods_late_init()
Definition mods.c:618
bool dttr_mods_handle_event(const SDL_Event *event)
Definition mods.c:759
void dttr_mods_cleanup()
Definition mods.c:788
void dttr_mods_init()
Definition mods.c:592
void dttr_mods_game_frame_blocked()
Definition mods.c:737
bool dttr_mods_should_advance_game_frame()
Definition mods.c:716
bool dttr_mods_before_event(const SDL_Event *event)
Definition mods.c:704
void dttr_mods_game_frame_advanced()
Definition mods.c:733
void dttr_mods_after_event(const SDL_Event *event, bool consumed)
Definition mods.c:708
void dttr_movies_hooks_cleanup(const DTTR_Mods_Context *ctx)
Definition movies.c:630
bool dttr_movies_hooks_init(const DTTR_Mods_Context *ctx)
Definition movies.c:616
void dttr_movies_start(const char *path)
Definition movies.c:644
dttr_movie_result dttr_movies_stop()
Definition movies.c:741
void dttr_movies_cleanup()
Definition movies.c:635
bool dttr_movies_is_playing()
Definition movies.c:748
void dttr_movies_init()
Definition movies.c:606
void dttr_movies_tick()
Definition movies.c:668
bool dttr_movies_handle_event(const SDL_Event *event)
Definition movies.c:705
dttr_movie_result
@ DTTR_MOVIE_QUIT
@ DTTR_MOVIE_ENDED
@ DTTR_EXE_HASH_LENGTH
static const char * dttr_sidecar_result_detail(DTTR_Result result)
EXCEPTION_RECORD exception_record
Definition dttr_mods.h:26
char dump_path[MAX_PATH]
Definition dttr_mods.h:36
char stack_trace[DTTR_MODS_EXCEPTION_REPORT_STACK_TRACE_CAPACITY]
Definition dttr_mods.h:37