From 35c0c408b9fdb2c4615bf98426506d8670b15eb2 Mon Sep 17 00:00:00 2001 From: otavepto Date: Tue, 16 Apr 2024 22:58:05 +0200 Subject: [PATCH] * allow changing the name of the base folder used to store save data via `saves_folder_name`, by default it would be `Goldberg SteamEmu Saves` * changed the environment variable `SteamAppPath` to `GseAppPath` * allow loading `config.ini` from global settings path + merge it with the local one, and allow the local one to override the global one * fixed the path returned by `get_user_appdata_path()` to include the path separator * updated readmes --- CHANGELOG.md | 6 +- dll/base.cpp | 2 +- dll/dll/common_includes.h | 9 +- dll/dll/local_storage.h | 35 ++++--- dll/dll/steam_matchmaking.h | 10 +- dll/local_storage.cpp | 72 +++++++++----- dll/settings_parser.cpp | 97 +++++++++++++++++-- dll/steam_matchmaking_servers.cpp | 6 +- post_build/README.debug.md | 2 +- post_build/README.release.md | 14 ++- .../configs.EXAMPLE.ini | 15 ++- .../linux/steamclient_loader.sh | 2 +- 12 files changed, 198 insertions(+), 72 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6f29a885..39c4cc38 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,10 +2,14 @@ --- -* **[breaking]** move some settings inside a new file `config.ini` which has to be created inside the `steam_settings` folder +* **[breaking]** move some settings inside a new file `config.ini` which could be created inside the `steam_settings` folder, or inside the global settings folder, which is located at `%appdata%\Goldberg SteamEmu Saves\settings\` on Windows for example. + you can create a global `.ini` file `Goldberg SteamEmu Saves/settings/config.ini` for the common options, and another local one `steam_settings/config.ini` for the game-specific options, and the emu will merge them. --- +* **[breaking]** changed the environment variable `SteamAppPath` to `GseAppPath`, which is used to override the program path detected by the emu +* allow changing the name of the base folder used to store save data, by default it would be `Goldberg SteamEmu Saves`, suggested by **[Clompress]** + this could be changed by setting the option `saves_folder_name` inside the local file `steam_settings/config.ini`, the global one will not work * allow creating the file `local_save.txt` inside the `steam_settings` folder * increase run callbacks background thread polling time to `~200ms` * changed the overlay title to give proper credits to its author diff --git a/dll/base.cpp b/dll/base.cpp index 3717e7d9..6e01a93e 100644 --- a/dll/base.cpp +++ b/dll/base.cpp @@ -218,7 +218,7 @@ std::string get_full_lib_path() std::string get_full_program_path() { - std::string env_program_path = get_env_variable("SteamAppPath"); + std::string env_program_path = get_env_variable("GseAppPath"); if (env_program_path.length()) { if (env_program_path.back() != PATH_SEPARATOR[0]) { env_program_path = env_program_path.append(PATH_SEPARATOR); diff --git a/dll/dll/common_includes.h b/dll/dll/common_includes.h index d604f652..2a8342d6 100644 --- a/dll/dll/common_includes.h +++ b/dll/dll/common_includes.h @@ -54,6 +54,7 @@ #include #include #include +#include #include #include #include @@ -237,14 +238,6 @@ static inline void reset_LastError() #define SERVER_HSTEAMUSER 1 #define DEFAULT_NAME "orca" -#define PROGRAM_NAME_1 "Go" -#define PROGRAM_NAME_2 "ld" -#define PROGRAM_NAME_3 "be" -#define PROGRAM_NAME_4 "rg " -#define PROGRAM_NAME_5 "St" -#define PROGRAM_NAME_6 "ea" -#define PROGRAM_NAME_7 "mE" -#define PROGRAM_NAME_8 "mu" #define DEFAULT_LANGUAGE "english" diff --git a/dll/dll/local_storage.h b/dll/dll/local_storage.h index 2616d7a9..7660148d 100644 --- a/dll/dll/local_storage.h +++ b/dll/dll/local_storage.h @@ -42,30 +42,39 @@ struct image_t }; class Local_Storage { -public: - static constexpr auto inventory_storage_folder = "inventory"; - static constexpr auto settings_storage_folder = "settings"; - static constexpr auto remote_storage_folder = "remote"; - static constexpr auto stats_storage_folder = "stats"; - static constexpr auto leaderboard_storage_folder = "leaderboard"; - static constexpr auto user_data_storage = "local"; - static constexpr auto screenshots_folder = "screenshots"; - static constexpr auto game_settings_folder = "steam_settings"; - private: - std::string save_directory; - std::string appid; - + static std::string saves_folder_name; + public: + static constexpr char inventory_storage_folder[] = "inventory"; + static constexpr char settings_storage_folder[] = "settings"; + static constexpr char remote_storage_folder[] = "remote"; + static constexpr char stats_storage_folder[] = "stats"; + static constexpr char leaderboard_storage_folder[] = "leaderboard"; + static constexpr char user_data_storage[] = "local"; + static constexpr char screenshots_folder[] = "screenshots"; + static constexpr char game_settings_folder[] = "steam_settings"; + static std::string get_program_path(); static std::string get_game_settings_path(); static std::string get_user_appdata_path(); + static int get_file_data(const std::string &full_path, char *data, unsigned int max_length, unsigned int offset=0); static int store_file_data(std::string folder, std::string file, const char *data, unsigned int length); + static std::vector get_filenames_path(std::string path); static std::vector get_folders_path(std::string path); + static void set_saves_folder_name(const std::string_view &str); + static const std::string& get_saves_folder_name(); + +private: + std::string save_directory{}; + std::string appid{}; // game appid + +public: Local_Storage(const std::string &save_directory); + void setAppId(uint32 appid); int store_data(std::string folder, std::string file, char *data, unsigned int length); int store_data_settings(std::string file, const char *data, unsigned int length); diff --git a/dll/dll/steam_matchmaking.h b/dll/dll/steam_matchmaking.h index 8405a952..4b5c02ad 100644 --- a/dll/dll/steam_matchmaking.h +++ b/dll/dll/steam_matchmaking.h @@ -346,7 +346,7 @@ static Lobby_Member *get_lobby_member(Lobby *lobby, CSteamID user_id) int GetFavoriteGameCount() { PRINT_DEBUG_ENTRY(); - std::string file_path = Local_Storage::get_user_appdata_path() + "/7/" + Local_Storage::remote_storage_folder + "/serverbrowser_favorites.txt"; + std::string file_path = Local_Storage::get_user_appdata_path() + "7" + PATH_SEPARATOR + Local_Storage::remote_storage_folder + PATH_SEPARATOR + "serverbrowser_favorites.txt"; unsigned long long file_size = file_size_(file_path); if (file_size) { std::string list{}; @@ -381,11 +381,11 @@ int AddFavoriteGame( AppId_t nAppID, uint32 nIP, uint16 nConnPort, uint16 nQuery unsigned long long file_size; if (unFlags == 1) { - file_path = Local_Storage::get_user_appdata_path() + "/7/" + Local_Storage::remote_storage_folder + "/serverbrowser_favorites.txt"; + file_path = Local_Storage::get_user_appdata_path() + "7" + PATH_SEPARATOR + Local_Storage::remote_storage_folder + PATH_SEPARATOR + "serverbrowser_favorites.txt"; file_size = file_size_(file_path); } else if (unFlags == 2) { - file_path = Local_Storage::get_user_appdata_path() + "/7/" + Local_Storage::remote_storage_folder + "/serverbrowser_history.txt"; + file_path = Local_Storage::get_user_appdata_path() + "7" + PATH_SEPARATOR + Local_Storage::remote_storage_folder + PATH_SEPARATOR + "serverbrowser_history.txt"; file_size = file_size_(file_path); } else { @@ -454,11 +454,11 @@ bool RemoveFavoriteGame( AppId_t nAppID, uint32 nIP, uint16 nConnPort, uint16 nQ unsigned long long file_size; if (unFlags == 1) { - file_path = Local_Storage::get_user_appdata_path() + "/7/" + Local_Storage::remote_storage_folder + "/serverbrowser_favorites.txt"; + file_path = Local_Storage::get_user_appdata_path() + "7" + PATH_SEPARATOR + Local_Storage::remote_storage_folder + "serverbrowser_favorites.txt"; file_size = file_size_(file_path); } else if (unFlags == 2) { - file_path = Local_Storage::get_user_appdata_path() + "/7/" + Local_Storage::remote_storage_folder + "/serverbrowser_history.txt"; + file_path = Local_Storage::get_user_appdata_path() + "7" + PATH_SEPARATOR + Local_Storage::remote_storage_folder + "serverbrowser_history.txt"; file_size = file_size_(file_path); } else { diff --git a/dll/local_storage.cpp b/dll/local_storage.cpp index 5f5836f5..8e52e7e2 100644 --- a/dll/local_storage.cpp +++ b/dll/local_storage.cpp @@ -34,24 +34,58 @@ #include "stb/stb_image_resize.h" struct File_Data { - std::string name; + std::string name{}; }; + +std::string Local_Storage::saves_folder_name = "Goldberg SteamEmu Saves"; + + #ifdef NO_DISK_WRITES std::string Local_Storage::get_program_path() { return " "; } +std::string Local_Storage::get_game_settings_path() +{ + return " "; +} std::string Local_Storage::get_user_appdata_path() { return " "; } -std::string Local_Storage::get_game_settings_path() +int Local_Storage::get_file_data(const std::string &full_path, char *data, unsigned int max_length, unsigned int offset) { - return " "; + return -1; +} + +int Local_Storage::store_file_data(std::string folder, std::string file, const char *data, unsigned int length) +{ + return -1; +} + +std::vector Local_Storage::get_filenames_path(std::string path) +{ + return std::vector(); +} + +std::vector Local_Storage::get_folders_path(std::string path) +{ + return std::vector(); +} + +void Local_Storage::set_saves_folder_name(const std::string_view &str) +{ + +} + +const std::string& Local_Storage::get_saves_folder_name() +{ + const static std::string empty{}; + return empty; } std::string Local_Storage::get_path(std::string folder) @@ -74,11 +108,6 @@ void Local_Storage::setAppId(uint32 appid) } -int Local_Storage::store_file_data(std::string folder, std::string file, const char *data, unsigned int length) -{ - return -1; -} - int Local_Storage::store_data(std::string folder, std::string file, char *data, unsigned int length) { return -1; @@ -89,11 +118,6 @@ int Local_Storage::store_data_settings(std::string file, const char *data, unsig return -1; } -int Local_Storage::get_file_data(const std::string &full_path, char *data, unsigned int max_length, unsigned int offset) -{ - return -1; -} - int Local_Storage::get_data(std::string folder, std::string file, char *data, unsigned int max_length, unsigned int offset) { return -1; @@ -154,16 +178,6 @@ bool Local_Storage::write_json_file(std::string folder, std::string const&file, return false; } -std::vector Local_Storage::get_filenames_path(std::string path) -{ - return std::vector(); -} - -std::vector Local_Storage::get_folders_path(std::string path) -{ - return std::vector(); -} - std::vector Local_Storage::load_image(std::string const& image_path) { return std::vector(); @@ -459,7 +473,7 @@ std::string Local_Storage::get_user_appdata_path() } } #endif - return user_appdata_path.append(PATH_SEPARATOR).append(PROGRAM_NAME_1).append(PROGRAM_NAME_2).append(PROGRAM_NAME_3).append(PROGRAM_NAME_4).append(PROGRAM_NAME_5).append(PROGRAM_NAME_6).append(PROGRAM_NAME_7).append(PROGRAM_NAME_8).append(" Saves"); + return user_appdata_path.append(PATH_SEPARATOR).append(get_saves_folder_name()).append(PATH_SEPARATOR); } static std::string replace_with(std::string s, std::string const &old, const char *new_str) @@ -600,6 +614,16 @@ std::vector Local_Storage::get_folders_path(std::string path) return output; } +void Local_Storage::set_saves_folder_name(const std::string_view &str) +{ + Local_Storage::saves_folder_name = str; +} + +const std::string& Local_Storage::get_saves_folder_name() +{ + return Local_Storage::saves_folder_name; +} + int Local_Storage::store_data(std::string folder, std::string file, char *data, unsigned int length) { if (folder.size() && folder.back() != *PATH_SEPARATOR) { diff --git a/dll/settings_parser.cpp b/dll/settings_parser.cpp index 4751028a..34fa0c1c 100644 --- a/dll/settings_parser.cpp +++ b/dll/settings_parser.cpp @@ -1298,16 +1298,96 @@ static void load_main_config() if (loaded) return; loaded = true; - std::ifstream ini_file(Local_Storage::get_game_settings_path() + "configs.ini", std::ios::binary | std::ios::in); - if (!ini_file.is_open()) { - PRINT_DEBUG("failed to open configs.ini"); - return; - } + constexpr const static auto merge_ini = [](const CSimpleIniA &new_ini) { + std::list sections{}; + new_ini.GetAllSections(sections); + for (auto const &sec : sections) { + std::list keys{}; + new_ini.GetAllKeys(sec.pItem, keys); + for (auto const &key : keys) { + std::list vals{}; + new_ini.GetAllValues(sec.pItem, key.pItem, vals); + for (const auto &val : vals) { + ini.SetValue(sec.pItem, key.pItem, val.pItem); + } + } + } + }; ini.SetUnicode(); - auto err = ini.LoadData(ini_file); - PRINT_DEBUG("result of parsing configs.ini %i (success == 0)", (int)err); - ini_file.close(); + + CSimpleIniA local_ini{}; + local_ini.SetUnicode(); + + // we have to load the local one first, since it might change base saves_folder_name + { + std::ifstream local_ini_file(Local_Storage::get_game_settings_path() + "configs.ini", std::ios::binary | std::ios::in); + if (local_ini_file.is_open()) { + auto err = local_ini.LoadData(local_ini_file); + PRINT_DEBUG("result of parsing local configs.ini %i (success == 0)", (int)err); + local_ini_file.close(); + + if (err == SI_OK) { + std::string saves_folder_name{}; + auto ptr = local_ini.GetValue("saves", "saves_folder_name", nullptr); + if (ptr && ptr[0]) { + saves_folder_name = Settings::sanitize(common_helpers::string_strip(ptr)); + } + + if (saves_folder_name.size()) { + Local_Storage::set_saves_folder_name(saves_folder_name); + PRINT_DEBUG("changed name of the base folder used for save data to '%s'", saves_folder_name.c_str()); + } + } + } + } + + { + CSimpleIniA global_ini{}; + global_ini.SetUnicode(); + + std::ifstream ini_file(Local_Storage::get_user_appdata_path() + Local_Storage::settings_storage_folder + PATH_SEPARATOR + "configs.ini", std::ios::binary | std::ios::in); + if (ini_file.is_open()) { + auto err = global_ini.LoadData(ini_file); + PRINT_DEBUG("result of parsing global configs.ini %i (success == 0)", (int)err); + ini_file.close(); + + if (err == SI_OK) { + merge_ini(global_ini); + } + } + + } + + if (!local_ini.IsEmpty()) { + merge_ini(local_ini); + } + +#ifndef EMU_RELEASE_BUILD + // dump the final ini file + { + PRINT_DEBUG("final ini start ---------"); + std::list sections{}; + ini.GetAllSections(sections); + for (auto const &sec : sections) { + PRINT_DEBUG("[%s]", sec.pItem); + std::list keys{}; + ini.GetAllKeys(sec.pItem, keys); + for (auto const &key : keys) { + std::list vals{}; + ini.GetAllValues(sec.pItem, key.pItem, vals); + for (const auto &val : vals) { + PRINT_DEBUG("%s=%s", key.pItem, val.pItem); + } + } + PRINT_DEBUG(""); + } + PRINT_DEBUG("final ini end *********"); + } +#endif // EMU_RELEASE_BUILD + + reset_LastError(); + } @@ -1335,6 +1415,7 @@ uint32 create_localstorage_settings(Settings **settings_client_out, Settings **s PRINT_DEBUG("program path: '%s', save path: '%s'", program_path.c_str(), save_path.c_str()); Local_Storage *local_storage = new Local_Storage(save_path); + PRINT_DEBUG("global settings path for this app/game: '%s'", local_storage->get_global_settings_path().c_str()); local_storage->setAppId(appid); // Listen port diff --git a/dll/steam_matchmaking_servers.cpp b/dll/steam_matchmaking_servers.cpp index fad4c79a..643edd88 100644 --- a/dll/steam_matchmaking_servers.cpp +++ b/dll/steam_matchmaking_servers.cpp @@ -88,13 +88,13 @@ HServerListRequest Steam_Matchmaking_Servers::RequestServerList(AppId_t iApp, IS std::string file_path; unsigned long long file_size; if (type == eInternetServer || type == eSpectatorServer) { - file_path = Local_Storage::get_user_appdata_path() + "/7/" + Local_Storage::remote_storage_folder + "/serverbrowser.txt"; + file_path = Local_Storage::get_user_appdata_path() + "7" + PATH_SEPARATOR + Local_Storage::remote_storage_folder + PATH_SEPARATOR + "serverbrowser.txt"; file_size = file_size_(file_path); } else if (type == eFavoritesServer) { - file_path = Local_Storage::get_user_appdata_path() + "/7/" + Local_Storage::remote_storage_folder + "/serverbrowser_favorites.txt"; + file_path = Local_Storage::get_user_appdata_path() + "7" + PATH_SEPARATOR + Local_Storage::remote_storage_folder + PATH_SEPARATOR + "serverbrowser_favorites.txt"; file_size = file_size_(file_path); } else if (type == eHistoryServer) { - file_path = Local_Storage::get_user_appdata_path() + "/7/" + Local_Storage::remote_storage_folder + "/serverbrowser_history.txt"; + file_path = Local_Storage::get_user_appdata_path() + "7" + PATH_SEPARATOR + Local_Storage::remote_storage_folder + PATH_SEPARATOR + "serverbrowser_history.txt"; file_size = file_size_(file_path); } diff --git a/post_build/README.debug.md b/post_build/README.debug.md index 69c2ecca..0e133b3b 100644 --- a/post_build/README.debug.md +++ b/post_build/README.debug.md @@ -3,7 +3,7 @@ This is the debug build of the emu, while the game/app is running the emu will write various events to a log file called `STEAM_LOG.txt`. ## Where is this log file ? -Generally it should be beside the .dll/.so iteself, unless the environment variable `SteamAppPath` +Generally it should be beside the .dll/.so iteself, unless the environment variable `GseAppPath` is defined, in which case this will be the path of this log file ## Why ? diff --git a/post_build/README.release.md b/post_build/README.release.md index aed57ec0..f443b353 100644 --- a/post_build/README.release.md +++ b/post_build/README.release.md @@ -29,20 +29,28 @@ so it is recommended to check each example file in the `steam_settings` folder, ## Saves location: * On Windows: - `C:\Users\\AppData\Roaming\Goldberg SteamEmu Saves\` + `%appdata%\Goldberg SteamEmu Saves\` + For example, if your user Windows user name is `Lion`, the save location would be: + `C:\Users\Lion\AppData\Roaming\Goldberg SteamEmu Saves\` * On Linux: * if `XDG_DATA_HOME` is defined: `$XDG_DATA_HOME/Goldberg SteamEmu Saves/` - * Otherwise: + * Otherwise, if `HOME` is defined: `$HOME/.local/share/Goldberg SteamEmu Saves/` + * Otherwise: + `SAVE/Goldberg SteamEmu Saves/` (relative to the current directory, which might not be the same as app/game directory) + +You can override the name of the base folder `Goldberg SteamEmu Saves` to whatever you want per game, to do this modify `configs.ini` inside your `steam_settings` folder and change the value of `saves_folder_name`. +Check the example file in `steam_settings.EXAMPLE\configs.EXAMPLE.ini`. --- -In the global settings folder in that save location you will find these files (if you have used the emulator at least once): +In the global settings folder, in that save location, you will find these files (if you have used the emulator at least once): * `account_name.txt`: edit this file to change your name * `listen_port.txt`: edit this file if you want to change the UDP/TCP port the emulator listens on, you should probably not change this because everyone needs to use the same port or you won't find yourselves on the network * `user_steam_id.txt` this is where your steam id is saved, you can change it, if your saves for a game are locked to a specific steam id see below for a way to change it on a per game basis, but it has to be valid * `language.txt`: edit this to change the language the emulator will report to the game, default is `english`, it must be a valid steam language name or the game might have weird behaviour (list provided at the end of this readme) +* You can also create the file `configs.ini` and specify the most common options you usually set, you can use the provided example file `steam_settings.EXAMPLE\configs.EXAMPLE.ini` as a base. Note that you do not have to specify everything Note that these are global so you won't have to change them for each game. For game unique stuff (stats and remote storage) a folder is created with the appid of the game. If you want to change your steam_id on a per game basis, simply create a settings folder in the game unique directory (Full path: `C:\Users\\AppData\Roaming\Goldberg SteamEmu Saves\\settings`) diff --git a/post_build/steam_settings.EXAMPLE/configs.EXAMPLE.ini b/post_build/steam_settings.EXAMPLE/configs.EXAMPLE.ini index 8b711e40..81d48da5 100644 --- a/post_build/steam_settings.EXAMPLE/configs.EXAMPLE.ini +++ b/post_build/steam_settings.EXAMPLE/configs.EXAMPLE.ini @@ -1,8 +1,10 @@ +# you do not have to specify everything, pick and choose the options you need only + [general] # generate new app auth ticket -new_app_ticket=0 -# generate/embed generate GC inside new App Ticket -gc_token=0 +new_app_ticket=1 +# generate/embed generate GC token inside new App Ticket +gc_token=1 # disable avatar functionality disable_account_avatar=0 # make the game/app think we're playing on a beta branch @@ -28,7 +30,7 @@ matchmaking_server_details_via_source_query=0 [connectivity] # prevent hooking OS networking APIs and allow any external requests # only used by the experimental builds on Windows -disable_lan_only=0 +disable_lan_only=1 # disable all steam networking interface functionality # this won't prevent games/apps from making external requests disable_networking=0 @@ -51,6 +53,11 @@ download_steamhttp_requests=0 # force the function Steam_HTTP::SendHTTPRequest() to always succeed force_steamhttp_success=0 +[saves] +# name of the base folder used to store save data, leading and trailing whitespaces are trimmed +# default=Goldberg SteamEmu Saves +saves_folder_name=Goldberg SteamEmu Saves + [overlay] # --------------------- # USE AT YOUR OWN RISK diff --git a/tools/steamclient_loader/linux/steamclient_loader.sh b/tools/steamclient_loader/linux/steamclient_loader.sh index 73b42077..6a0c0a68 100644 --- a/tools/steamclient_loader/linux/steamclient_loader.sh +++ b/tools/steamclient_loader/linux/steamclient_loader.sh @@ -214,7 +214,7 @@ if [ ! -z "${STEAM_RUNTIME}" ]; then ) fi -SteamAppPath="${EXE_RUN_DIR}" SteamAppId=$APP_ID SteamGameId=$APP_ID SteamOverlayGameId=$APP_ID SteamAppUser='client_player' SteamUser='client_player' SteamClientLaunch='1' SteamEnv='1' SteamPath="$script_dir" "$TARGET_EXE" "${EXE_COMMAND_LINE[@]}" +GseAppPath="${EXE_RUN_DIR}" SteamAppId=$APP_ID SteamGameId=$APP_ID SteamOverlayGameId=$APP_ID SteamAppUser='client_player' SteamUser='client_player' SteamClientLaunch='1' SteamEnv='1' SteamPath="$script_dir" "$TARGET_EXE" "${EXE_COMMAND_LINE[@]}" popd