1 /** @file plugins.h Plugin loader. 2 * 3 * @authors Copyright © 2003-2017 Jaakko Keränen <jaakko.keranen@iki.fi> 4 * @authors Copyright © 2006-2015 Daniel Swanson <danij@dengine.net> 5 * 6 * @par License 7 * GPL: http://www.gnu.org/licenses/gpl.html 8 * 9 * <small>This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License as published by the 11 * Free Software Foundation; either version 2 of the License, or (at your 12 * option) any later version. This program is distributed in the hope that it 13 * will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty 14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General 15 * Public License for more details. You should have received a copy of the GNU 16 * General Public License along with this program; if not, see: 17 * http://www.gnu.org/licenses</small> 18 */ 19 20 #ifndef LIBDOOMSDAY_PLUGINS_H 21 #define LIBDOOMSDAY_PLUGINS_H 22 23 #include <de/str.h> 24 #include <de/rect.h> 25 #include "world/valuetype.h" 26 27 /** 28 * Unique identifier assigned to each plugin during initial startup. 29 * Zero is not a valid ID. 30 */ 31 typedef int pluginid_t; 32 33 typedef int (*pluginfunc_t) (void); 34 typedef int (*hookfunc_t) (int type, int parm, void *data); 35 36 /// Maximum allowed number of plugins. 37 /// @todo Remove fixed size limit. 38 #define MAX_PLUGS 32 39 40 /// Hook types. 41 typedef enum { 42 HOOK_STARTUP = 0, ///< Called ASAP after startup. 43 HOOK_INIT = 1, ///< Called after engine has been initialized. 44 HOOK_DEFS = 2, ///< Called after DEDs have been loaded. 45 HOOK_MAP_CONVERT = 3, ///< Called when a map needs converting. 46 HOOK_TICKER = 4, ///< Called as part of the run loop. 47 HOOK_DEMO_STOP = 5, ///< Called when demo playback completes. 48 HOOK_FINALE_SCRIPT_BEGIN = 6, ///< Called as a script begins. 49 HOOK_FINALE_SCRIPT_STOP = 7, ///< Called as a script stops. 50 HOOK_FINALE_SCRIPT_TICKER = 8, ///< Called each time a script 'thinks'. 51 HOOK_FINALE_EVAL_IF = 9, ///< Called to evaluate an IF conditional statement. 52 HOOK_VIEWPORT_RESHAPE = 10, ///< Called when viewport dimensions change. 53 HOOK_SAVEGAME_CONVERT = 11, ///< Called when a legacy savegame needs converting. 54 HOOK_GAME_INIT = 12, /**< Called when initializing a loaded game. This occurs 55 once all startup resources are loaded but @em before 56 parsing of definitions and processing game data. 57 This is a suitable time for game data conversion. */ 58 HOOK_MAPINFO_CONVERT = 13, ///< Called when map definition data needs converting. 59 60 NUM_HOOK_TYPES 61 } HookType; 62 63 /// Parameters for HOOK_FINALE_EVAL_IF 64 typedef struct { 65 char const *token; 66 dd_bool returnVal; 67 } ddhook_finale_script_evalif_paramaters_t; 68 69 /// Parameters for HOOK_FINALE_SCRIPT_TICKER 70 typedef struct { 71 dd_bool runTick; 72 dd_bool canSkip; 73 } ddhook_finale_script_ticker_paramaters_t; 74 75 /// Parameters for HOOK_VIEWPORT_RESHAPE 76 typedef struct { 77 RectRaw geometry; ///< New/Current. 78 RectRaw oldGeometry; ///< Previous. 79 } ddhook_viewport_reshape_t; 80 81 /// Parameters for HOOK_SAVEGAME_CONVERT 82 typedef struct { 83 Str sourcePath; 84 Str outputPath; 85 Str fallbackGameId; 86 } ddhook_savegame_convert_t; 87 88 /// Parameters for HOOK_MAPINFO_CONVERT 89 typedef struct { 90 Str paths; ///< ';' delimited 91 Str translated; 92 Str translatedCustom; 93 } ddhook_mapinfo_convert_t; 94 95 /// Parameters for DD_NOTIFY_PLAYER_WEAPON_CHANGED 96 typedef struct { 97 int player; 98 int weapon; ///< Number of the weapon. 99 char const *weaponId; ///< Defined in Values (includes power-ups) (UTF-8). 100 } ddnotify_player_weapon_changed_t; 101 102 /// Parameters for DD_NOTIFY_PSPRITE_STATE_CHANGED 103 typedef struct { 104 int player; 105 struct state_s const *state; 106 } ddnotify_psprite_state_changed_t; 107 108 #ifdef __cplusplus 109 110 #include <de/Observers> 111 #include <de/Info> 112 #include "libdoomsday.h" 113 #include "library.h" 114 #include "gameapi.h" 115 116 /** 117 * Routines exported from a game plugin. @ingroup game 118 * 119 * Note that this struct is not part of the game plugin ABI any longer (since 2.1). 120 */ 121 struct GameExports 122 { 123 // Base-level. 124 void (*PreInit) (char const *gameId); 125 void (*PostInit) (void); 126 dd_bool (*TryShutdown) (void); 127 void (*Shutdown) (void); 128 void (*UpdateState) (int step); 129 int (*GetInteger) (int id); 130 void *(*GetPointer) (int id); 131 132 // Networking. 133 int (*NetServerStart) (int before); 134 int (*NetServerStop) (int before); 135 int (*NetConnect) (int before); 136 int (*NetDisconnect) (int before); 137 long int (*NetPlayerEvent) (int playernum, int type, void *data); 138 int (*NetWorldEvent) (int type, int parm, void *data); 139 void (*HandlePacket) (int fromplayer, int type, void *data, 140 size_t length); 141 142 // Tickers. 143 void (*Ticker) (timespan_t ticLength); 144 145 // Responders. 146 int (*FinaleResponder) (void const *ddev); 147 int (*PrivilegedResponder) (struct event_s *ev); 148 int (*Responder) (struct event_s *ev); 149 int (*FallbackResponder) (struct event_s *ev); 150 151 // Refresh. 152 void (*BeginFrame) (void); 153 154 /** 155 * Called at the end of a refresh frame. This is the last chance the game 156 * will have at updating the engine state before rendering of the frame 157 * begins. Once rendering begins, the viewer can still be updated however 158 * any changes will not take effect until the subsequent frame. Therefore 159 * this is the place where games should strive to update the viewer to 160 * ensure latency-free world refresh. 161 */ 162 void (*EndFrame) (void); 163 164 /** 165 * Draw the view port display of the identified console @a player. 166 * The engine will configure a orthographic GL projection in real pixel 167 * dimensions prior to calling this. 168 * 169 * Example subdivision of the game window into four view ports: 170 * <pre> 171 * (0,0)-----------------------. X 172 * | .--------. | | 173 * | | window | | | 174 * | '--------' | | 175 * | port #0 | port #1 | 176 * |-------------------------| 177 * | | | 178 * | | | 179 * | | | 180 * | port #2 | port #3 | 181 * '--------------------(xn-1, yn-1) 182 * Y Game Window 183 * </pre> 184 * 185 * @param port Logical number of this view port. 186 * @param portGeometry Geometry of the view port in real screen pixels. 187 * @param windowGeometry Geometry of the view window within the port, in 188 * real screen pixels. 189 * 190 * @param player Console player number associated with the view port. 191 * @param layer Logical layer identifier for the content to be drawn: 192 * - 0: The bottom-most layer and the one which generally contains the 193 * call to R_RenderPlayerView. 194 * - 1: Displays to be drawn on top of view window (after bordering), 195 * such as the player HUD. 196 */ 197 void (*DrawViewPort) (int port, RectRaw const *portGeometry, 198 RectRaw const *windowGeometry, int player, int layer); 199 200 /** 201 * Draw over-viewport displays covering the whole game window. Typically 202 * graphical user interfaces such as game menus are done here. 203 * 204 * @param windowSize Dimensions of the game window in real screen pixels. 205 */ 206 void (*DrawWindow) (Size2Raw const *windowSize); 207 208 // Miscellaneous. 209 void (*MobjThinker) (void *mobj); 210 coord_t (*MobjFriction) (struct mobj_s const *mobj); // Returns a friction factor. 211 dd_bool (*MobjCheckPositionXYZ) (struct mobj_s *mobj, coord_t x, coord_t y, coord_t z); 212 dd_bool (*MobjTryMoveXYZ) (struct mobj_s *mobj, coord_t x, coord_t y, coord_t z); 213 de::String (*MobjStateAsInfo) (struct mobj_s const *); 214 void (*MobjRestoreState) (struct mobj_s *, de::Info::BlockElement const &stateInfoBlockElement); 215 216 void (*SectorHeightChangeNotification)(int sectorIdx); // Applies necessary checks on objects. 217 218 // Map setup 219 220 /** 221 * Called once a map change (i.e., P_MapChange()) has completed to allow the 222 * game to do any post change finalization it needs to do at this time. 223 */ 224 void (*FinalizeMapChange) (void const *uri); 225 226 /** 227 * Called when trying to assign a value read from the map data (to a 228 * property known to us) that we don't know what to do with. 229 * 230 * (eg the side->toptexture field contains a text string that 231 * we don't understand but the game might). 232 * 233 * @return The action code returned by the game depends on the context. 234 */ 235 int (*HandleMapDataPropertyValue) (uint id, int dtype, int prop, 236 valuetype_t type, void *data); 237 // Post map setup 238 /** 239 * The engine calls this to inform the game of any changes it is 240 * making to map data object to which the game might want to 241 * take further action. 242 */ 243 int (*HandleMapObjectStatusReport) (int code, uint id, int dtype, void *data); 244 }; 245 246 /** 247 * Plugin loader. 248 */ 249 class LIBDOOMSDAY_PUBLIC Plugins 250 { 251 public: 252 DENG2_DEFINE_AUDIENCE2(PublishAPI, void publishAPIToPlugin(Library *)) 253 DENG2_DEFINE_AUDIENCE2(Notification, void pluginSentNotification(int id, void *data)) 254 255 DENG2_ERROR(EntryPointError); 256 257 public: 258 Plugins(); 259 260 void publishAPIs(Library *lib); 261 262 void notify(int notification, void *data); 263 264 /** 265 * Loads all the plugins from the library directory. Note that audio plugins 266 * are not loaded here, they are managed by AudioDriver. 267 */ 268 void loadAll(); 269 270 /** 271 * Unloads all plugins. 272 */ 273 void unloadAll(); 274 275 /** 276 * Change the currently active plugin for the current thread to that attributed 277 * with the given @a id. 278 */ 279 void setActivePluginId(pluginid_t id); 280 281 /** 282 * Returns the unique identifier of the currently active plugin. The currently 283 * active plugin is tracked separately for each thread. 284 */ 285 pluginid_t activePluginId() const; 286 287 /** 288 * Locate the LibraryFile attributed with the given @a id. 289 */ 290 de::LibraryFile const &fileForPlugin(pluginid_t id) const; 291 292 /** 293 * Locate the address of the named, exported procedure in the plugin. 294 */ 295 void *findEntryPoint(pluginid_t pluginId, char const *fn) const; 296 297 bool exchangeGameEntryPoints(pluginid_t pluginId); 298 299 /** 300 * Returns the current game plugin's entrypoints. 301 */ 302 GameExports &gameExports() const; 303 304 public: // Function hooks: ---------------------------------------------------------- 305 306 /** 307 * Describes a function hook. 308 */ 309 struct Hook 310 { 311 /** 312 * Returns @c true if the hook matches @a other. 313 * Note that if the plugin Id of either is not valid then this attribute is 314 * considered @em wild and therefore plugin Ids are ignored when matching. 315 */ 316 bool operator == (Hook const &other) const; 317 inline bool operator != (Hook const &other) const { return !(*this == other); } 318 319 /** 320 * Execute the hook function and return the result. 321 * 322 * @param parm Integer paramater to pass to the hook function. 323 * @param data Pointer paramater to pass to the hook function. 324 * 325 * @return Hook function return value. 326 */ 327 int execute(int parm = 0, void *data = nullptr) const; 328 329 /** 330 * Returns the unique Id attributed to the plugin that registered the hook, 331 * or @c 0 (not valid plugin Id) if a plugin is not attributed. 332 */ 333 pluginid_t pluginId() const; 334 335 private: 336 friend class Plugins; 337 338 HookType _type = NUM_HOOK_TYPES/*invalid type*/; 339 hookfunc_t _function = nullptr; 340 pluginid_t _pluginId = 0/*invalid ID*/; 341 }; 342 343 /** 344 * Returns @c true if one or more hooks of the given @a type is registered. 345 * 346 * @see forAllHooks(), callAllHooks() 347 */ 348 bool hasHook(HookType type) const; 349 350 /** 351 * Add a new @a function hook of the given @a type. 352 */ 353 void addHook(HookType type, hookfunc_t function); 354 355 /** 356 * Remove a @a function hook of the given @a type. 357 */ 358 bool removeHook(HookType type, hookfunc_t function); 359 360 /** 361 * Iterate through the registered Hooks. 362 * 363 * @param func Callback to make for each Hook. 364 * 365 * @see callAllHooks() 366 */ 367 de::LoopResult forAllHooks(HookType type, std::function<de::LoopResult (Hook const &)> func) const; 368 369 /** 370 * Convenient method of executing all hook functions of the given @a type in 371 * registration order, passing the same paramater values to each. 372 * 373 * @param type Hook-type identifier. 374 * @param parm Integer data paramater to pass to the hook function. 375 * @param data Pointer data paramater to pass to the hook function. 376 * 377 * @return Bit zero is set if one or more hooks completed successfully (returned 378 * non-zero). Bit one is set if @em all the hooks completed successfully. 379 * 380 * @see forAllHooks() 381 */ 382 int callAllHooks(HookType type, int parm = 0, void *data = nullptr); 383 384 private: 385 DENG2_PRIVATE(d) 386 }; 387 388 #endif // __cplusplus 389 390 /** 391 * Registers a new hook function. A plugin can call this to add a hook function to be 392 * executed at the time specified by @a type. 393 * 394 * @param type Hook-type identifier. 395 * @param function Function pointer to hook. 396 * 397 * @return @c true if successfully registered. 398 */ 399 LIBDOOMSDAY_EXTERN_C LIBDOOMSDAY_PUBLIC 400 int Plug_AddHook(HookType type, hookfunc_t function); 401 402 /** 403 * Removes a @a function hook from the register. 404 * 405 * @param type Hook-type identifier. 406 * @param function Function pointer to hook. 407 * 408 * @return @c true if found and removed. 409 */ 410 LIBDOOMSDAY_EXTERN_C LIBDOOMSDAY_PUBLIC 411 int Plug_RemoveHook(HookType type, hookfunc_t function); 412 413 /** 414 * Check if there are any hooks of the given @a type registered. 415 * 416 * @param type Hook-type identifier to lookup. 417 * 418 * @return @c true if one or more hooks are registered for given @a type. 419 */ 420 LIBDOOMSDAY_EXTERN_C LIBDOOMSDAY_PUBLIC 421 int Plug_CheckForHook(HookType type); 422 423 /** 424 * Provides a way for plugins (e.g., games) to notify the engine of important events. 425 * 426 * @param notification One of the DD_NOTIFY_* enums. 427 * @param param Additional arguments about the notification, depending on the 428 * notification type. 429 */ 430 LIBDOOMSDAY_EXTERN_C LIBDOOMSDAY_PUBLIC 431 void Plug_Notify(int notification, void *data); 432 433 #endif // LIBDOOMSDAY_PLUGINS_H 434