14#include <gen/packed_sdb.h>
23static bool set_env(
const char *name,
const char *value) {
24 if (SetEnvironmentVariableA(name, value)) {
47 sds default_config_path =
NULL;
48 const char *config_path = argc > 1 ? argv[1] :
NULL;
49 if (!config_path || !config_path[0]) {
51 config_path = default_config_path;
54 if (!config_path || !config_path[0]) {
55 sdsfree(default_config_path);
56 DTTR_FATAL(
"Could not resolve default loader config path");
60 sdsfree(default_config_path);
61 if (len == 0 || len >= MAX_PATH) {
62 DTTR_FATAL(
"Could not resolve loader config path");
69 char loader_dir[MAX_PATH];
70 const char *base_dir =
NULL;
72 base_dir = loader_dir;
80 FILE *log_file = fopen(log_path,
"a+");
90 if (!child_info->hProcess) {
94 if (!TerminateProcess(child_info->hProcess, exit_code)) {
95 DTTR_LOG_ERROR(
"Could not terminate game process after launch failure");
99 const DWORD wait_result = WaitForSingleObject(child_info->hProcess, 10000);
100 if (wait_result != WAIT_OBJECT_0) {
102 "Timed out waiting for game process to terminate after launch failure"
111 if (child_info->hThread) {
112 CloseHandle(child_info->hThread);
115 if (child_info->hProcess) {
116 CloseHandle(child_info->hProcess);
123 const DWORD old_len = GetEnvironmentVariableA(
"PATH", old_path,
sizeof(old_path));
124 if (old_len >=
sizeof(old_path)) {
125 DTTR_LOG_ERROR(
"PATH is too long to prepend DttR modules directory");
129 char modules_dir[MAX_PATH];
131 DTTR_LOG_ERROR(
"Could not resolve DttR modules directory for PATH");
136 const int written = old_len > 0
144 : snprintf(new_path,
sizeof(new_path),
"%s", modules_dir);
146 if (written <= 0 || (
size_t)written >=
sizeof(new_path)) {
147 DTTR_LOG_ERROR(
"PATH is too long after prepending DttR modules directory");
151 if (!
set_env(
"PATH", new_path)) {
155 DTTR_LOG_DEBUG(
"Prepended DttR modules directory to PATH: %s", modules_dir);
159 char exe_dir[MAX_PATH];
160 PROCESS_INFORMATION child_info = {0};
161 DWORD child_exit_code = 1;
164 DTTR_FATAL(
"Could not resolve loader directory");
174 "Could not load configuration file %s%s%s",
176 details ?
":\n" :
"",
177 details ? details :
""
186 DTTR_LOG_INFO(
"Starting DttR loader (log level: %s)", log_level_string(log_level));
190 WCHAR exe_path[MAX_PATH];
197 DTTR_FATAL(
"Could not pass configuration path to game process");
205 DTTR_FATAL(
"Could not pass ISO extraction paths to game process");
212 (
const char *)packed_sdb,
226 WaitForSingleObject(child_info.hProcess, INFINITE);
227 if (!GetExitCodeProcess(child_info.hProcess, &child_exit_code)) {
232 DTTR_LOG_INFO(
"Exiting loader with child exit code %lu", child_exit_code);
242 return child_info.hProcess ? (int)child_exit_code : 0;
static void cleanup(DTTR_BackendState *state)
DTTR_Graphics_COM_DirectDrawSurface7 DWORD flags void NULL
const char * DTTR_Config_LastError()
Returns details from the most recent config load failure, or NULL when none exist.
#define DTTR_CONFIG_FILENAME
bool DTTR_Config_Load(const char *filename)
Loads config values from a strict JSON file into the global config object.
void DTTR_CrashDump_Init(const char *dump_dir)
#define DTTR_REPORT_SUFFIX
void DTTR_Errors_SetMessageHandler(DTTR_ErrorMessageHandler handler)
#define DTTR_FATAL(error_message,...)
#define DTTR_ERROR(error_message,...)
void DTTR_ImGuiDialog_Shutdown()
void DTTR_Loader_WatchdogDetach(const PROCESS_INFORMATION *child_info)
bool DTTR_Loader_InjectSidecar(const PROCESS_INFORMATION *child_info)
bool DTTR_Loader_WatchdogWait(const PROCESS_INFORMATION *child_info)
const char * dttr_config_path
void DTTR_Loader_WatchdogAttach(const PROCESS_INFORMATION *child_info)
bool DTTR_Loader_ResolveEXEPath(WCHAR *out, const char *configured_path, DTTR_LoaderIsoContext *iso_context)
void DTTR_Compat_CreateProcess(const WCHAR *image_name, const char *shim_data, size_t shim_data_len, PROCESS_INFORMATION *child_info)
void DTTR_LoaderUI_ShowError(const char *title, const char *message)
#define DTTR_LOG_DEBUG(...)
void DTTR_Log_SetLevel(int level)
#define DTTR_LOG_INFO(...)
int DTTR_Log_AddFP(FILE *fp, int level)
#define DTTR_LOG_ERROR(...)
sds DTTR_Path_ModuleSibling(void *module, const char *relative_path)
bool DTTR_Path_CopySds(char *out, size_t out_size, sds value)
sds DTTR_Path_ResolveRelativeTo(const char *base_dir, const char *path)
sds DTTR_Path_ModuleDir(void *module)
static const char *const MODULES_DIR_NAME
int dttr_launcher_main(int argc, char *argv[])
static bool terminate_child(PROCESS_INFORMATION *child_info, DWORD exit_code)
static bool set_env(const char *name, const char *value)
static void resolve_config_path(int argc, char *argv[])
static bool resolve_modules_dir(char *out, size_t out_size)
static void prepend_modules_to_path()
static FILE * open_log_file(int log_level)
static char config_path_buf[MAX_PATH]
static bool resolve_loader_dir(char *out, size_t out_size)
static void close_child_handles(PROCESS_INFORMATION *child_info)
char cache_root[MAX_PATH]