diff options
Diffstat (limited to 'src/openvic-simulation/dataloader')
-rw-r--r-- | src/openvic-simulation/dataloader/Dataloader.cpp | 305 | ||||
-rw-r--r-- | src/openvic-simulation/dataloader/Dataloader.hpp | 11 | ||||
-rw-r--r-- | src/openvic-simulation/dataloader/Vic2PathSearch.cpp | 342 | ||||
-rw-r--r-- | src/openvic-simulation/dataloader/Vic2PathSearch_Windows.hpp (renamed from src/openvic-simulation/dataloader/Dataloader_Windows.hpp) | 0 |
4 files changed, 342 insertions, 316 deletions
diff --git a/src/openvic-simulation/dataloader/Dataloader.cpp b/src/openvic-simulation/dataloader/Dataloader.cpp index ef0b398..11b4332 100644 --- a/src/openvic-simulation/dataloader/Dataloader.cpp +++ b/src/openvic-simulation/dataloader/Dataloader.cpp @@ -11,16 +11,6 @@ #include "openvic-simulation/utility/ConstexprIntToStr.hpp" #include "openvic-simulation/utility/Logger.hpp" -#ifdef _WIN32 -#include <Windows.h> - -#include "Dataloader_Windows.hpp" -#endif - -#if defined(__APPLE__) && defined(__MACH__) -#include <TargetConditionals.h> -#endif - using namespace OpenVic; using namespace OpenVic::NodeTools; using namespace ovdl; @@ -42,301 +32,6 @@ static constexpr bool path_equals_case_insensitive(std::string_view lhs, std::st return std::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end(), ichar_equals); } -// Windows and Mac by default act like case insensitive filesystems -static constexpr bool path_equals(std::string_view lhs, std::string_view rhs) { -#if defined(FILESYSTEM_CASE_INSENSITIVE) - return path_equals_case_insensitive(lhs, rhs); -#else - return std::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); -#endif -} - -template<typename T> -concept is_filename = std::same_as<T, std::filesystem::path> || std::convertible_to<T, std::string_view>; - -static bool filename_equals(const is_filename auto& lhs, const is_filename auto& rhs) { - auto left = [&lhs] { - if constexpr (std::same_as<std::decay_t<decltype(lhs)>, std::filesystem::path>) { - return lhs.filename().string(); - } else { - return lhs; - } - }(); - auto right = [&rhs] { - if constexpr (std::same_as<std::decay_t<decltype(rhs)>, std::filesystem::path>) { - return rhs.filename().string(); - } else { - return rhs; - } - }(); - return path_equals(left, right); -} - -static fs::path _search_for_game_path(fs::path hint_path = {}) { - // Apparently max amount of steam libraries is 8, if incorrect please correct it to the correct max amount - static constexpr int max_amount_of_steam_libraries = 8; - static constexpr std::string_view Victoria_2_folder = "Victoria 2"; - static constexpr std::string_view v2_game_exe = "v2game.exe"; - static constexpr std::string_view steamapps = "steamapps"; - static constexpr std::string_view libraryfolders = "libraryfolders.vdf"; - static constexpr std::string_view vic2_appmanifest = "appmanifest_42960.acf"; - static constexpr std::string_view common_folder = "common"; - - std::error_code error_code; - - // Don't waste time trying to search for Victoria 2 when supplied a valid looking Victoria 2 game directory - if (filename_equals(Victoria_2_folder, hint_path)) { - if (fs::is_regular_file(hint_path / v2_game_exe, error_code)) { - return hint_path; - } - } - - const bool hint_path_was_empty = hint_path.empty(); - if (hint_path_was_empty) { -#if defined(_WIN32) - static const fs::path registry_path = - Windows::ReadRegValue<char>(HKEY_LOCAL_MACHINE, "SOFTWARE\\WOW6432Node\\Paradox Interactive\\Victoria 2", "path"); - - if (!registry_path.empty()) { - return registry_path; - } - -#pragma warning(push) -#pragma warning(disable : 4996) - static const fs::path prog_files = std::string(std::getenv("ProgramFiles")); - hint_path = prog_files / "Steam"; - if (!fs::is_directory(hint_path, error_code)) { - static const fs::path prog_files_x86 = std::string(std::getenv("ProgramFiles(x86)")); - hint_path = prog_files_x86 / "Steam"; - if (!fs::is_directory(hint_path, error_code)) { - Logger::warning("Could not find path for Steam installation on Windows."); - return ""; - } - } -#pragma warning(pop) - // Cannot support Android - // Only FreeBSD currently unofficially supports emulating Linux -#elif (defined(__linux__) && !defined(__ANDROID__)) || defined(__FreeBSD__) - static const fs::path home = std::getenv("HOME"); - hint_path = home / ".steam" / "steam"; - if (fs::is_symlink(hint_path, error_code)) { - hint_path = fs::read_symlink(hint_path, error_code); - } else if (!fs::is_directory(hint_path, error_code)) { - hint_path = home / ".local" / "share" / "Steam"; - if (!fs::is_directory(hint_path, error_code)) { -#ifdef __FreeBSD__ - Logger::warning("Could not find path for Steam installation on FreeBSD."); -#else - Logger::warning("Could not find path for Steam installation on Linux."); -#endif - return ""; - } - } - // Support only Mac, cannot support iOS -#elif (defined(__APPLE__) && defined(__MACH__)) && TARGET_OS_MAC == 1 - static const fs::path home = std::getenv("HOME"); - hint_path = home / "Library" / "Application Support" / "Steam"; - if (!fs::is_directory(hint_path, error_code)) { - Logger::warning("Could not find path for Steam installation on Mac."); - return ""; - } - // All platforms that reach this point do not seem to even have unofficial Steam support -#else - Logger::warning("Could not find path for Steam installation on unsupported platform."); -#endif - } - - // Could not determine Steam install on platform - if (hint_path.empty()) { - return ""; - } - - // Supplied path was useless, ignore hint_path - if (!hint_path_was_empty && !fs::exists(hint_path, error_code)) { - return _search_for_game_path(); - } - - // Steam Library's directory that will contain Victoria 2 - fs::path vic2_steam_lib_directory; - fs::path current_path = hint_path; - - // If hinted path is directory that contains steamapps - bool is_steamapps = false; - if (fs::is_directory(current_path / steamapps, error_code)) { - current_path /= steamapps; - is_steamapps = true; - } - - // If hinted path is steamapps directory - bool is_libraryfolders_vdf = false; - if (is_steamapps || (filename_equals(steamapps, current_path) && fs::is_directory(current_path, error_code))) { - current_path /= libraryfolders; - is_libraryfolders_vdf = true; - } - - bool vic2_install_confirmed = false; - // if current_path is not a regular file, this is a non-default Steam Library, skip this parser evaluation - if (fs::is_regular_file(current_path, error_code) && - (is_libraryfolders_vdf || filename_equals(libraryfolders, current_path))) { - lexy_vdf::Parser parser; - - std::string buffer; - auto error_log_stream = detail::CallbackStream { - [](void const* s, std::streamsize n, void* user_data) -> std::streamsize { - if (s != nullptr && n > 0 && user_data != nullptr) { - static_cast<std::string*>(user_data)->append(static_cast<char const*>(s), n); - return n; - } else { - Logger::warning("Invalid input to parser error log callback: ", s, " / ", n, " / ", user_data); - return 0; - } - }, - &buffer - }; - parser.set_error_log_to(error_log_stream); - - parser.load_from_file(current_path); - if (!parser.parse()) { - // Could not find or load libraryfolders.vdf, report error as warning - if (!buffer.empty()) { - Logger::warning _(buffer); - } - return ""; - } - std::optional current_node = *(parser.get_key_values()); - - // check "libraryfolders" list - auto it = current_node.value().find("libraryfolders"); - if (it == current_node.value().end()) { - Logger::warning("Expected libraryfolders.vdf to contain a libraryfolders key."); - return ""; - } - - static constexpr auto visit_node = [](auto&& arg) -> std::optional<lexy_vdf::KeyValues> { - using T = std::decay_t<decltype(arg)>; - if constexpr (std::is_same_v<T, lexy_vdf::KeyValues>) { - return arg; - } else { - return std::nullopt; - } - }; - - current_node = std::visit(visit_node, it->second); - - if (!current_node.has_value()) { - Logger::warning("Expected libraryfolders.vdf's libraryfolders key to be a KeyValue dictionary."); - return ""; - } - - // Array of strings contain "0" to std::to_string(max_amount_of_steam_libraries - 1) - static constexpr auto library_indexes = OpenVic::ConstexprIntToStr::make_itosv_array<max_amount_of_steam_libraries>(); - - for (const auto& index : library_indexes) { - decltype(current_node) node = std::nullopt; - - auto it = current_node.value().find(index); - if (it != current_node.value().end()) { - node = std::visit(visit_node, it->second); - } - - // check "apps" list - decltype(node) apps_node = std::nullopt; - if (node.has_value()) { - it = node.value().find("apps"); - if (it != node.value().end()) { - apps_node = std::visit(visit_node, it->second); - } - } - - bool lib_contains_victoria_2 = false; - if (apps_node.has_value()) { - lib_contains_victoria_2 = apps_node.value().find("42960") != node.value().end(); - } - - if (lib_contains_victoria_2) { - it = node.value().find("path"); - if (it != node.value().end()) { - vic2_steam_lib_directory = std::visit( - [](auto&& arg) -> std::string_view { - using T = std::decay_t<decltype(arg)>; - if constexpr (std::is_same_v<T, std::string>) { - return arg; - } else { - return ""; - } - }, - it->second - ); - vic2_install_confirmed = true; - break; - } - } - } - - if (vic2_steam_lib_directory.empty()) { - Logger::info("Steam installation appears not to contain Victoria 2."); - return ""; - } - } - - // If current_path points to steamapps/libraryfolders.vdf - if (vic2_steam_lib_directory.empty()) { - if (is_libraryfolders_vdf || filename_equals(libraryfolders, current_path)) { - vic2_steam_lib_directory = current_path.parent_path() / vic2_appmanifest; - } else if (filename_equals(vic2_appmanifest, current_path)) { - vic2_steam_lib_directory = current_path; - } - } - - // If we could not confirm Victoria 2 was installed via the default Steam installation - bool is_common_folder = false; - if (!vic2_install_confirmed) { - auto parser = lexy_vdf::Parser::from_file(vic2_steam_lib_directory); - if (!parser.parse()) { - // Could not find or load appmanifest_42960.acf, report error as warning - for (auto& error : parser.get_errors()) { - Logger::warning(error.message); - } - return ""; - } - - // we can pretty much assume the Victoria 2 directory on Steam is valid from here - vic2_steam_lib_directory /= common_folder; - is_common_folder = true; - } else if (fs::is_directory(vic2_steam_lib_directory / steamapps, error_code)) { - vic2_steam_lib_directory /= fs::path(steamapps) / common_folder; - is_common_folder = true; - } - - bool is_Victoria_2_folder = false; - if ((is_common_folder || filename_equals(common_folder, vic2_steam_lib_directory)) && - fs::is_directory(vic2_steam_lib_directory, error_code)) { - vic2_steam_lib_directory /= Victoria_2_folder; - is_Victoria_2_folder = true; - } - if ((is_Victoria_2_folder || filename_equals(Victoria_2_folder, vic2_steam_lib_directory)) && - fs::is_regular_file(vic2_steam_lib_directory / v2_game_exe, error_code)) { - return vic2_steam_lib_directory; - } - - // Hail Mary check ignoring the hint_path - if (!hint_path_was_empty) { - return _search_for_game_path(); - } - - Logger::warning("Could not find Victoria 2 game path, this requires manually supplying one."); - return ""; // The supplied path fits literally none of the criteria -} - -fs::path Dataloader::search_for_game_path(fs::path hint_path) { - auto it = _cached_paths.find(hint_path); - if (it != _cached_paths.end()) { - return it->second; - } - - return _cached_paths[hint_path] = _search_for_game_path(hint_path); -} - bool Dataloader::set_roots(path_vector_t const& new_roots) { if (!roots.empty()) { Logger::error("Overriding existing dataloader roots!"); diff --git a/src/openvic-simulation/dataloader/Dataloader.hpp b/src/openvic-simulation/dataloader/Dataloader.hpp index f0a0678..e98d220 100644 --- a/src/openvic-simulation/dataloader/Dataloader.hpp +++ b/src/openvic-simulation/dataloader/Dataloader.hpp @@ -110,16 +110,5 @@ namespace OpenVic { bool load_localisation_files( localisation_callback_t callback, std::string_view localisation_dir = "localisation" ) const; - - private: - struct fshash { - size_t operator()(const std::filesystem::path& p) const noexcept { - return std::filesystem::hash_value(p); - } - }; - - using hint_path_t = fs::path; - using game_path_t = fs::path; - static inline std::unordered_map<hint_path_t, game_path_t, fshash> _cached_paths; }; } diff --git a/src/openvic-simulation/dataloader/Vic2PathSearch.cpp b/src/openvic-simulation/dataloader/Vic2PathSearch.cpp new file mode 100644 index 0000000..10bd08d --- /dev/null +++ b/src/openvic-simulation/dataloader/Vic2PathSearch.cpp @@ -0,0 +1,342 @@ +#include <openvic-dataloader/detail/CallbackOStream.hpp> + +#include <lexy-vdf/KeyValues.hpp> +#include <lexy-vdf/Parser.hpp> + +#include "openvic-simulation/utility/ConstexprIntToStr.hpp" +#include "openvic-simulation/utility/Logger.hpp" + +#include "Dataloader.hpp" + +#ifdef _WIN32 +#include <Windows.h> + +#include "Vic2PathSearch_Windows.hpp" +#endif + +#if defined(__APPLE__) && defined(__MACH__) +#include <TargetConditionals.h> +#endif + +using namespace OpenVic; +using namespace OpenVic::NodeTools; +using namespace ovdl; + +#if defined(_WIN32) || (defined(__APPLE__) && defined(__MACH__)) +#define FILESYSTEM_CASE_INSENSITIVE +#endif + +#if !defined(_WIN32) +#define FILESYSTEM_NEEDS_FORWARD_SLASHES +#endif + +static constexpr bool path_equals_case_insensitive(std::string_view lhs, std::string_view rhs) { + constexpr auto ichar_equals = [](unsigned char l, unsigned char r) { + return std::tolower(l) == std::tolower(r); + }; + return std::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end(), ichar_equals); +} + +// Windows and Mac by default act like case insensitive filesystems +static constexpr bool path_equals(std::string_view lhs, std::string_view rhs) { +#if defined(FILESYSTEM_CASE_INSENSITIVE) + return path_equals_case_insensitive(lhs, rhs); +#else + return std::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); +#endif +} + +template<typename T> +concept is_filename = std::same_as<T, std::filesystem::path> || std::convertible_to<T, std::string_view>; + +static bool filename_equals(const is_filename auto& lhs, const is_filename auto& rhs) { + auto left = [&lhs] { + if constexpr (std::same_as<std::decay_t<decltype(lhs)>, std::filesystem::path>) { + return lhs.filename().string(); + } else { + return lhs; + } + }(); + auto right = [&rhs] { + if constexpr (std::same_as<std::decay_t<decltype(rhs)>, std::filesystem::path>) { + return rhs.filename().string(); + } else { + return rhs; + } + }(); + return path_equals(left, right); +} + +static fs::path _search_for_game_path(fs::path hint_path = {}) { + // Apparently max amount of steam libraries is 8, if incorrect please correct it to the correct max amount + static constexpr int max_amount_of_steam_libraries = 8; + static constexpr std::string_view Victoria_2_folder = "Victoria 2"; + static constexpr std::string_view v2_game_exe = "v2game.exe"; + static constexpr std::string_view steamapps = "steamapps"; + static constexpr std::string_view libraryfolders = "libraryfolders.vdf"; + static constexpr std::string_view vic2_appmanifest = "appmanifest_42960.acf"; + static constexpr std::string_view common_folder = "common"; + + std::error_code error_code; + + // Don't waste time trying to search for Victoria 2 when supplied a valid looking Victoria 2 game directory + if (filename_equals(Victoria_2_folder, hint_path)) { + if (fs::is_regular_file(hint_path / v2_game_exe, error_code)) { + return hint_path; + } + } + + const bool hint_path_was_empty = hint_path.empty(); + if (hint_path_was_empty) { +#if defined(_WIN32) + static const fs::path registry_path = + Windows::ReadRegValue<char>(HKEY_LOCAL_MACHINE, "SOFTWARE\\WOW6432Node\\Paradox Interactive\\Victoria 2", "path"); + + if (!registry_path.empty()) { + return registry_path; + } + +#pragma warning(push) +#pragma warning(disable : 4996) + static const fs::path prog_files = std::string(std::getenv("ProgramFiles")); + hint_path = prog_files / "Steam"; + if (!fs::is_directory(hint_path, error_code)) { + static const fs::path prog_files_x86 = std::string(std::getenv("ProgramFiles(x86)")); + hint_path = prog_files_x86 / "Steam"; + if (!fs::is_directory(hint_path, error_code)) { + Logger::warning("Could not find path for Steam installation on Windows."); + return ""; + } + } +#pragma warning(pop) + // Cannot support Android + // Only FreeBSD currently unofficially supports emulating Linux +#elif (defined(__linux__) && !defined(__ANDROID__)) || defined(__FreeBSD__) + static const fs::path home = std::getenv("HOME"); + hint_path = home / ".steam" / "steam"; + if (fs::is_symlink(hint_path, error_code)) { + hint_path = fs::read_symlink(hint_path, error_code); + } else if (!fs::is_directory(hint_path, error_code)) { + hint_path = home / ".local" / "share" / "Steam"; + if (!fs::is_directory(hint_path, error_code)) { +#ifdef __FreeBSD__ + Logger::warning("Could not find path for Steam installation on FreeBSD."); +#else + Logger::warning("Could not find path for Steam installation on Linux."); +#endif + return ""; + } + } + // Support only Mac, cannot support iOS +#elif (defined(__APPLE__) && defined(__MACH__)) && TARGET_OS_MAC == 1 + static const fs::path home = std::getenv("HOME"); + hint_path = home / "Library" / "Application Support" / "Steam"; + if (!fs::is_directory(hint_path, error_code)) { + Logger::warning("Could not find path for Steam installation on Mac."); + return ""; + } + // All platforms that reach this point do not seem to even have unofficial Steam support +#else + Logger::warning("Could not find path for Steam installation on unsupported platform."); +#endif + } + + // Could not determine Steam install on platform + if (hint_path.empty()) { + return ""; + } + + // Supplied path was useless, ignore hint_path + if (!hint_path_was_empty && !fs::exists(hint_path, error_code)) { + return _search_for_game_path(); + } + + // Steam Library's directory that will contain Victoria 2 + fs::path vic2_steam_lib_directory; + fs::path current_path = hint_path; + + // If hinted path is directory that contains steamapps + bool is_steamapps = false; + if (fs::is_directory(current_path / steamapps, error_code)) { + current_path /= steamapps; + is_steamapps = true; + } + + // If hinted path is steamapps directory + bool is_libraryfolders_vdf = false; + if (is_steamapps || (filename_equals(steamapps, current_path) && fs::is_directory(current_path, error_code))) { + current_path /= libraryfolders; + is_libraryfolders_vdf = true; + } + + bool vic2_install_confirmed = false; + // if current_path is not a regular file, this is a non-default Steam Library, skip this parser evaluation + if (fs::is_regular_file(current_path, error_code) && + (is_libraryfolders_vdf || filename_equals(libraryfolders, current_path))) { + lexy_vdf::Parser parser; + + std::string buffer; + auto error_log_stream = detail::CallbackStream { + [](void const* s, std::streamsize n, void* user_data) -> std::streamsize { + if (s != nullptr && n > 0 && user_data != nullptr) { + static_cast<std::string*>(user_data)->append(static_cast<char const*>(s), n); + return n; + } else { + Logger::warning("Invalid input to parser error log callback: ", s, " / ", n, " / ", user_data); + return 0; + } + }, + &buffer + }; + parser.set_error_log_to(error_log_stream); + + parser.load_from_file(current_path); + if (!parser.parse()) { + // Could not find or load libraryfolders.vdf, report error as warning + if (!buffer.empty()) { + Logger::warning _(buffer); + } + return ""; + } + std::optional current_node = *(parser.get_key_values()); + + // check "libraryfolders" list + auto it = current_node.value().find("libraryfolders"); + if (it == current_node.value().end()) { + Logger::warning("Expected libraryfolders.vdf to contain a libraryfolders key."); + return ""; + } + + static constexpr auto visit_node = [](auto&& arg) -> std::optional<lexy_vdf::KeyValues> { + using T = std::decay_t<decltype(arg)>; + if constexpr (std::is_same_v<T, lexy_vdf::KeyValues>) { + return arg; + } else { + return std::nullopt; + } + }; + + current_node = std::visit(visit_node, it->second); + + if (!current_node.has_value()) { + Logger::warning("Expected libraryfolders.vdf's libraryfolders key to be a KeyValue dictionary."); + return ""; + } + + // Array of strings contain "0" to std::to_string(max_amount_of_steam_libraries - 1) + static constexpr auto library_indexes = OpenVic::ConstexprIntToStr::make_itosv_array<max_amount_of_steam_libraries>(); + + for (const auto& index : library_indexes) { + decltype(current_node) node = std::nullopt; + + auto it = current_node.value().find(index); + if (it != current_node.value().end()) { + node = std::visit(visit_node, it->second); + } + + // check "apps" list + decltype(node) apps_node = std::nullopt; + if (node.has_value()) { + it = node.value().find("apps"); + if (it != node.value().end()) { + apps_node = std::visit(visit_node, it->second); + } + } + + bool lib_contains_victoria_2 = false; + if (apps_node.has_value()) { + lib_contains_victoria_2 = apps_node.value().find("42960") != node.value().end(); + } + + if (lib_contains_victoria_2) { + it = node.value().find("path"); + if (it != node.value().end()) { + vic2_steam_lib_directory = std::visit( + [](auto&& arg) -> std::string_view { + using T = std::decay_t<decltype(arg)>; + if constexpr (std::is_same_v<T, std::string>) { + return arg; + } else { + return ""; + } + }, + it->second + ); + vic2_install_confirmed = true; + break; + } + } + } + + if (vic2_steam_lib_directory.empty()) { + Logger::info("Steam installation appears not to contain Victoria 2."); + return ""; + } + } + + // If current_path points to steamapps/libraryfolders.vdf + if (vic2_steam_lib_directory.empty()) { + if (is_libraryfolders_vdf || filename_equals(libraryfolders, current_path)) { + vic2_steam_lib_directory = current_path.parent_path() / vic2_appmanifest; + } else if (filename_equals(vic2_appmanifest, current_path)) { + vic2_steam_lib_directory = current_path; + } + } + + // If we could not confirm Victoria 2 was installed via the default Steam installation + bool is_common_folder = false; + if (!vic2_install_confirmed) { + auto parser = lexy_vdf::Parser::from_file(vic2_steam_lib_directory); + if (!parser.parse()) { + // Could not find or load appmanifest_42960.acf, report error as warning + for (auto& error : parser.get_errors()) { + Logger::warning(error.message); + } + return ""; + } + + // we can pretty much assume the Victoria 2 directory on Steam is valid from here + vic2_steam_lib_directory /= common_folder; + is_common_folder = true; + } else if (fs::is_directory(vic2_steam_lib_directory / steamapps, error_code)) { + vic2_steam_lib_directory /= fs::path(steamapps) / common_folder; + is_common_folder = true; + } + + bool is_Victoria_2_folder = false; + if ((is_common_folder || filename_equals(common_folder, vic2_steam_lib_directory)) && + fs::is_directory(vic2_steam_lib_directory, error_code)) { + vic2_steam_lib_directory /= Victoria_2_folder; + is_Victoria_2_folder = true; + } + if ((is_Victoria_2_folder || filename_equals(Victoria_2_folder, vic2_steam_lib_directory)) && + fs::is_regular_file(vic2_steam_lib_directory / v2_game_exe, error_code)) { + return vic2_steam_lib_directory; + } + + // Hail Mary check ignoring the hint_path + if (!hint_path_was_empty) { + return _search_for_game_path(); + } + + Logger::warning("Could not find Victoria 2 game path, this requires manually supplying one."); + return ""; // The supplied path fits literally none of the criteria +} + +fs::path Dataloader::search_for_game_path(fs::path hint_path) { + struct fshash { + size_t operator()(const std::filesystem::path& p) const noexcept { + return std::filesystem::hash_value(p); + } + }; + using hint_path_t = fs::path; + using game_path_t = fs::path; + static std::unordered_map<hint_path_t, game_path_t, fshash> _cached_paths; + + auto it = _cached_paths.find(hint_path); + if (it != _cached_paths.end()) { + return it->second; + } + + return _cached_paths[hint_path] = _search_for_game_path(hint_path); +} diff --git a/src/openvic-simulation/dataloader/Dataloader_Windows.hpp b/src/openvic-simulation/dataloader/Vic2PathSearch_Windows.hpp index 37991b6..37991b6 100644 --- a/src/openvic-simulation/dataloader/Dataloader_Windows.hpp +++ b/src/openvic-simulation/dataloader/Vic2PathSearch_Windows.hpp |