diff --git a/src/pc/cliopts.c b/src/pc/cliopts.c index 18b485333..f8bab9c2f 100644 --- a/src/pc/cliopts.c +++ b/src/pc/cliopts.c @@ -15,7 +15,7 @@ struct CLIOptions gCLIOpts; static void print_help(void) { printf("sm64coopdx\n"); #if defined(_WIN32) || defined(_WIN64) - printf("--console Enables the Windows console.\n"); + printf("--console Enables the Windows console.\n"); #endif printf("--savepath SAVEPATH Overrides the default save/config path ('!' expands to executable path).\n"); printf("--configfile CONFIGNAME Saves the configuration file as CONFIGNAME.\n"); @@ -33,7 +33,8 @@ static void print_help(void) { printf("--skip-update-check Skips the update check when loading the game.\n"); printf("--no-discord Disables discord integration.\n"); printf("--disable-mods Disables all mods that are already enabled.\n"); - printf("--enable-mod MODNAME Enables a mod."); + printf("--enable-mod MODNAME Enables a mod.\n"); + printf("--headless Enable Headless mode."); } static inline int arg_string(const char *name, const char *value, char *target, int maxLength) { @@ -112,6 +113,8 @@ bool parse_cli_opts(int argc, char* argv[]) { gCLIOpts.enableMods = realloc(gCLIOpts.enableMods, sizeof(char*) * gCLIOpts.enabledModsCount); } gCLIOpts.enableMods[gCLIOpts.enabledModsCount - 1] = strdup(argv[++i]); + } else if (!strcmp(argv[i], "--headless")) { + gCLIOpts.headless = true; } else if (!strcmp(argv[i], "--help")) { print_help(); return false; diff --git a/src/pc/cliopts.h b/src/pc/cliopts.h index e30f67be1..d848ed4f5 100644 --- a/src/pc/cliopts.h +++ b/src/pc/cliopts.h @@ -36,6 +36,7 @@ struct CLIOptions { bool disableMods; int enabledModsCount; char** enableMods; + bool headless; }; extern struct CLIOptions gCLIOpts; diff --git a/src/pc/debuglog.h b/src/pc/debuglog.h index e078c5380..04e238c14 100644 --- a/src/pc/debuglog.h +++ b/src/pc/debuglog.h @@ -49,7 +49,7 @@ static void _debuglog_print_log(const char* logType, char* filename) { #define LOG_ERROR(...) #else #define LOG_DEBUG(...) (configDebugPrint ? ( _debuglog_print_log("DEBUG", __FILE__), printf(__VA_ARGS__), printf("\n") ) : 0) -#define LOG_INFO(...) (configDebugInfo ? ( _debuglog_print_log("INFO", __FILE__), printf(__VA_ARGS__), printf("\n") ) : 0) +#define LOG_INFO(...) ((configDebugInfo || gCLIOpts.headless) ? ( _debuglog_print_log("INFO", __FILE__), printf(__VA_ARGS__), printf("\n") ) : 0) #define LOG_ERROR(...) (configDebugError ? ( _debuglog_print_log("ERROR", __FILE__), printf(__VA_ARGS__), printf("\n") ) : 0) #endif #define LOG_CONSOLE(...) { snprintf(gDjuiConsoleTmpBuffer, CONSOLE_MAX_TMP_BUFFER, __VA_ARGS__), djui_console_message_create(gDjuiConsoleTmpBuffer, CONSOLE_MESSAGE_INFO); } diff --git a/src/pc/gfx/gfx_dummy.c b/src/pc/gfx/gfx_dummy.c index f435d8adb..944af34b1 100644 --- a/src/pc/gfx/gfx_dummy.c +++ b/src/pc/gfx/gfx_dummy.c @@ -1,5 +1,3 @@ -#if defined(RAPI_DUMMY) || defined(WAPI_DUMMY) - #ifdef WIN32 #include #elif _POSIX_C_SOURCE >= 199309L @@ -247,5 +245,4 @@ struct GfxRenderingAPI gfx_dummy_renderer_api = { gfx_dummy_renderer_end_frame, gfx_dummy_renderer_finish_render, gfx_dummy_renderer_shutdown -}; -#endif +}; \ No newline at end of file diff --git a/src/pc/network/network.c b/src/pc/network/network.c index 86eda1ded..4c29aa7bb 100644 --- a/src/pc/network/network.c +++ b/src/pc/network/network.c @@ -132,11 +132,7 @@ bool network_init(enum NetworkType inNetworkType, bool reconnecting) { gServerSettings.maxPlayers = configAmountOfPlayers; gServerSettings.pauseAnywhere = configPauseAnywhere; gServerSettings.pvpType = configPvpType; -#if defined(RAPI_DUMMY) || defined(WAPI_DUMMY) - gServerSettings.headlessServer = (inNetworkType == NT_SERVER); -#else - gServerSettings.headlessServer = 0; -#endif + gServerSettings.headlessServer = gCLIOpts.headless && (inNetworkType == NT_SERVER); gNametagsSettings.showHealth = false; gNametagsSettings.showSelfTag = false; diff --git a/src/pc/pc_main.c b/src/pc/pc_main.c index 6fe95bc21..ed8508ba5 100644 --- a/src/pc/pc_main.c +++ b/src/pc/pc_main.c @@ -411,9 +411,13 @@ int main(int argc, char *argv[]) { // handle terminal arguments if (!parse_cli_opts(argc, argv)) { return 0; } +#if defined(RAPI_DUMMY) || defined(WAPI_DUMMY) + gCLIOpts.headless = true; +#endif + #ifdef _WIN32 // handle Windows console - if (gCLIOpts.console) { + if (gCLIOpts.console || gCLIOpts.headless) { SetConsoleOutputCP(CP_UTF8); } else { FreeConsole(); @@ -433,6 +437,13 @@ int main(int argc, char *argv[]) { fs_init(gCLIOpts.savePath[0] ? gCLIOpts.savePath : sys_user_path()); #endif +#if !defined(RAPI_DUMMY) && !defined(WAPI_DUMMY) + if (gCLIOpts.headless) { + memcpy(&WAPI, &gfx_dummy_wm_api, sizeof(struct GfxWindowManagerAPI)); + memcpy(&RAPI, &gfx_dummy_renderer_api, sizeof(struct GfxRenderingAPI)); + } +#endif + configfile_load(); legacy_folder_handler(); @@ -460,7 +471,7 @@ int main(int argc, char *argv[]) { // start the thread for setting up the game #ifdef LOADING_SCREEN_SUPPORTED bool threadSuccess = false; - if (!gCLIOpts.hideLoadingScreen) { + if (!gCLIOpts.hideLoadingScreen && !gCLIOpts.headless) { if (init_thread_handle(&gLoadingThread, main_game_init, NULL, NULL, 0) == 0) { render_loading_screen(); // render the loading screen while the game is setup threadSuccess = true; @@ -477,10 +488,11 @@ int main(int argc, char *argv[]) { thread5_game_loop(NULL); // initialize sound outside threads + if (gCLIOpts.headless) audio_api = &audio_null; #if defined(AAPI_SDL1) || defined(AAPI_SDL2) - if (!audio_api && audio_sdl.init()) { audio_api = &audio_sdl; } + if (!audio_api && audio_sdl.init()) audio_api = &audio_sdl; #endif - if (!audio_api) { audio_api = &audio_null; } + if (!audio_api) audio_api = &audio_null; // Initialize the audio thread if possible. // init_thread_handle(&gAudioThread, audio_thread, NULL, NULL, 0);