diff --git a/common/util/FileUtil.cpp b/common/util/FileUtil.cpp index fdde168510..b6b4768dcd 100644 --- a/common/util/FileUtil.cpp +++ b/common/util/FileUtil.cpp @@ -57,6 +57,14 @@ fs::path get_user_home_dir() { #endif } +struct { + bool initialized = false; + fs::path path_to_data_folder; + fs::path user_config_dir_override = ""; + // by default - if the config dir is overridden, we don't use the default save location + bool use_overridden_config_dir_for_saves = true; +} g_file_path_info; + fs::path get_user_config_dir() { fs::path config_base_path; #ifdef _WIN32 @@ -80,36 +88,52 @@ fs::path get_user_config_dir() { fs::path get_user_settings_dir(GameVersion game_version) { auto game_version_name = game_version_names[game_version]; - return get_user_config_dir() / game_version_name / "settings"; + auto config_dir = get_user_config_dir(); + if (!g_file_path_info.user_config_dir_override.empty()) { + config_dir = g_file_path_info.user_config_dir_override / "OpenGOAL"; + } + return config_dir / game_version_name / "settings"; } fs::path get_user_memcard_dir(GameVersion game_version) { auto game_version_name = game_version_names[game_version]; - return get_user_config_dir() / game_version_name / "saves"; + auto config_dir = get_user_config_dir(); + if (!g_file_path_info.user_config_dir_override.empty() && + g_file_path_info.use_overridden_config_dir_for_saves) { + config_dir = g_file_path_info.user_config_dir_override / "OpenGOAL"; + } + return config_dir / game_version_name / "saves"; } fs::path get_user_screenshots_dir(GameVersion game_version) { auto game_version_name = game_version_names[game_version]; - return get_user_config_dir() / game_version_name / "screenshots"; + auto config_dir = get_user_config_dir(); + if (!g_file_path_info.user_config_dir_override.empty()) { + config_dir = g_file_path_info.user_config_dir_override / "OpenGOAL"; + } + return config_dir / game_version_name / "screenshots"; } fs::path get_user_misc_dir(GameVersion game_version) { auto game_version_name = game_version_names[game_version]; - return get_user_config_dir() / game_version_name / "misc"; + auto config_dir = get_user_config_dir(); + if (!g_file_path_info.user_config_dir_override.empty()) { + config_dir = g_file_path_info.user_config_dir_override / "OpenGOAL"; + } + return config_dir / game_version_name / "misc"; } fs::path get_user_features_dir(GameVersion game_version) { auto game_version_name = game_version_names[game_version]; - auto path = get_user_config_dir() / game_version_name / "features"; + auto config_dir = get_user_config_dir(); + if (!g_file_path_info.user_config_dir_override.empty()) { + config_dir = g_file_path_info.user_config_dir_override / "OpenGOAL"; + } + auto path = config_dir / game_version_name / "features"; file_util::create_dir_if_needed(path); return path; } -struct { - bool initialized = false; - fs::path path_to_data; -} gFilePathInfo; - fs::path g_iso_data_directory = ""; /*! @@ -173,29 +197,30 @@ std::optional try_get_data_dir() { } bool setup_project_path(std::optional project_path_override) { - if (gFilePathInfo.initialized) { + if (g_file_path_info.initialized) { return true; } if (project_path_override) { - gFilePathInfo.path_to_data = fs::absolute(project_path_override.value()); - gFilePathInfo.initialized = true; - lg::info("Using explicitly set project path: {}", gFilePathInfo.path_to_data.string()); + g_file_path_info.path_to_data_folder = fs::absolute(project_path_override.value()); + g_file_path_info.initialized = true; + lg::info("Using explicitly set project path: {}", + g_file_path_info.path_to_data_folder.string()); return true; } auto data_path = try_get_data_dir(); if (data_path) { - gFilePathInfo.path_to_data = *data_path; - gFilePathInfo.initialized = true; + g_file_path_info.path_to_data_folder = *data_path; + g_file_path_info.initialized = true; lg::info("Using data path: {}", data_path->string()); return true; } auto development_repo_path = try_get_jak_project_path(); if (development_repo_path) { - gFilePathInfo.path_to_data = *development_repo_path; - gFilePathInfo.initialized = true; + g_file_path_info.path_to_data_folder = *development_repo_path; + g_file_path_info.initialized = true; lg::info("Using development repo path: {}", *development_repo_path); return true; } @@ -204,9 +229,15 @@ bool setup_project_path(std::optional project_path_override) { return false; } +void override_user_config_dir(fs::path user_config_dir_override, + bool use_overridden_config_dir_for_saves) { + g_file_path_info.user_config_dir_override = user_config_dir_override; + g_file_path_info.use_overridden_config_dir_for_saves = use_overridden_config_dir_for_saves; +} + fs::path get_jak_project_dir() { - ASSERT(gFilePathInfo.initialized); - return gFilePathInfo.path_to_data; + ASSERT(g_file_path_info.initialized); + return g_file_path_info.path_to_data_folder; } fs::path get_iso_dir_for_game(GameVersion game_version) { diff --git a/common/util/FileUtil.h b/common/util/FileUtil.h index c271b7f2ee..dcaecdd2e8 100644 --- a/common/util/FileUtil.h +++ b/common/util/FileUtil.h @@ -41,8 +41,11 @@ void set_iso_data_dir(const fs::path& directory); bool create_dir_if_needed(const fs::path& path); bool create_dir_if_needed_for_file(const std::string& path); bool create_dir_if_needed_for_file(const fs::path& path); +std::string get_current_executable_path(); std::optional try_get_project_path_from_path(const std::string& path); bool setup_project_path(std::optional project_path_override); +void override_user_config_dir(fs::path user_config_dir_override, + bool use_overridden_config_dir_for_saves); std::string get_file_path(const std::vector& path); void write_binary_file(const std::string& name, const void* data, size_t size); void write_binary_file(const fs::path& name, const void* data, size_t size); diff --git a/game/graphics/gfx.cpp b/game/graphics/gfx.cpp index 3762851f2b..8709d9bbeb 100644 --- a/game/graphics/gfx.cpp +++ b/game/graphics/gfx.cpp @@ -55,6 +55,7 @@ u32 Init(GameVersion version) { prof().instant_event("ROOT"); g_debug_settings = game_settings::DebugSettings(); + g_debug_settings.load_settings(); { auto p = scoped_prof("startup::gfx::get_renderer"); g_global_settings.renderer = GetRenderer(GfxPipeline::OpenGL); diff --git a/game/kernel/jak1/klink.cpp b/game/kernel/jak1/klink.cpp index f6ca91b6ea..97be859dde 100644 --- a/game/kernel/jak1/klink.cpp +++ b/game/kernel/jak1/klink.cpp @@ -526,7 +526,7 @@ void link_control::jak1_finish(bool jump_from_c_to_goal) { *EnableMethodSet = *EnableMethodSet + m_keep_debug; ObjectFileHeader* ofh = m_link_block_ptr.cast().c(); - lg::info("link finish: {}", m_object_name); + lg::debug("link finish: {}", m_object_name); if (ofh->object_file_version == 3) { // todo check function type of entry diff --git a/game/kernel/jak2/klink.cpp b/game/kernel/jak2/klink.cpp index 31eeeb1ef1..d0112d0898 100644 --- a/game/kernel/jak2/klink.cpp +++ b/game/kernel/jak2/klink.cpp @@ -544,7 +544,7 @@ void link_control::jak2_finish(bool jump_from_c_to_goal) { *EnableMethodSet = *EnableMethodSet + m_keep_debug; ObjectFileHeader* ofh = m_link_block_ptr.cast().c(); - lg::info("link finish: {}", m_object_name); + lg::debug("link finish: {}", m_object_name); if (ofh->object_file_version == 3) { // todo check function type of entry diff --git a/game/main.cpp b/game/main.cpp index edff28b3e1..c7c147f6fb 100644 --- a/game/main.cpp +++ b/game/main.cpp @@ -42,7 +42,7 @@ void setup_logging(const std::string& game_name, bool verbose, bool disable_ansi lg::set_flush_level(lg::level::debug); } else { lg::set_file_level(lg::level::debug); - lg::set_stdout_level(lg::level::warn); + lg::set_stdout_level(lg::level::info); lg::set_flush_level(lg::level::warn); } if (disable_ansi_colors) { @@ -96,11 +96,14 @@ int main(int argc, char** argv) { bool disable_avx2 = false; bool disable_display = false; bool enable_profiling = false; + bool enable_portable = false; + bool disable_save_location_override = false; std::string profile_until_event = ""; std::string gpu_test = ""; std::string gpu_test_out_path = ""; int port_number = -1; fs::path project_path_override; + fs::path user_config_dir_override; std::vector game_args; CLI::App app{"OpenGOAL Game Runtime"}; app.add_flag("--version", show_version, "Display the built revision"); @@ -112,6 +115,12 @@ int main(int argc, char** argv) { app.add_flag("--no-avx2", disable_avx2, "Disable AVX2 for testing"); app.add_flag("--no-display", disable_display, "Disable video display"); app.add_flag("--profile", enable_profiling, "Enables profiling immediately from startup"); + app.add_flag("--portable", enable_portable, + "Save settings and saves relative to the game's executable, takes precedence over " + "--config-path"); + app.add_flag("--disable_save_location_override", disable_save_location_override, + "If --config-path is provided along with this flag, saves will still be loaded and " + "stored to the default location"); app.add_option("--profile-until-event", profile_until_event, "Stops recording profile events once an event with this name is seen"); app.add_option("--gpu-test", gpu_test, @@ -120,6 +129,8 @@ int main(int argc, char** argv) { "Where to store the gpu test result file"); app.add_option("--proj-path", project_path_override, "Specify the location of the 'data/' folder"); + app.add_option("--config-path", user_config_dir_override, + "Override the location where all user configuration and saves are saved"); app.footer(game_arg_documentation()); app.add_option("Game Args", game_args, "Remaining arguments (after '--') that are passed-through to the game itself"); @@ -127,6 +138,17 @@ int main(int argc, char** argv) { app.allow_extras(); CLI11_PARSE(app, argc, argv); + // Override the user's config dir, potentially (either because it was explicitly provided + // or because it's portable mode) + if (enable_portable) { + lg::info("Portable mod enabled"); + user_config_dir_override = file_util::get_current_executable_path(); + } + if (!user_config_dir_override.empty()) { + lg::info("Overriding config directory with: {}", user_config_dir_override.string()); + file_util::override_user_config_dir(user_config_dir_override, !disable_save_location_override); + } + if (show_version) { lg::print("{}", build_revision()); return 0; diff --git a/game/settings/settings.cpp b/game/settings/settings.cpp index f17edbccad..93092e6d31 100644 --- a/game/settings/settings.cpp +++ b/game/settings/settings.cpp @@ -33,7 +33,9 @@ void from_json(const json& j, DebugSettings& obj) { json_deserialize_if_exists(hide_imgui_key); } -DebugSettings::DebugSettings() { +DebugSettings::DebugSettings() {} + +void DebugSettings::load_settings() { try { std::string file_path = (file_util::get_user_misc_dir(g_game_version) / "debug-settings.json").string(); @@ -71,7 +73,9 @@ void from_json(const json& j, DisplaySettings& obj) { json_deserialize_if_exists(window_ypos); } -DisplaySettings::DisplaySettings() { +DisplaySettings::DisplaySettings() {} + +void DisplaySettings::load_settings() { try { std::string file_path = (file_util::get_user_settings_dir(g_game_version) / "display-settings.json").string(); @@ -114,7 +118,9 @@ void from_json(const json& j, InputSettings& obj) { json_deserialize_if_exists(keyboard_enabled); } -InputSettings::InputSettings() { +InputSettings::InputSettings() {} + +void InputSettings::load_settings() { try { keyboard_binds = DEFAULT_KEYBOARD_BINDS; mouse_binds = DEFAULT_MOUSE_BINDS; @@ -131,6 +137,7 @@ InputSettings::InputSettings() { lg::error("Error encountered when attempting to load input settings {}", e.what()); } } + void InputSettings::save_settings() { json data = *this; auto file_path = file_util::get_user_settings_dir(g_game_version) / "input-settings.json"; diff --git a/game/settings/settings.h b/game/settings/settings.h index 4f161a6ffd..2b66c04e54 100644 --- a/game/settings/settings.h +++ b/game/settings/settings.h @@ -25,6 +25,7 @@ struct DebugSettings { float text_max_range = 0; u32 hide_imgui_key = SDLK_LALT; + void load_settings(); void save_settings(); }; void to_json(json& j, const DebugSettings& obj); @@ -39,6 +40,7 @@ struct DisplaySettings { int window_ypos = 50; int display_id = 0; + void load_settings(); void save_settings(); }; @@ -60,6 +62,7 @@ struct InputSettings { bool keyboard_temp_enabled = false; // not saved or restored, flips on if no controllers are detected + void load_settings(); void save_settings(); }; diff --git a/game/system/hid/display_manager.cpp b/game/system/hid/display_manager.cpp index 8b536803bf..87620b2b08 100644 --- a/game/system/hid/display_manager.cpp +++ b/game/system/hid/display_manager.cpp @@ -12,6 +12,7 @@ DisplayManager::DisplayManager(SDL_Window* window) prof().instant_event("ROOT"); { auto p = scoped_prof("display_manager::init"); + m_display_settings.load_settings(); #ifdef _WIN32 // Windows hint to disable OS level forced scaling and allow native resolution at non 100% // scales diff --git a/game/system/hid/input_manager.cpp b/game/system/hid/input_manager.cpp index b788d3250c..727851c336 100644 --- a/game/system/hid/input_manager.cpp +++ b/game/system/hid/input_manager.cpp @@ -22,6 +22,7 @@ InputManager::InputManager() prof().instant_event("ROOT"); { auto p = scoped_prof("input_manager::init"); + m_settings->load_settings(); { auto p = scoped_prof("input_manager::init::sdl_init_subsystem"); // initializing the controllers on startup can sometimes take a very long time diff --git a/lsp/state/workspace.cpp b/lsp/state/workspace.cpp index 4ea3bc4c3b..4559fd2f5a 100644 --- a/lsp/state/workspace.cpp +++ b/lsp/state/workspace.cpp @@ -379,9 +379,11 @@ void Workspace::tracked_file_will_save(const LSPSpec::DocumentUri& file_uri) { } } -void Workspace::update_global_index(const GameVersion game_version){ - // TODO - project wide indexing potentially (ie. finding references) +// clang-format off +void Workspace::update_global_index(const GameVersion game_version) { + // TODO - project wide indexing potentially (ie. finding references) }; +// clang-format on void Workspace::stop_tracking_file(const LSPSpec::DocumentUri& file_uri) { m_tracked_ir_files.erase(file_uri);