OpenTTD Source 20241224-master-gf74b0cf984
social_integration.cpp
Go to the documentation of this file.
1/*
2 * This file is part of OpenTTD.
3 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
6 */
7
10#include "stdafx.h"
11
12#include "social_integration.h"
13#include "3rdparty/openttd_social_integration_api/openttd_social_integration_api.h"
14
15#include "debug.h"
16#include "fileio_func.h"
17#include "library_loader.h"
18#include "rev.h"
19#include "string_func.h"
20#include "signature.h"
21
22#include "safeguards.h"
23
28public:
29 InternalSocialIntegrationPlugin(const std::string &filename, const std::string &basepath) : library(nullptr), external(basepath)
30 {
31 openttd_info.openttd_version = _openttd_revision;
32
33 if (!ValidateSignatureFile(fmt::format("{}.sig", filename))) {
35 return;
36 }
37
38 this->library = std::make_unique<LibraryLoader>(filename);
39 }
40
41 OpenTTD_SocialIntegration_v1_PluginInfo plugin_info = {};
42 OpenTTD_SocialIntegration_v1_PluginApi plugin_api = {};
43 OpenTTD_SocialIntegration_v1_OpenTTDInfo openttd_info = {};
44
45 std::unique_ptr<LibraryLoader> library = nullptr;
46
48};
49
50static std::vector<std::unique_ptr<InternalSocialIntegrationPlugin>> _plugins;
51static std::set<std::string> _loaded_social_platform;
52
55public:
56 void Scan()
57 {
58#ifdef _WIN32
59 std::string extension = "-social.dll";
60#elif defined(__APPLE__)
61 std::string extension = "-social.dylib";
62#else
63 std::string extension = "-social.so";
64#endif
65
66 this->FileScanner::Scan(extension, SOCIAL_INTEGRATION_DIR, false);
67 }
68
69 bool AddFile(const std::string &filename, size_t basepath_length, const std::string &) override
70 {
71 std::string basepath = filename.substr(basepath_length);
72 Debug(misc, 1, "[Social Integration: {}] Loading ...", basepath);
73
74 auto &plugin = _plugins.emplace_back(std::make_unique<InternalSocialIntegrationPlugin>(filename, basepath));
75
76 /* Validation failed, so no library was loaded. */
77 if (plugin->library == nullptr) {
78 return false;
79 }
80
81 if (plugin->library->HasError()) {
82 plugin->external.state = SocialIntegrationPlugin::FAILED;
83
84 Debug(misc, 0, "[Social Integration: {}] Failed to load library: {}", basepath, plugin->library->GetLastError());
85 return false;
86 }
87
88 OpenTTD_SocialIntegration_v1_GetInfo getinfo_func = plugin->library->GetFunction("SocialIntegration_v1_GetInfo");
89 if (plugin->library->HasError()) {
90 plugin->external.state = SocialIntegrationPlugin::UNSUPPORTED_API;
91
92 Debug(misc, 0, "[Social Integration: {}] Failed to find symbol SocialPlugin_v1_GetInfo: {}", basepath, plugin->library->GetLastError());
93 return false;
94 }
95
96 OpenTTD_SocialIntegration_v1_Init init_func = plugin->library->GetFunction("SocialIntegration_v1_Init");
97 if (plugin->library->HasError()) {
98 plugin->external.state = SocialIntegrationPlugin::UNSUPPORTED_API;
99
100 Debug(misc, 0, "[Social Integration: {}] Failed to find symbol SocialPlugin_v1_Init: {}", basepath, plugin->library->GetLastError());
101 return false;
102 }
103
104 getinfo_func(&plugin->plugin_info);
105 /* Setup the information for the outside world to see. */
106 plugin->external.social_platform = plugin->plugin_info.social_platform;
107 plugin->external.name = plugin->plugin_info.name;
108 plugin->external.version = plugin->plugin_info.version;
109
110 /* Lowercase the string for comparison. */
111 std::string lc_social_platform = plugin->plugin_info.social_platform;
112 strtolower(lc_social_platform);
113
114 /* Prevent more than one plugin for a certain Social Platform to be loaded, as that never ends well. */
115 if (_loaded_social_platform.find(lc_social_platform) != _loaded_social_platform.end()) {
116 plugin->external.state = SocialIntegrationPlugin::DUPLICATE;
117
118 Debug(misc, 0, "[Social Integration: {}] Another plugin for {} is already loaded", basepath, plugin->plugin_info.social_platform);
119 return false;
120 }
121 _loaded_social_platform.insert(lc_social_platform);
122
123 auto state = init_func(&plugin->plugin_api, &plugin->openttd_info);
124 switch (state) {
125 case OTTD_SOCIAL_INTEGRATION_V1_INIT_SUCCESS:
126 plugin->external.state = SocialIntegrationPlugin::RUNNING;
127
128 Debug(misc, 1, "[Social Integration: {}] Loaded for {}: {} ({})", basepath, plugin->plugin_info.social_platform, plugin->plugin_info.name, plugin->plugin_info.version);
129 return true;
130
131 case OTTD_SOCIAL_INTEGRATION_V1_INIT_FAILED:
132 plugin->external.state = SocialIntegrationPlugin::FAILED;
133
134 Debug(misc, 0, "[Social Integration: {}] Failed to initialize", basepath);
135 return false;
136
137 case OTTD_SOCIAL_INTEGRATION_V1_INIT_PLATFORM_NOT_RUNNING:
138 plugin->external.state = SocialIntegrationPlugin::PLATFORM_NOT_RUNNING;
139
140 Debug(misc, 1, "[Social Integration: {}] Failed to initialize: {} is not running", basepath, plugin->plugin_info.social_platform);
141 return false;
142
143 default:
144 NOT_REACHED();
145 }
146 }
147};
148
149std::vector<SocialIntegrationPlugin *> SocialIntegration::GetPlugins()
150{
151 std::vector<SocialIntegrationPlugin *> plugins;
152
153 for (auto &plugin : _plugins) {
154 plugins.push_back(&plugin->external);
155 }
156
157 return plugins;
158}
159
161{
163 fs.Scan();
164}
165
172template <typename T, typename... Ts>
173static void PluginCall(std::unique_ptr<InternalSocialIntegrationPlugin> &plugin, T func, Ts... args)
174{
175 if (plugin->external.state != SocialIntegrationPlugin::RUNNING) {
176 return;
177 }
178
179 if (func != nullptr) {
180 func(args...);
181 }
182}
183
185{
186 for (auto &plugin : _plugins) {
187 PluginCall(plugin, plugin->plugin_api.shutdown);
188 }
189
190 _plugins.clear();
192}
193
195{
196 for (auto &plugin : _plugins) {
197 if (plugin->external.state != SocialIntegrationPlugin::RUNNING) {
198 continue;
199 }
200
201 if (plugin->plugin_api.run_callbacks != nullptr) {
202 if (!plugin->plugin_api.run_callbacks()) {
203 Debug(misc, 1, "[Social Plugin: {}] Requested to be unloaded", plugin->external.basepath);
204
205 _loaded_social_platform.erase(plugin->plugin_info.social_platform);
206 plugin->external.state = SocialIntegrationPlugin::UNLOADED;
207 PluginCall(plugin, plugin->plugin_api.shutdown);
208 }
209 }
210 }
211}
212
214{
215 for (auto &plugin : _plugins) {
216 PluginCall(plugin, plugin->plugin_api.event_enter_main_menu);
217 }
218}
219
220void SocialIntegration::EventEnterScenarioEditor(uint map_width, uint map_height)
221{
222 for (auto &plugin : _plugins) {
223 PluginCall(plugin, plugin->plugin_api.event_enter_scenario_editor, map_width, map_height);
224 }
225}
226
227void SocialIntegration::EventEnterSingleplayer(uint map_width, uint map_height)
228{
229 for (auto &plugin : _plugins) {
230 PluginCall(plugin, plugin->plugin_api.event_enter_singleplayer, map_width, map_height);
231 }
232}
233
234void SocialIntegration::EventEnterMultiplayer(uint map_width, uint map_height)
235{
236 for (auto &plugin : _plugins) {
237 PluginCall(plugin, plugin->plugin_api.event_enter_multiplayer, map_width, map_height);
238 }
239}
240
242{
243 for (auto &plugin : _plugins) {
244 PluginCall(plugin, plugin->plugin_api.event_joining_multiplayer);
245 }
246}
Helper for scanning for files with a given name.
Definition fileio_func.h:37
uint Scan(std::string_view extension, Subdirectory sd, bool tars=true, bool recursive=true)
Scan for files with the given extension in the given search path.
Definition fileio.cpp:1114
Container to track information per plugin.
std::unique_ptr< LibraryLoader > library
Library handle.
SocialIntegrationPlugin external
Information of the plugin to be used by other parts of our codebase.
OpenTTD_SocialIntegration_v1_OpenTTDInfo openttd_info
Information supplied by OpenTTD.
OpenTTD_SocialIntegration_v1_PluginApi plugin_api
API supplied by plugin.
OpenTTD_SocialIntegration_v1_PluginInfo plugin_info
Information supplied by plugin.
Helper for scanning for files with SocialIntegration as extension.
bool AddFile(const std::string &filename, size_t basepath_length, const std::string &) override
Add a file with the given filename.
@ PLATFORM_NOT_RUNNING
The plugin failed to initialize because the Social Platform is not running.
@ UNSUPPORTED_API
The plugin does not support the current API version.
@ RUNNING
The plugin is successfully loaded and running.
@ FAILED
The plugin failed to initialize.
@ DUPLICATE
Another plugin of the same Social Platform is already loaded.
@ INVALID_SIGNATURE
The signature of the plugin is invalid.
@ UNLOADED
The plugin is unloaded upon request.
State state
Result of the plugin's init function.
static void EventEnterScenarioEditor(uint map_width, uint map_height)
Event: user entered the Scenario Editor.
static void EventEnterSingleplayer(uint map_width, uint map_height)
Event: user entered a singleplayer game.
static std::vector< SocialIntegrationPlugin * > GetPlugins()
Get the list of loaded social integration plugins.
static void RunCallbacks()
Allow any social integration library to handle their own events.
static void EventEnterMultiplayer(uint map_width, uint map_height)
Event: user entered a multiplayer game.
static void Shutdown()
Shutdown the social integration system, and all social integration plugins that are loaded.
static void EventEnterMainMenu()
Event: user entered the main menu.
static void EventJoiningMultiplayer()
Event: user is joining a multiplayer game.
static void Initialize()
Initialize the social integration system, loading any social integration plugins that are available.
Functions related to debugging.
#define Debug(category, level, format_string,...)
Ouptut a line of debugging information.
Definition debug.h:37
Functions for Standard In/Out file operations.
@ SOCIAL_INTEGRATION_DIR
Subdirectory for all social integration plugins.
Functions/types related to loading libraries dynamically.
declaration of OTTD revision dependent variables
A number of safeguards to prevent using unsafe methods.
bool ValidateSignatureFile(const std::string &filename)
Validate that the signatures mentioned in the signature file are matching the files in question.
Routines to validate signature files.
static void PluginCall(std::unique_ptr< InternalSocialIntegrationPlugin > &plugin, T func, Ts... args)
Wrapper to call a function pointer of a plugin if it isn't a nullptr.
static std::vector< std::unique_ptr< InternalSocialIntegrationPlugin > > _plugins
List of loaded plugins.
static std::set< std::string > _loaded_social_platform
List of Social Platform plugins already loaded. Used to prevent loading a plugin for the same Social ...
Interface definitions for game to report/respond to social integration.
Definition of base types and functions in a cross-platform compatible way.
Functions related to low-level strings.