From 48f7b23c61a5817685aa02f7801d551431b7531e Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Tue, 17 Mar 2026 20:10:42 +0000 Subject: [PATCH] Change: add automatic baseset path discovery to plugin API --- .../CMakeLists.txt | 2 +- .../openttd_social_integration_api.h | 2 +- ....h => openttd_social_integration_api_v2.h} | 28 ++++++++------- src/fileio.cpp | 32 ++++++++++++++++- src/fileio_func.h | 2 ++ src/fileio_type.h | 7 +++- src/openttd.cpp | 3 +- src/social_integration.cpp | 36 +++++++++++++------ src/social_integration.h | 5 +++ 9 files changed, 89 insertions(+), 28 deletions(-) rename src/3rdparty/openttd_social_integration_api/{openttd_social_integration_api_v1.h => openttd_social_integration_api_v2.h} (85%) diff --git a/src/3rdparty/openttd_social_integration_api/CMakeLists.txt b/src/3rdparty/openttd_social_integration_api/CMakeLists.txt index 86cca4a3d6c68..b4bcfc7695fc0 100644 --- a/src/3rdparty/openttd_social_integration_api/CMakeLists.txt +++ b/src/3rdparty/openttd_social_integration_api/CMakeLists.txt @@ -1,4 +1,4 @@ add_files( openttd_social_integration_api.h - openttd_social_integration_api_v1.h + openttd_social_integration_api_v2.h ) diff --git a/src/3rdparty/openttd_social_integration_api/openttd_social_integration_api.h b/src/3rdparty/openttd_social_integration_api/openttd_social_integration_api.h index 3a165a1b96e45..3a4b7d579f4b2 100644 --- a/src/3rdparty/openttd_social_integration_api/openttd_social_integration_api.h +++ b/src/3rdparty/openttd_social_integration_api/openttd_social_integration_api.h @@ -33,6 +33,6 @@ #ifndef OPENTTD_SOCIAL_INTEGRATION_API_H #define OPENTTD_SOCIAL_INTEGRATION_API_H -#include "openttd_social_integration_api_v1.h" +#include "openttd_social_integration_api_v2.h" #endif /* OPENTTD_SOCIAL_INTEGRATION_API_H */ diff --git a/src/3rdparty/openttd_social_integration_api/openttd_social_integration_api_v1.h b/src/3rdparty/openttd_social_integration_api/openttd_social_integration_api_v2.h similarity index 85% rename from src/3rdparty/openttd_social_integration_api/openttd_social_integration_api_v1.h rename to src/3rdparty/openttd_social_integration_api/openttd_social_integration_api_v2.h index fcf9dcc8a7731..086d59b44e5ee 100644 --- a/src/3rdparty/openttd_social_integration_api/openttd_social_integration_api_v1.h +++ b/src/3rdparty/openttd_social_integration_api/openttd_social_integration_api_v2.h @@ -28,17 +28,17 @@ * for non-free implementations. */ -/** @file v1.h Version 1 definition of the OpenTTD Social Integration Plugin API. */ +/** @file v1.h Version 2 definition of the OpenTTD Social Integration Plugin API. */ -#ifndef OPENTTD_SOCIAL_INTEGRATION_API_V1_H -#define OPENTTD_SOCIAL_INTEGRATION_API_V1_H +#ifndef OPENTTD_SOCIAL_INTEGRATION_API_V2_H +#define OPENTTD_SOCIAL_INTEGRATION_API_V2_H #ifdef __cplusplus extern "C" { #endif /** Pointers supplied by the plugin for OpenTTD to use. */ -struct OpenTTD_SocialIntegration_v1_PluginInfo { +struct OpenTTD_SocialIntegration_v2_PluginInfo { /** * The Social Platform this plugin is for. * @@ -62,7 +62,7 @@ struct OpenTTD_SocialIntegration_v1_PluginInfo { }; /** Pointers supplied by the plugin for OpenTTD to use. */ -struct OpenTTD_SocialIntegration_v1_PluginApi { +struct OpenTTD_SocialIntegration_v2_PluginApi { /** * OpenTTD tells the plugin to shut down. * @@ -114,18 +114,20 @@ struct OpenTTD_SocialIntegration_v1_PluginApi { * This is followed by event_enter_multiplayer() if the join was successful. */ void (*event_joining_multiplayer)(); + + char *(*add_search_paths)(char *path, const char *path_last); }; /** Pointers supplied by OpenTTD, for the plugin to use. */ -struct OpenTTD_SocialIntegration_v1_OpenTTDInfo { +struct OpenTTD_SocialIntegration_v2_OpenTTDInfo { const char *openttd_version; ///< Version of OpenTTD. UTF-8, nul-terminated. OpenTTD is and remains the owner of the memory. }; /** The result of the initialization. */ -enum OpenTTD_SocialIntegration_v1_InitResult : int { - OTTD_SOCIAL_INTEGRATION_V1_INIT_SUCCESS = 1, ///< Plugin initialized successfully. - OTTD_SOCIAL_INTEGRATION_V1_INIT_FAILED = -1, ///< Plugin failed to initialize (generic error). - OTTD_SOCIAL_INTEGRATION_V1_INIT_PLATFORM_NOT_RUNNING = -2, ///< The Social Platform is not running. +enum OpenTTD_SocialIntegration_v2_InitResult : int { + OTTD_SOCIAL_INTEGRATION_V2_INIT_SUCCESS = 1, ///< Plugin initialized successfully. + OTTD_SOCIAL_INTEGRATION_V2_INIT_FAILED = -1, ///< Plugin failed to initialize (generic error). + OTTD_SOCIAL_INTEGRATION_V2_INIT_PLATFORM_NOT_RUNNING = -2, ///< The Social Platform is not running. }; /** @@ -138,7 +140,7 @@ enum OpenTTD_SocialIntegration_v1_InitResult : int { * @param[in] openttd_info Structure that OpenTTD filled with pointers. All pointers will remain valid until shutdown(). OpenTTD is owner of the memory. * @return The status of the initialization. */ -typedef OpenTTD_SocialIntegration_v1_InitResult (*OpenTTD_SocialIntegration_v1_Init)(OpenTTD_SocialIntegration_v1_PluginApi *plugin_api, const OpenTTD_SocialIntegration_v1_OpenTTDInfo *openttd_info); +typedef OpenTTD_SocialIntegration_v2_InitResult (*OpenTTD_SocialIntegration_v2_Init)(OpenTTD_SocialIntegration_v2_PluginApi *plugin_api, const OpenTTD_SocialIntegration_v2_OpenTTDInfo *openttd_info); /** * Type of the GetInfo function the plugin is expected to export from its dynamic library. @@ -148,10 +150,10 @@ typedef OpenTTD_SocialIntegration_v1_InitResult (*OpenTTD_SocialIntegration_v1_I * * @param[out] plugin_info Structure the plugin must fill with pointers. The plugin is owner of the memory. */ -typedef void (*OpenTTD_SocialIntegration_v1_GetInfo)(OpenTTD_SocialIntegration_v1_PluginInfo *plugin_info); +typedef void (*OpenTTD_SocialIntegration_v2_GetInfo)(OpenTTD_SocialIntegration_v2_PluginInfo *plugin_info); #ifdef __cplusplus } /* extern "C" */ #endif -#endif /* OPENTTD_SOCIAL_INTEGRATION_API_V1_H */ +#endif /* OPENTTD_SOCIAL_INTEGRATION_API_V2_H */ diff --git a/src/fileio.cpp b/src/fileio.cpp index bb767376ea31e..9c438c7ee922f 100644 --- a/src/fileio.cpp +++ b/src/fileio.cpp @@ -10,6 +10,7 @@ #include "stdafx.h" #include "core/string_consumer.hpp" #include "fileio_func.h" +#include "social_integration.h" #include "spriteloader/spriteloader.hpp" #include "debug.h" #include "fios.h" @@ -165,6 +166,9 @@ std::string FioGetDirectory(Searchpath sp, Subdirectory subdir) assert(subdir < NUM_SUBDIRS); assert(sp < NUM_SEARCHPATHS); + /* For additional baseset directories, don't ever include the subdirectory. */ + if (sp >= SP_ADDITIONAL_DIR && subdir == BASESET_DIR) return _searchpaths[sp]; + return fmt::format("{}{}", _searchpaths[sp], _subdirs[subdir]); } @@ -195,7 +199,7 @@ static std::optional FioFOpenFileSp(std::string_view filename, std:: if (subdir == NO_DIRECTORY) { buf = filename; } else { - buf = fmt::format("{}{}{}", _searchpaths[sp], _subdirs[subdir], filename); + buf = fmt::format("{}{}", FioGetDirectory(sp, subdir), filename); } auto f = FileHandle::Open(buf, mode); @@ -753,6 +757,29 @@ static std::string GetHomeDir() return {}; } +/** + * Clear all additional search paths. + */ +void ClearAdditionalSearchPaths() +{ + for (Searchpath sp = SP_ADDITIONAL_DIR; sp != NUM_SEARCHPATHS; ++sp) { + _searchpaths[sp].clear(); + } +} + +/** + * Set an additional search path. + * @param path the search path to set. + */ +void SetAdditionalSearchPath(std::string_view path) +{ + for (Searchpath sp = SP_ADDITIONAL_DIR; sp != NUM_SEARCHPATHS; ++sp) { + if (!_searchpaths[sp].empty()) continue; + _searchpaths[sp] = path.ends_with(PATHSEP) ? path : fmt::format("{}{}", path, PATHSEP); + break; + } +} + /** * Determine the base (personal dir and game data dir) paths * @param exe the path to the executable @@ -852,6 +879,9 @@ void DetermineBasePaths(std::string_view exe) _searchpaths[SP_BINARY_DIR].clear(); } + ClearAdditionalSearchPaths(); + SocialIntegration::AddSearchPaths(); + if (cwd[0] != '\0') { /* Go back to the current working directory. */ if (chdir(cwd) != 0) { diff --git a/src/fileio_func.h b/src/fileio_func.h index 264bb9677d6dc..3a0b43fbf6c74 100644 --- a/src/fileio_func.h +++ b/src/fileio_func.h @@ -30,6 +30,8 @@ std::unique_ptr ReadFileToMem(const std::string &filename, size_t &lenp, bool FileExists(std::string_view filename); bool ExtractTar(const std::string &tar_filename, Subdirectory subdir); +void SetAdditionalSearchPath(std::string_view path); + extern std::string _personal_dir; ///< custom directory for personal settings, saves, newgrf, etc. extern std::vector _valid_searchpaths; diff --git a/src/fileio_type.h b/src/fileio_type.h index 5e33e33e7ad2e..3e9d903790500 100644 --- a/src/fileio_type.h +++ b/src/fileio_type.h @@ -107,6 +107,9 @@ enum Subdirectory : uint8_t { NO_DIRECTORY, ///< A path without any base directory }; +/** Number of additional search directories. */ +static constexpr size_t NUM_ADDITIONAL_DIRS = 3; + /** * Types of searchpaths OpenTTD might use */ @@ -124,7 +127,9 @@ enum Searchpath : uint8_t { SP_AUTODOWNLOAD_DIR, ///< Search within the autodownload directory SP_AUTODOWNLOAD_PERSONAL_DIR, ///< Search within the autodownload directory located in the personal directory SP_AUTODOWNLOAD_PERSONAL_DIR_XDG, ///< Search within the autodownload directory located in the personal directory (XDG variant) - NUM_SEARCHPATHS + SP_ADDITIONAL_DIR, ///< Search within an additional directory + + NUM_SEARCHPATHS = SP_ADDITIONAL_DIR + NUM_ADDITIONAL_DIRS, ///< Total number of search paths }; DECLARE_INCREMENT_DECREMENT_OPERATORS(Searchpath) diff --git a/src/openttd.cpp b/src/openttd.cpp index 7de9e0cf12b6d..b23379c20b15e 100644 --- a/src/openttd.cpp +++ b/src/openttd.cpp @@ -663,6 +663,8 @@ int openttd_main(std::span arguments) return 1; } + DeterminePaths(arguments[0], only_local_path); + SocialIntegration::Initialize(); DeterminePaths(arguments[0], only_local_path); TarScanner::DoScan(TarScanner::Mode::Baseset); @@ -760,7 +762,6 @@ int openttd_main(std::span arguments) /* The video driver is now selected, now initialise GUI zoom */ UpdateGUIZoom(); - SocialIntegration::Initialize(); NetworkStartUp(); // initialize network-core if (!HandleBootstrap()) { diff --git a/src/social_integration.cpp b/src/social_integration.cpp index d19d57947168a..9ca945fe3ec7d 100644 --- a/src/social_integration.cpp +++ b/src/social_integration.cpp @@ -16,6 +16,7 @@ #include "fileio_func.h" #include "library_loader.h" #include "rev.h" +#include "settings_type.h" #include "string_func.h" #include "signature.h" @@ -38,9 +39,9 @@ class InternalSocialIntegrationPlugin { this->library = std::make_unique(filename); } - OpenTTD_SocialIntegration_v1_PluginInfo plugin_info = {}; ///< Information supplied by plugin. - OpenTTD_SocialIntegration_v1_PluginApi plugin_api = {}; ///< API supplied by plugin. - OpenTTD_SocialIntegration_v1_OpenTTDInfo openttd_info = {}; ///< Information supplied by OpenTTD. + OpenTTD_SocialIntegration_v2_PluginInfo plugin_info = {}; ///< Information supplied by plugin. + OpenTTD_SocialIntegration_v2_PluginApi plugin_api = {}; ///< API supplied by plugin. + OpenTTD_SocialIntegration_v2_OpenTTDInfo openttd_info = {}; ///< Information supplied by OpenTTD. std::unique_ptr library = nullptr; ///< Library handle. @@ -85,19 +86,19 @@ class SocialIntegrationFileScanner : FileScanner { return false; } - OpenTTD_SocialIntegration_v1_GetInfo getinfo_func = plugin->library->GetFunction("SocialIntegration_v1_GetInfo"); + OpenTTD_SocialIntegration_v2_GetInfo getinfo_func = plugin->library->GetFunction("SocialIntegration_v2_GetInfo"); if (plugin->library->HasError()) { plugin->external.state = SocialIntegrationPlugin::UNSUPPORTED_API; - Debug(misc, 0, "[Social Integration: {}] Failed to find symbol SocialPlugin_v1_GetInfo: {}", basepath, plugin->library->GetLastError()); + Debug(misc, 0, "[Social Integration: {}] Failed to find symbol SocialPlugin_v2_GetInfo: {}", basepath, plugin->library->GetLastError()); return false; } - OpenTTD_SocialIntegration_v1_Init init_func = plugin->library->GetFunction("SocialIntegration_v1_Init"); + OpenTTD_SocialIntegration_v2_Init init_func = plugin->library->GetFunction("SocialIntegration_v2_Init"); if (plugin->library->HasError()) { plugin->external.state = SocialIntegrationPlugin::UNSUPPORTED_API; - Debug(misc, 0, "[Social Integration: {}] Failed to find symbol SocialPlugin_v1_Init: {}", basepath, plugin->library->GetLastError()); + Debug(misc, 0, "[Social Integration: {}] Failed to find symbol SocialPlugin_v2_Init: {}", basepath, plugin->library->GetLastError()); return false; } @@ -122,19 +123,19 @@ class SocialIntegrationFileScanner : FileScanner { auto state = init_func(&plugin->plugin_api, &plugin->openttd_info); switch (state) { - case OTTD_SOCIAL_INTEGRATION_V1_INIT_SUCCESS: + case OTTD_SOCIAL_INTEGRATION_V2_INIT_SUCCESS: plugin->external.state = SocialIntegrationPlugin::RUNNING; Debug(misc, 1, "[Social Integration: {}] Loaded for {}: {} ({})", basepath, plugin->plugin_info.social_platform, plugin->plugin_info.name, plugin->plugin_info.version); return true; - case OTTD_SOCIAL_INTEGRATION_V1_INIT_FAILED: + case OTTD_SOCIAL_INTEGRATION_V2_INIT_FAILED: plugin->external.state = SocialIntegrationPlugin::FAILED; Debug(misc, 0, "[Social Integration: {}] Failed to initialize", basepath); return false; - case OTTD_SOCIAL_INTEGRATION_V1_INIT_PLATFORM_NOT_RUNNING: + case OTTD_SOCIAL_INTEGRATION_V2_INIT_PLATFORM_NOT_RUNNING: plugin->external.state = SocialIntegrationPlugin::PLATFORM_NOT_RUNNING; Debug(misc, 1, "[Social Integration: {}] Failed to initialize: {} is not running", basepath, plugin->plugin_info.social_platform); @@ -211,6 +212,21 @@ void SocialIntegration::RunCallbacks() } } +void SocialIntegration::AddSearchPaths() +{ + for (auto &plugin : _plugins) { + if (plugin->external.state != SocialIntegrationPlugin::RUNNING) continue; + if (plugin->plugin_api.add_search_paths == nullptr) continue; + + char path[1024]; + const char *path_last = path + sizeof(path); + char *last = plugin->plugin_api.add_search_paths(path, path_last); + if (last == nullptr || last == path) continue; + + SetAdditionalSearchPath({path, last}); + } +} + void SocialIntegration::EventEnterMainMenu() { for (auto &plugin : _plugins) { diff --git a/src/social_integration.h b/src/social_integration.h index 7314733e06bd3..f5e1a0de4155e 100644 --- a/src/social_integration.h +++ b/src/social_integration.h @@ -57,6 +57,11 @@ class SocialIntegration { */ static void RunCallbacks(); + /** + * Add search paths that may be provided by the integration library. + */ + static void AddSearchPaths(); + /** * Event: user entered the main menu. */