102 Patches: Detours to the Rescue
C reference for DttR maintainers and modders.
Loading...
Searching...
No Matches
hooks.c
Go to the documentation of this file.
1#include "hooks_private.h"
2#include "mss_private.h"
3#include "sidecar_private.h"
4#include <dttr_log.h>
5#include <dttr_pcdogs.h>
6
7#include <SDL3/SDL.h>
8
14
15static int32_t audio_init_system();
16static int32_t __cdecl audio_init_system_detour();
17static int32_t __cdecl audio_stop_all_sounds_detour();
18static int32_t __cdecl audio_init_level_audio_detour();
19static int32_t __cdecl audio_stop_all_samples_detour();
20
21// Detects whether SDL can see a playback endpoint before MSS initializes.
22static bool has_playback_devices() {
23 int count = 0;
24 SDL_AudioDeviceID *devices = SDL_GetAudioPlaybackDevices(&count);
25 SDL_free(devices);
26 return count > 0;
27}
28
29// Treats either the original MSS driver or SDL shim as an active audio backend.
30static bool has_audio_driver() {
31 void *audio_driver = NULL;
33
34 return audio_driver || dttr_mss_core_has_driver();
35}
36
37// Stops SDL-backed samples before delegating only while an audio driver is alive.
38static int32_t run_guarded_audio_hook(int32_t(__cdecl *original)(), bool stop_all_samples) {
39 if (stop_all_samples) {
41 }
42
43 if (!original || !has_audio_driver()) {
44 return 0;
45 }
46
47 return original();
48}
49
50// Shuts down game audio after the last playback device disappears.
53 return;
54 }
55
56 DTTR_LOG_ERROR("Audio device removed, shutting down audio subsystem");
57 int32_t shutdown_result = 0;
60 &shutdown_result
61 );
62}
63
64// Reinitializes game audio when a playback device returns.
66 if (has_audio_driver()) {
67 return;
68 }
69
70 DTTR_LOG_INFO("Audio device connected, reinitializing audio");
72 if (has_audio_driver()) {
73 DTTR_LOG_INFO("Audio reinitialized successfully");
74 return;
75 }
76
77 DTTR_LOG_ERROR("Audio reinitialization failed");
78}
79
80// Starts the MSS audio system only when SDL still has a playback device available.
81static int32_t audio_init_system() {
82 if (!has_playback_devices()) {
83 DTTR_LOG_ERROR("No audio playback devices found, skipping audio init");
84 return 0;
85 }
86
88}
89
90// Funnels game audio initialization through the SDL device guard.
91static int32_t __cdecl audio_init_system_detour() {
92 return audio_init_system();
93}
94
95// Mirrors stop-all-sounds into the SDL sample backend before delegating.
99
100// Skips level-audio initialization after the audio backend is gone.
104
105// Clears SDL sample playback before the original stop-samples routine runs.
109
110// Keeps the game MSS driver matched to SDL audio device availability.
112 switch (event->type) {
113 case SDL_EVENT_AUDIO_DEVICE_REMOVED:
115 return;
116 case SDL_EVENT_AUDIO_DEVICE_ADDED:
118 return;
119 default:
120 return;
121 }
122}
123
124// Installs the MSS audio patch group after SDL audio startup.
126 if (!SDL_InitSubSystem(SDL_INIT_AUDIO)) {
127 DTTR_LOG_ERROR("SDL_InitSubSystem(SDL_INIT_AUDIO) failed: %s", SDL_GetError());
128 }
129
130 const bool imports_ok = dttr_mss_sdl_install_hooks(ctx);
131 const DTTR_PCDOGS_T_Patch_Spec audio_patches[] = {
135 true,
138 ),
140 true,
143 ),
145 true,
148 ),
149 };
150
151 const bool patches_ok = dttr_sidecar_install_pcdogs_patch_group(
152 ctx,
153 "sidecar/audio",
154 audio_patches,
155 DTTR_ARRAY_COUNT(audio_patches),
157 );
158 return imports_ok && patches_ok;
159}
160
161// Releases audio patches before shutting down the SDL replacement backend.
static DTTR_Core_PatchGroup * audio_patch_group
Definition hooks.c:13
static int32_t run_guarded_audio_hook(int32_t(*original)(), bool stop_all_samples)
Definition hooks.c:38
static int32_t audio_stop_all_samples_detour()
Definition hooks.c:106
static DTTR_PCDOGS_F_Audio_StopAllSamples_proto audio_stop_all_samples_original
Definition hooks.c:12
static DTTR_PCDOGS_F_Audio_InitializeSystem_proto audio_init_system_original
Definition hooks.c:9
static int32_t audio_stop_all_sounds_detour()
Definition hooks.c:96
bool dttr_audio_init(const DTTR_Mods_Context *ctx)
Definition hooks.c:125
static bool has_audio_driver()
Definition hooks.c:30
static int32_t audio_init_system()
Definition hooks.c:81
void dttr_audio_handle_device_event(const SDL_Event *event)
Definition hooks.c:111
static int32_t audio_init_level_audio_detour()
Definition hooks.c:101
static DTTR_PCDOGS_F_Audio_StopAllSounds_proto audio_stop_all_sounds_original
Definition hooks.c:10
static void handle_audio_device_added()
Definition hooks.c:65
static void handle_audio_device_removed()
Definition hooks.c:51
void dttr_audio_cleanup(const DTTR_Mods_Context *)
Definition hooks.c:162
static int32_t audio_init_system_detour()
Definition hooks.c:91
static DTTR_PCDOGS_F_Audio_InitializeLevelAudio_proto audio_init_level_audio_original
Definition hooks.c:11
static bool has_playback_devices()
Definition hooks.c:22
DTTR_Graphics_COM_Direct3DDevice7 void DWORD flags DWORD count
void void * ctx
void void DWORD HANDLE event
DTTR_Graphics_COM_DirectDrawSurface7 DWORD flags void NULL
DTTR_Result DTTR_Core_PatchGroupRelease(DTTR_Core_PatchGroup **group)
Definition core.c:657
#define DTTR_ARRAY_COUNT(array_)
Definition dttr_core.h:18
struct DTTR_Core_PatchGroup DTTR_Core_PatchGroup
Definition dttr_core.h:25
#define DTTR_LOG_INFO(...)
Definition dttr_log.h:29
#define DTTR_LOG_ERROR(...)
Definition dttr_log.h:31
union SDL_Event SDL_Event
Definition dttr_mods.h:20
DTTR_PCDOGS_API const struct dttr_pcdogs_function_accessor_Audio_InitializeLevelAudio *const DTTR_PCDOGS_F_Audio_InitializeLevelAudio
Accessor object for Audio_InitializeLevelAudio.
DTTR_PCDOGS_API const struct dttr_pcdogs_function_accessor_Audio_ShutdownSystem *const DTTR_PCDOGS_F_Audio_ShutdownSystem
Accessor object for Audio_ShutdownSystem.
DTTR_PCDOGS_API const struct dttr_pcdogs_function_accessor_Audio_StopAllSounds *const DTTR_PCDOGS_F_Audio_StopAllSounds
Accessor object for Audio_StopAllSounds.
int32_t(* DTTR_PCDOGS_F_Audio_StopAllSounds_proto)()
Stops all currently playing game sounds through the active Miles digital driver.
int32_t(* DTTR_PCDOGS_F_Audio_StopAllSamples_proto)()
Stops all active Miles sample playback slots while leaving the audio system initialized.
DTTR_PCDOGS_API const struct dttr_pcdogs_function_accessor_Audio_StopAllSamples *const DTTR_PCDOGS_F_Audio_StopAllSamples
Accessor object for Audio_StopAllSamples.
int32_t(* DTTR_PCDOGS_F_Audio_InitializeLevelAudio_proto)()
Initializes level audio playback state using the active Miles digital driver.
int32_t(* DTTR_PCDOGS_F_Audio_InitializeSystem_proto)()
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_function_accessor_Audio_InitializeSystem *const DTTR_PCDOGS_F_Audio_InitializeSystem
Accessor object for Audio_InitializeSystem.
const DTTR_Core_Context * dttr_sidecar_runtime_context()
Definition entrypoint.c:156
bool dttr_mss_core_has_driver()
Definition mss_core.c:32
void dttr_mss_sample_stop_all()
Definition mss_sample.c:319
void dttr_mss_sdl_shutdown()
Definition mss_sdl.c:108
bool dttr_mss_sdl_install_hooks(const DTTR_Mods_Context *ctx)
Definition mss_sdl.c:228
void dttr_mss_sdl_release_hooks()
Definition mss_sdl.c:205
static bool dttr_sidecar_install_pcdogs_patch_group(const DTTR_Mods_Context *ctx, const char *label, const DTTR_PCDOGS_T_Patch_Spec *patches, size_t patch_count, DTTR_Core_PatchGroup **group)