1 /* 2 * Copyright (C) 2014-2018 Team Kodi 3 * This file is part of Kodi - https://kodi.tv 4 * 5 * SPDX-License-Identifier: GPL-2.0-or-later 6 * See LICENSES/README.md for more information. 7 */ 8 9 #pragma once 10 11 #include "../AddonBase.h" 12 #include "../c-api/addon-instance/game.h" 13 14 #ifdef __cplusplus 15 16 namespace kodi 17 { 18 namespace addon 19 { 20 21 //============================================================================== 22 /// @addtogroup cpp_kodi_addon_game 23 /// 24 /// To use on Libretro and for stand-alone games or emulators that does not use 25 /// the Libretro API. 26 /// 27 /// Possible examples could be, Nvidia GameStream via Limelight or WINE capture 28 /// could possible through the Game API. 29 /// 30 31 //============================================================================== 32 /// @defgroup cpp_kodi_addon_game_Defs Definitions, structures and enumerators 33 /// @ingroup cpp_kodi_addon_game 34 /// @brief **Game add-on instance definition values** 35 /// 36 37 //============================================================================== 38 /// @defgroup cpp_kodi_addon_game_Defs_InputTypes_GameControllerLayout class GameControllerLayout 39 /// @ingroup cpp_kodi_addon_game_Defs_InputTypes 40 /// @brief Data of layouts for known controllers. 41 /// 42 /// Used on @ref kodi::addon::CInstanceGame::SetControllerLayouts(). 43 ///@{ 44 class GameControllerLayout 45 { 46 public: 47 /*! @cond PRIVATE */ 48 explicit GameControllerLayout() = default; GameControllerLayout(const game_controller_layout & layout)49 GameControllerLayout(const game_controller_layout& layout) 50 { 51 controller_id = layout.controller_id; 52 provides_input = layout.provides_input; 53 for (unsigned int i = 0; i < layout.digital_button_count; ++i) 54 digital_buttons.push_back(layout.digital_buttons[i]); 55 for (unsigned int i = 0; i < layout.analog_button_count; ++i) 56 analog_buttons.push_back(layout.analog_buttons[i]); 57 for (unsigned int i = 0; i < layout.analog_stick_count; ++i) 58 analog_sticks.push_back(layout.analog_sticks[i]); 59 for (unsigned int i = 0; i < layout.accelerometer_count; ++i) 60 accelerometers.push_back(layout.accelerometers[i]); 61 for (unsigned int i = 0; i < layout.key_count; ++i) 62 keys.push_back(layout.keys[i]); 63 for (unsigned int i = 0; i < layout.rel_pointer_count; ++i) 64 rel_pointers.push_back(layout.rel_pointers[i]); 65 for (unsigned int i = 0; i < layout.abs_pointer_count; ++i) 66 abs_pointers.push_back(layout.abs_pointers[i]); 67 for (unsigned int i = 0; i < layout.motor_count; ++i) 68 motors.push_back(layout.motors[i]); 69 } 70 /*! @endcond */ 71 72 /// @brief Controller identifier. 73 std::string controller_id; 74 75 /// @brief Provides input. 76 /// 77 /// False for multitaps 78 bool provides_input; 79 80 /// @brief Digital buttons. 81 std::vector<std::string> digital_buttons; 82 83 /// @brief Analog buttons. 84 std::vector<std::string> analog_buttons; 85 86 /// @brief Analog sticks. 87 std::vector<std::string> analog_sticks; 88 89 /// @brief Accelerometers. 90 std::vector<std::string> accelerometers; 91 92 /// @brief Keys. 93 std::vector<std::string> keys; 94 95 /// @brief Relative pointers. 96 std::vector<std::string> rel_pointers; 97 98 /// @brief Absolute pointers. 99 std::vector<std::string> abs_pointers; 100 101 /// @brief Motors. 102 std::vector<std::string> motors; 103 }; 104 ///@} 105 //------------------------------------------------------------------------------ 106 107 //============================================================================== 108 /// @addtogroup cpp_kodi_addon_game 109 /// @brief @cpp_class{ kodi::addon::CInstanceGame } 110 /// **Game add-on instance**\n 111 /// This class provides the basic game processing system for use as an add-on in 112 /// Kodi. 113 /// 114 /// This class is created at addon by Kodi. 115 /// 116 class ATTRIBUTE_HIDDEN CInstanceGame : public IAddonInstance 117 { 118 public: 119 //============================================================================ 120 /// @defgroup cpp_kodi_addon_game_Base 1. Basic functions 121 /// @ingroup cpp_kodi_addon_game 122 /// @brief **Functions to manage the addon and get basic information about it** 123 /// 124 ///@{ 125 126 //============================================================================ 127 /// @brief Game class constructor 128 /// 129 /// Used by an add-on that only supports only Game and only in one instance. 130 /// 131 /// This class is created at addon by Kodi. 132 /// 133 /// 134 /// -------------------------------------------------------------------------- 135 /// 136 /// 137 /// **Here's example about the use of this:** 138 /// ~~~~~~~~~~~~~{.cpp} 139 /// #include <kodi/addon-instance/Game.h> 140 /// ... 141 /// 142 /// class ATTRIBUTE_HIDDEN CGameExample 143 /// : public kodi::addon::CAddonBase, 144 /// public kodi::addon::CInstanceGame 145 /// { 146 /// public: 147 /// CGameExample() 148 /// { 149 /// } 150 /// 151 /// virtual ~CGameExample(); 152 /// { 153 /// } 154 /// 155 /// ... 156 /// }; 157 /// 158 /// ADDONCREATOR(CGameExample) 159 /// ~~~~~~~~~~~~~ 160 /// CInstanceGame()161 CInstanceGame() : IAddonInstance(ADDON_INSTANCE_GAME, GetKodiTypeVersion(ADDON_INSTANCE_GAME)) 162 { 163 if (CAddonBase::m_interface->globalSingleInstance != nullptr) 164 throw std::logic_error("kodi::addon::CInstanceGame: Creation of more as one in single " 165 "instance way is not allowed!"); 166 167 SetAddonStruct(CAddonBase::m_interface->firstKodiInstance); 168 CAddonBase::m_interface->globalSingleInstance = this; 169 } 170 //---------------------------------------------------------------------------- 171 172 //============================================================================ 173 /// @brief Destructor 174 /// 175 ~CInstanceGame() override = default; 176 //---------------------------------------------------------------------------- 177 178 //============================================================================ 179 /// @brief **Callback to Kodi Function**\n 180 /// The path of the game client being loaded. 181 /// 182 /// @return the used game client Dll path 183 /// 184 /// @remarks Only called from addon itself 185 /// GameClientDllPath()186 std::string GameClientDllPath() const { return m_instanceData->props->game_client_dll_path; } 187 //---------------------------------------------------------------------------- 188 189 //============================================================================ 190 /// @brief **Callback to Kodi Function**\n 191 /// Paths to proxy DLLs used to load the game client. 192 /// 193 /// @param[out] paths vector list to store available dll paths 194 /// @return true if success and dll paths present 195 /// 196 /// @remarks Only called from addon itself 197 /// ProxyDllPaths(std::vector<std::string> & paths)198 bool ProxyDllPaths(std::vector<std::string>& paths) 199 { 200 for (unsigned int i = 0; i < m_instanceData->props->proxy_dll_count; ++i) 201 { 202 if (m_instanceData->props->proxy_dll_paths[i] != nullptr) 203 paths.push_back(m_instanceData->props->proxy_dll_paths[i]); 204 } 205 return !paths.empty(); 206 } 207 //---------------------------------------------------------------------------- 208 209 //============================================================================ 210 /// @brief **Callback to Kodi Function**\n 211 /// The "system" directories of the frontend. 212 /// 213 /// These directories can be used to store system-specific ROMs such as 214 /// BIOSes, configuration data, etc. 215 /// 216 /// @return the used resource directory 217 /// 218 /// @remarks Only called from addon itself 219 /// ResourceDirectories(std::vector<std::string> & dirs)220 bool ResourceDirectories(std::vector<std::string>& dirs) 221 { 222 for (unsigned int i = 0; i < m_instanceData->props->resource_directory_count; ++i) 223 { 224 if (m_instanceData->props->resource_directories[i] != nullptr) 225 dirs.push_back(m_instanceData->props->resource_directories[i]); 226 } 227 return !dirs.empty(); 228 } 229 //---------------------------------------------------------------------------- 230 231 //============================================================================ 232 /// @brief **Callback to Kodi Function**\n 233 /// The writable directory of the frontend. 234 /// 235 /// This directory can be used to store SRAM, memory cards, high scores, 236 /// etc, if the game client cannot use the regular memory interface, 237 /// GetMemoryData(). 238 /// 239 /// @return the used profile directory 240 /// 241 /// @remarks Only called from addon itself 242 /// ProfileDirectory()243 std::string ProfileDirectory() const { return m_instanceData->props->profile_directory; } 244 //---------------------------------------------------------------------------- 245 246 //============================================================================ 247 /// @brief **Callback to Kodi Function**\n 248 /// The value of the <supports_vfs> property from addon.xml. 249 /// 250 /// @return true if VFS is supported 251 /// 252 /// @remarks Only called from addon itself 253 /// SupportsVFS()254 bool SupportsVFS() const { return m_instanceData->props->supports_vfs; } 255 //---------------------------------------------------------------------------- 256 257 //============================================================================ 258 /// @brief **Callback to Kodi Function**\n 259 /// The extensions in the <extensions> property from addon.xml. 260 /// 261 /// @param[out] extensions vector list to store available extension 262 /// @return true if success and extensions present 263 /// 264 /// @remarks Only called from addon itself 265 /// Extensions(std::vector<std::string> & extensions)266 bool Extensions(std::vector<std::string>& extensions) 267 { 268 for (unsigned int i = 0; i < m_instanceData->props->extension_count; ++i) 269 { 270 if (m_instanceData->props->extensions[i] != nullptr) 271 extensions.push_back(m_instanceData->props->extensions[i]); 272 } 273 return !extensions.empty(); 274 } 275 //---------------------------------------------------------------------------- 276 277 ///@} 278 279 //--==----==----==----==----==----==----==----==----==----==----==----==----==-- 280 281 //============================================================================ 282 /// 283 /// @defgroup cpp_kodi_addon_game_Operation 2. Game operations 284 /// @ingroup cpp_kodi_addon_game 285 /// @brief **Game operations** 286 /// 287 /// These are mandatory functions for using this addon to get the available 288 /// channels. 289 /// 290 /// 291 ///--------------------------------------------------------------------------- 292 /// 293 /// **Game operation parts in interface:**\n 294 /// Copy this to your project and extend with your parts or leave functions 295 /// complete away where not used or supported. 296 /// 297 /// @copydetails cpp_kodi_addon_game_Operation_header_addon_auto_check 298 /// @copydetails cpp_kodi_addon_game_Operation_source_addon_auto_check 299 /// 300 ///@{ 301 302 //============================================================================ 303 /// @brief Load a game 304 /// 305 /// @param[in] url The URL to load 306 /// @return the error, or @ref GAME_ERROR_NO_ERROR if the game was loaded 307 /// LoadGame(const std::string & url)308 virtual GAME_ERROR LoadGame(const std::string& url) 309 { 310 return GAME_ERROR_NOT_IMPLEMENTED; 311 } 312 //---------------------------------------------------------------------------- 313 314 //============================================================================ 315 /// @brief Load a game that requires multiple files 316 /// 317 /// @param[in] type The game type 318 /// @param[in] urls An array of urls 319 /// @return the error, or @ref GAME_ERROR_NO_ERROR if the game was loaded 320 /// LoadGameSpecial(SPECIAL_GAME_TYPE type,const std::vector<std::string> & urls)321 virtual GAME_ERROR LoadGameSpecial(SPECIAL_GAME_TYPE type, const std::vector<std::string>& urls) 322 { 323 return GAME_ERROR_NOT_IMPLEMENTED; 324 } 325 //---------------------------------------------------------------------------- 326 327 //============================================================================ 328 /// @brief Begin playing without a game file 329 /// 330 /// If the add-on supports standalone mode, it must add the <supports_standalone> 331 /// tag to the extension point in addon.xml: 332 /// 333 /// <supports_no_game>false</supports_no_game> 334 /// 335 /// @return the error, or @ref GAME_ERROR_NO_ERROR if the game add-on was loaded 336 /// LoadStandalone()337 virtual GAME_ERROR LoadStandalone() 338 { 339 return GAME_ERROR_NOT_IMPLEMENTED; 340 } 341 //---------------------------------------------------------------------------- 342 343 //============================================================================ 344 /// @brief Unload the current game 345 /// 346 /// Unloads a currently loaded game 347 /// 348 /// @return the error, or @ref GAME_ERROR_NO_ERROR if the game was unloaded 349 /// UnloadGame()350 virtual GAME_ERROR UnloadGame() 351 { 352 return GAME_ERROR_NOT_IMPLEMENTED; 353 } 354 //---------------------------------------------------------------------------- 355 356 //============================================================================ 357 /// @brief Get timing information about the loaded game 358 /// 359 /// @param[out] timing_info The info structure to fill 360 /// 361 /// @return the error, or @ref GAME_ERROR_NO_ERROR if info was filled 362 /// GetGameTiming(game_system_timing & timing_info)363 virtual GAME_ERROR GetGameTiming(game_system_timing& timing_info) 364 { 365 return GAME_ERROR_NOT_IMPLEMENTED; 366 } 367 //---------------------------------------------------------------------------- 368 369 //============================================================================ 370 /// @brief Get region of the loaded game 371 /// 372 /// @return the region, or @ref GAME_REGION_UNKNOWN if unknown or no game is loaded 373 /// GetRegion()374 virtual GAME_REGION GetRegion() 375 { 376 return GAME_REGION_UNKNOWN; 377 } 378 //---------------------------------------------------------------------------- 379 380 //============================================================================ 381 /// @brief Return true if the client requires the frontend to provide a game loop 382 /// 383 /// The game loop is a thread that calls RunFrame() in a loop at a rate 384 /// determined by the playback speed and the client's FPS. 385 /// 386 /// @return true if the frontend should provide a game loop, false otherwise 387 /// RequiresGameLoop()388 virtual bool RequiresGameLoop() 389 { 390 return false; 391 } 392 //---------------------------------------------------------------------------- 393 394 //============================================================================ 395 /// @brief Run a single frame for add-ons that use a game loop 396 /// 397 /// @return the error, or @ref GAME_ERROR_NO_ERROR if there was no error 398 /// RunFrame()399 virtual GAME_ERROR RunFrame() 400 { 401 return GAME_ERROR_NOT_IMPLEMENTED; 402 } 403 //---------------------------------------------------------------------------- 404 405 //============================================================================ 406 /// @brief Reset the current game 407 /// 408 /// @return the error, or @ref GAME_ERROR_NO_ERROR if the game was reset 409 /// Reset()410 virtual GAME_ERROR Reset() 411 { 412 return GAME_ERROR_NOT_IMPLEMENTED; 413 } 414 //---------------------------------------------------------------------------- 415 416 //========================================================================== 417 /// @brief **Callback to Kodi Function**\n 418 /// Requests the frontend to stop the current game 419 /// 420 /// @remarks Only called from addon itself 421 /// CloseGame(void)422 void CloseGame(void) { m_instanceData->toKodi->CloseGame(m_instanceData->toKodi->kodiInstance); } 423 //---------------------------------------------------------------------------- 424 425 //============================================================================ 426 /// @defgroup cpp_kodi_addon_game_Operation_CStream Class: CStream 427 /// @ingroup cpp_kodi_addon_game_Operation 428 /// @brief @cpp_class{ kodi::addon::CInstanceGame::CStream } 429 /// **Game stream handler** 430 /// 431 /// This class will be integrated into the addon, which can then open it if 432 /// necessary for the processing of an audio or video stream. 433 /// 434 /// 435 /// @note Callback to Kodi class 436 ///@{ 437 class CStream 438 { 439 public: 440 CStream() = default; 441 CStream(const game_stream_properties & properties)442 CStream(const game_stream_properties& properties) 443 { 444 Open(properties); 445 } 446 ~CStream()447 ~CStream() 448 { 449 Close(); 450 } 451 452 //========================================================================== 453 /// @ingroup cpp_kodi_addon_game_Operation_CStream 454 /// @brief Create a stream for gameplay data 455 /// 456 /// @param[in] properties The stream properties 457 /// @return A stream handle, or `nullptr` on failure 458 /// 459 /// @remarks Only called from addon itself 460 /// Open(const game_stream_properties & properties)461 bool Open(const game_stream_properties& properties) 462 { 463 if (!CAddonBase::m_interface->globalSingleInstance) 464 return false; 465 466 if (m_handle) 467 { 468 kodi::Log(ADDON_LOG_INFO, "kodi::addon::CInstanceGame::CStream already becomes reopened"); 469 Close(); 470 } 471 472 AddonToKodiFuncTable_Game& cb = 473 *static_cast<CInstanceGame*>(CAddonBase::m_interface->globalSingleInstance) 474 ->m_instanceData->toKodi; 475 m_handle = cb.OpenStream(cb.kodiInstance, &properties); 476 return m_handle != nullptr; 477 } 478 //-------------------------------------------------------------------------- 479 480 //========================================================================== 481 /// @ingroup cpp_kodi_addon_game_Operation_CStream 482 /// @brief Free the specified stream 483 /// 484 /// @remarks Only called from addon itself 485 /// Close()486 void Close() 487 { 488 if (!m_handle || !CAddonBase::m_interface->globalSingleInstance) 489 return; 490 491 AddonToKodiFuncTable_Game& cb = 492 *static_cast<CInstanceGame*>(CAddonBase::m_interface->globalSingleInstance) 493 ->m_instanceData->toKodi; 494 cb.CloseStream(cb.kodiInstance, m_handle); 495 m_handle = nullptr; 496 } 497 //-------------------------------------------------------------------------- 498 499 //========================================================================== 500 /// @ingroup cpp_kodi_addon_game_Operation_CStream 501 /// @brief Get a buffer for zero-copy stream data 502 /// 503 /// @param[in] width The framebuffer width, or 0 for no width specified 504 /// @param[in] height The framebuffer height, or 0 for no height specified 505 /// @param[out] buffer The buffer, or unmodified if false is returned 506 /// @return True if buffer was set, false otherwise 507 /// 508 /// @note If this returns true, buffer must be freed using @ref ReleaseBuffer(). 509 /// 510 /// @remarks Only called from addon itself 511 /// GetBuffer(unsigned int width,unsigned int height,game_stream_buffer & buffer)512 bool GetBuffer(unsigned int width, unsigned int height, game_stream_buffer& buffer) 513 { 514 if (!m_handle || !CAddonBase::m_interface->globalSingleInstance) 515 return false; 516 517 AddonToKodiFuncTable_Game& cb = 518 *static_cast<CInstanceGame*>(CAddonBase::m_interface->globalSingleInstance) 519 ->m_instanceData->toKodi; 520 return cb.GetStreamBuffer(cb.kodiInstance, m_handle, width, height, &buffer); 521 } 522 //-------------------------------------------------------------------------- 523 524 //========================================================================== 525 /// @ingroup cpp_kodi_addon_game_Operation_CStream 526 /// @brief Add a data packet to a stream 527 /// 528 /// @param[in] packet The data packet 529 /// 530 /// @remarks Only called from addon itself 531 /// AddData(const game_stream_packet & packet)532 void AddData(const game_stream_packet& packet) 533 { 534 if (!m_handle || !CAddonBase::m_interface->globalSingleInstance) 535 return; 536 537 AddonToKodiFuncTable_Game& cb = 538 *static_cast<CInstanceGame*>(CAddonBase::m_interface->globalSingleInstance) 539 ->m_instanceData->toKodi; 540 cb.AddStreamData(cb.kodiInstance, m_handle, &packet); 541 } 542 //-------------------------------------------------------------------------- 543 544 //========================================================================== 545 /// @ingroup cpp_kodi_addon_game_Operation_CStream 546 /// @brief Free an allocated buffer 547 /// 548 /// @param[in] buffer The buffer returned from GetStreamBuffer() 549 /// 550 /// @remarks Only called from addon itself 551 /// ReleaseBuffer(game_stream_buffer & buffer)552 void ReleaseBuffer(game_stream_buffer& buffer) 553 { 554 if (!m_handle || !CAddonBase::m_interface->globalSingleInstance) 555 return; 556 557 AddonToKodiFuncTable_Game& cb = 558 *static_cast<CInstanceGame*>(CAddonBase::m_interface->globalSingleInstance) 559 ->m_instanceData->toKodi; 560 cb.ReleaseStreamBuffer(cb.kodiInstance, m_handle, &buffer); 561 } 562 //-------------------------------------------------------------------------- 563 564 //========================================================================== 565 /// @ingroup cpp_kodi_addon_game_Operation_CStream 566 /// @brief To check stream open was OK, e.g. after use of constructor 567 /// 568 /// @return true if stream was successfully opened 569 /// 570 /// @remarks Only called from addon itself 571 /// IsOpen()572 bool IsOpen() const { return m_handle != nullptr; } 573 //-------------------------------------------------------------------------- 574 575 private: 576 KODI_GAME_STREAM_HANDLE m_handle = nullptr; 577 }; 578 ///@} 579 580 ///@} 581 582 //--==----==----==----==----==----==----==----==----==----==----==----==----==-- 583 584 //============================================================================ 585 /// 586 /// @defgroup cpp_kodi_addon_game_HardwareRendering 3. Hardware rendering operations 587 /// @ingroup cpp_kodi_addon_game 588 /// @brief **Hardware rendering operations** 589 /// 590 /// 591 ///--------------------------------------------------------------------------- 592 /// 593 /// **Hardware rendering operation parts in interface:**\n 594 /// Copy this to your project and extend with your parts or leave functions 595 /// complete away where not used or supported. 596 /// 597 /// @copydetails cpp_kodi_addon_game_HardwareRendering_header_addon_auto_check 598 /// @copydetails cpp_kodi_addon_game_HardwareRendering_source_addon_auto_check 599 /// 600 ///@{ 601 602 //============================================================================ 603 /// @brief Invalidates the current HW context and reinitializes GPU resources 604 /// 605 /// Any GL state is lost, and must not be deinitialized explicitly. 606 /// 607 /// @return the error, or @ref GAME_ERROR_NO_ERROR if the HW context was reset 608 /// HwContextReset()609 virtual GAME_ERROR HwContextReset() 610 { 611 return GAME_ERROR_NOT_IMPLEMENTED; 612 } 613 //---------------------------------------------------------------------------- 614 615 //============================================================================ 616 /// @brief Called before the context is destroyed 617 /// 618 /// Resources can be deinitialized at this step. 619 /// 620 /// @return the error, or @ref GAME_ERROR_NO_ERROR if the HW context was destroyed 621 /// HwContextDestroy()622 virtual GAME_ERROR HwContextDestroy() 623 { 624 return GAME_ERROR_NOT_IMPLEMENTED; 625 } 626 627 //============================================================================ 628 /// @brief **Callback to Kodi Function**<br>Get a symbol from the hardware context 629 /// 630 /// @param[in] sym The symbol's name 631 /// 632 /// @return A function pointer for the specified symbol 633 /// 634 /// @remarks Only called from addon itself 635 /// HwGetProcAddress(const char * sym)636 game_proc_address_t HwGetProcAddress(const char* sym) 637 { 638 return m_instanceData->toKodi->HwGetProcAddress(m_instanceData->toKodi->kodiInstance, sym); 639 } 640 //---------------------------------------------------------------------------- 641 642 ///@} 643 644 //--==----==----==----==----==----==----==----==----==----==----==----==----==-- 645 646 //============================================================================ 647 /// @defgroup cpp_kodi_addon_game_InputOperations 4. Input operations 648 /// @ingroup cpp_kodi_addon_game 649 /// @brief **Input operations** 650 /// 651 /// 652 ///--------------------------------------------------------------------------- 653 /// 654 /// **Hardware rendering operation parts in interface:**\n 655 /// Copy this to your project and extend with your parts or leave functions 656 /// complete away where not used or supported. 657 /// 658 /// @copydetails cpp_kodi_addon_game_InputOperations_header_addon_auto_check 659 /// @copydetails cpp_kodi_addon_game_InputOperations_source_addon_auto_check 660 /// 661 ///@{ 662 663 //============================================================================ 664 /// @brief Check if input is accepted for a feature on the controller 665 /// 666 /// If only a subset of the controller profile is used, this can return false 667 /// for unsupported features to not absorb their input. 668 /// 669 /// If the entire controller profile is used, this should always return true. 670 /// 671 /// @param[in] controller_id The ID of the controller profile 672 /// @param[in] feature_name The name of a feature in that profile 673 /// @return true if input is accepted for the feature, false otherwise 674 /// HasFeature(const std::string & controller_id,const std::string & feature_name)675 virtual bool HasFeature(const std::string& controller_id, const std::string& feature_name) 676 { 677 return false; 678 } 679 //---------------------------------------------------------------------------- 680 681 //============================================================================ 682 /// @brief Get the input topology that specifies which controllers can be connected 683 /// 684 /// @return The input topology, or null to use the default 685 /// 686 /// If this returns non-null, topology must be freed using FreeTopology(). 687 /// 688 /// If this returns null, the topology will default to a single port that can 689 /// accept all controllers imported by addon.xml. The port ID is set to 690 /// the @ref DEFAULT_PORT_ID constant. 691 /// GetTopology()692 virtual game_input_topology* GetTopology() 693 { 694 return nullptr; 695 } 696 //---------------------------------------------------------------------------- 697 698 //============================================================================ 699 /// @brief Free the topology's resources 700 /// 701 /// @param[in] topology The topology returned by GetTopology() 702 /// FreeTopology(game_input_topology * topology)703 virtual void FreeTopology(game_input_topology* topology) 704 { 705 } 706 //---------------------------------------------------------------------------- 707 708 //============================================================================ 709 /// @brief Set the layouts for known controllers 710 /// 711 /// @param[in] controllers The controller layouts 712 /// 713 /// After loading the input topology, the frontend will call this with 714 /// controller layouts for all controllers discovered in the topology. 715 /// SetControllerLayouts(const std::vector<kodi::addon::GameControllerLayout> & controllers)716 virtual void SetControllerLayouts(const std::vector<kodi::addon::GameControllerLayout>& controllers) 717 { 718 } 719 //---------------------------------------------------------------------------- 720 721 //============================================================================ 722 /// @brief Enable/disable keyboard input using the specified controller 723 /// 724 /// @param[in] enable True to enable input, false otherwise 725 /// @param[in] controller_id The controller ID if enabling, or unused if disabling 726 /// 727 /// @return True if keyboard input was enabled, false otherwise 728 /// EnableKeyboard(bool enable,const std::string & controller_id)729 virtual bool EnableKeyboard(bool enable, const std::string& controller_id) 730 { 731 return false; 732 } 733 //---------------------------------------------------------------------------- 734 735 //============================================================================ 736 /// @brief Enable/disable mouse input using the specified controller 737 /// 738 /// @param[in] enable True to enable input, false otherwise 739 /// @param[in] controller_id The controller ID if enabling, or unused if disabling 740 /// 741 /// @return True if mouse input was enabled, false otherwise 742 /// EnableMouse(bool enable,const std::string & controller_id)743 virtual bool EnableMouse(bool enable, const std::string& controller_id) 744 { 745 return false; 746 } 747 //-------------------------------------------------------------------------- 748 749 //========================================================================== 750 /// @brief Connect/disconnect a controller to a port on the virtual game console 751 /// 752 /// @param[in] connect True to connect a controller, false to disconnect 753 /// @param[in] port_address The address of the port 754 /// @param[in] controller_id The controller ID if connecting, or unused if disconnecting 755 /// @return True if the \p controller was (dis-)connected to the port, false otherwise 756 /// 757 /// The address is a string that allows traversal of the controller topology. 758 /// It is formed by alternating port IDs and controller IDs separated by "/". 759 /// 760 /// For example, assume that the topology represented in XML for Snes9x is: 761 /// 762 /// ~~~~~~~~~~~~~{.xml} 763 /// <logicaltopology> 764 /// <port type="controller" id="1"> 765 /// <accepts controller="game.controller.snes"/> 766 /// <accepts controller="game.controller.snes.multitap"> 767 /// <port type="controller" id="1"> 768 /// <accepts controller="game.controller.snes"/> 769 /// </port> 770 /// <port type="controller" id="2"> 771 /// <accepts controller="game.controller.snes"/> 772 /// </port> 773 /// ... 774 /// </accepts> 775 /// </port> 776 /// </logicaltopology> 777 /// ~~~~~~~~~~~~~ 778 /// 779 /// To connect a multitap to the console's first port, the multitap's controller 780 /// info is set using the port address: 781 /// 782 /// 1 783 /// 784 /// To connect a SNES controller to the second port of the multitap, the 785 /// controller info is next set using the address: 786 /// 787 /// 1/game.controller.multitap/2 788 /// 789 /// Any attempts to connect a controller to a port on a disconnected multitap 790 /// will return false. 791 /// ConnectController(bool connect,const std::string & port_address,const std::string & controller_id)792 virtual bool ConnectController(bool connect, 793 const std::string& port_address, 794 const std::string& controller_id) 795 { 796 return false; 797 } 798 //---------------------------------------------------------------------------- 799 800 //============================================================================ 801 /// @brief Notify the add-on of an input event 802 /// 803 /// @param[in] event The input event 804 /// 805 /// @return true if the event was handled, false otherwise 806 /// InputEvent(const game_input_event & event)807 virtual bool InputEvent(const game_input_event& event) 808 { 809 return false; 810 } 811 //---------------------------------------------------------------------------- 812 813 //============================================================================ 814 /// @brief **Callback to Kodi Function**<br>Notify the port of an input event 815 /// 816 /// @param[in] event The input event 817 /// @return true if the event was handled, false otherwise 818 /// 819 /// @note Input events can arrive for the following sources: 820 /// - @ref GAME_INPUT_EVENT_MOTOR 821 /// 822 /// @remarks Only called from addon itself 823 /// KodiInputEvent(const game_input_event & event)824 bool KodiInputEvent(const game_input_event& event) 825 { 826 return m_instanceData->toKodi->InputEvent(m_instanceData->toKodi->kodiInstance, &event); 827 } 828 //---------------------------------------------------------------------------- 829 830 ///@} 831 832 //--==----==----==----==----==----==----==----==----==----==----==----==----==-- 833 834 //============================================================================ 835 /// @defgroup cpp_kodi_addon_game_SerializationOperations 5. Serialization operations 836 /// @ingroup cpp_kodi_addon_game 837 /// @brief **Serialization operations** 838 /// 839 /// 840 ///--------------------------------------------------------------------------- 841 /// 842 /// **Serialization operation parts in interface:**\n 843 /// Copy this to your project and extend with your parts or leave functions 844 /// complete away where not used or supported. 845 /// 846 /// @copydetails cpp_kodi_addon_game_SerializationOperations_header_addon_auto_check 847 /// @copydetails cpp_kodi_addon_game_SerializationOperations_source_addon_auto_check 848 /// 849 ///@{ 850 851 //============================================================================ 852 /// @brief Get the number of bytes required to serialize the game 853 /// 854 /// @return the number of bytes, or 0 if serialization is not supported 855 /// SerializeSize()856 virtual size_t SerializeSize() 857 { 858 return 0; 859 } 860 //---------------------------------------------------------------------------- 861 862 //============================================================================ 863 /// @brief Serialize the state of the game 864 /// 865 /// @param[in] data The buffer receiving the serialized game data 866 /// @param[in] size The size of the buffer 867 /// 868 /// @return the error, or @ref GAME_ERROR_NO_ERROR if the game was serialized into the buffer 869 /// Serialize(uint8_t * data,size_t size)870 virtual GAME_ERROR Serialize(uint8_t* data, size_t size) 871 { 872 return GAME_ERROR_NOT_IMPLEMENTED; 873 } 874 //---------------------------------------------------------------------------- 875 876 //============================================================================ 877 /// @brief Deserialize the game from the given state 878 /// 879 /// @param[in] data A buffer containing the game's new state 880 /// @param[in] size The size of the buffer 881 /// 882 /// @return the error, or @ref GAME_ERROR_NO_ERROR if the game deserialized 883 /// Deserialize(const uint8_t * data,size_t size)884 virtual GAME_ERROR Deserialize(const uint8_t* data, size_t size) 885 { 886 return GAME_ERROR_NOT_IMPLEMENTED; 887 } 888 //---------------------------------------------------------------------------- 889 890 ///@} 891 892 //--==----==----==----==----==----==----==----==----==----==----==----==----==-- 893 894 //============================================================================ 895 /// @defgroup cpp_kodi_addon_game_CheatOperations 6. Cheat operations 896 /// @ingroup cpp_kodi_addon_game 897 /// @brief **Cheat operations** 898 /// 899 /// 900 ///--------------------------------------------------------------------------- 901 /// 902 /// **Cheat operation parts in interface:**\n 903 /// Copy this to your project and extend with your parts or leave functions 904 /// complete away where not used or supported. 905 /// 906 /// @copydetails cpp_kodi_addon_game_CheatOperations_header_addon_auto_check 907 /// @copydetails cpp_kodi_addon_game_CheatOperations_source_addon_auto_check 908 /// 909 ///@{ 910 911 //============================================================================ 912 /// @brief Reset the cheat system 913 /// 914 /// @return the error, or @ref GAME_ERROR_NO_ERROR if the cheat system was reset 915 /// CheatReset()916 virtual GAME_ERROR CheatReset() 917 { 918 return GAME_ERROR_NOT_IMPLEMENTED; 919 } 920 //---------------------------------------------------------------------------- 921 922 //============================================================================ 923 /// @brief Get a region of memory 924 /// 925 /// @param[in] type The type of memory to retrieve 926 /// @param[in] data Set to the region of memory; must remain valid until UnloadGame() is called 927 /// @param[in] size Set to the size of the region of memory 928 /// 929 /// @return the error, or @ref GAME_ERROR_NO_ERROR if data was set to a valid buffer 930 /// GetMemory(GAME_MEMORY type,uint8_t * & data,size_t & size)931 virtual GAME_ERROR GetMemory(GAME_MEMORY type, uint8_t*& data, size_t& size) 932 { 933 return GAME_ERROR_NOT_IMPLEMENTED; 934 } 935 //---------------------------------------------------------------------------- 936 937 //============================================================================ 938 /// @brief Set a cheat code 939 /// 940 /// @param[in] index 941 /// @param[in] enabled 942 /// @param[in] code 943 /// 944 /// @return the error, or @ref GAME_ERROR_NO_ERROR if the cheat was set 945 /// SetCheat(unsigned int index,bool enabled,const std::string & code)946 virtual GAME_ERROR SetCheat(unsigned int index, bool enabled, const std::string& code) 947 { 948 return GAME_ERROR_NOT_IMPLEMENTED; 949 } 950 //---------------------------------------------------------------------------- 951 952 ///@} 953 954 private: SetAddonStruct(KODI_HANDLE instance)955 void SetAddonStruct(KODI_HANDLE instance) 956 { 957 if (instance == nullptr) 958 throw std::logic_error("kodi::addon::CInstanceGame: Creation with empty addon structure not" 959 "allowed, table must be given from Kodi!"); 960 961 m_instanceData = static_cast<AddonInstance_Game*>(instance); 962 m_instanceData->toAddon->addonInstance = this; 963 964 m_instanceData->toAddon->LoadGame = ADDON_LoadGame; 965 m_instanceData->toAddon->LoadGameSpecial = ADDON_LoadGameSpecial; 966 m_instanceData->toAddon->LoadStandalone = ADDON_LoadStandalone; 967 m_instanceData->toAddon->UnloadGame = ADDON_UnloadGame; 968 m_instanceData->toAddon->GetGameTiming = ADDON_GetGameTiming; 969 m_instanceData->toAddon->GetRegion = ADDON_GetRegion; 970 m_instanceData->toAddon->RequiresGameLoop = ADDON_RequiresGameLoop; 971 m_instanceData->toAddon->RunFrame = ADDON_RunFrame; 972 m_instanceData->toAddon->Reset = ADDON_Reset; 973 974 m_instanceData->toAddon->HwContextReset = ADDON_HwContextReset; 975 m_instanceData->toAddon->HwContextDestroy = ADDON_HwContextDestroy; 976 977 m_instanceData->toAddon->HasFeature = ADDON_HasFeature; 978 m_instanceData->toAddon->GetTopology = ADDON_GetTopology; 979 m_instanceData->toAddon->FreeTopology = ADDON_FreeTopology; 980 m_instanceData->toAddon->SetControllerLayouts = ADDON_SetControllerLayouts; 981 m_instanceData->toAddon->EnableKeyboard = ADDON_EnableKeyboard; 982 m_instanceData->toAddon->EnableMouse = ADDON_EnableMouse; 983 m_instanceData->toAddon->ConnectController = ADDON_ConnectController; 984 m_instanceData->toAddon->InputEvent = ADDON_InputEvent; 985 986 m_instanceData->toAddon->SerializeSize = ADDON_SerializeSize; 987 m_instanceData->toAddon->Serialize = ADDON_Serialize; 988 m_instanceData->toAddon->Deserialize = ADDON_Deserialize; 989 990 m_instanceData->toAddon->CheatReset = ADDON_CheatReset; 991 m_instanceData->toAddon->GetMemory = ADDON_GetMemory; 992 m_instanceData->toAddon->SetCheat = ADDON_SetCheat; 993 } 994 995 // --- Game operations --------------------------------------------------------- 996 ADDON_LoadGame(const AddonInstance_Game * instance,const char * url)997 inline static GAME_ERROR ADDON_LoadGame(const AddonInstance_Game* instance, const char* url) 998 { 999 return static_cast<CInstanceGame*>(instance->toAddon->addonInstance)->LoadGame(url); 1000 } 1001 ADDON_LoadGameSpecial(const AddonInstance_Game * instance,SPECIAL_GAME_TYPE type,const char ** urls,size_t urlCount)1002 inline static GAME_ERROR ADDON_LoadGameSpecial(const AddonInstance_Game* instance, 1003 SPECIAL_GAME_TYPE type, 1004 const char** urls, 1005 size_t urlCount) 1006 { 1007 std::vector<std::string> urlList; 1008 for (size_t i = 0; i < urlCount; ++i) 1009 { 1010 if (urls[i] != nullptr) 1011 urlList.push_back(urls[i]); 1012 } 1013 1014 return static_cast<CInstanceGame*>(instance->toAddon->addonInstance) 1015 ->LoadGameSpecial(type, urlList); 1016 } 1017 ADDON_LoadStandalone(const AddonInstance_Game * instance)1018 inline static GAME_ERROR ADDON_LoadStandalone(const AddonInstance_Game* instance) 1019 { 1020 return static_cast<CInstanceGame*>(instance->toAddon->addonInstance)->LoadStandalone(); 1021 } 1022 ADDON_UnloadGame(const AddonInstance_Game * instance)1023 inline static GAME_ERROR ADDON_UnloadGame(const AddonInstance_Game* instance) 1024 { 1025 return static_cast<CInstanceGame*>(instance->toAddon->addonInstance)->UnloadGame(); 1026 } 1027 ADDON_GetGameTiming(const AddonInstance_Game * instance,game_system_timing * timing_info)1028 inline static GAME_ERROR ADDON_GetGameTiming(const AddonInstance_Game* instance, 1029 game_system_timing* timing_info) 1030 { 1031 return static_cast<CInstanceGame*>(instance->toAddon->addonInstance) 1032 ->GetGameTiming(*timing_info); 1033 } 1034 ADDON_GetRegion(const AddonInstance_Game * instance)1035 inline static GAME_REGION ADDON_GetRegion(const AddonInstance_Game* instance) 1036 { 1037 return static_cast<CInstanceGame*>(instance->toAddon->addonInstance)->GetRegion(); 1038 } 1039 ADDON_RequiresGameLoop(const AddonInstance_Game * instance)1040 inline static bool ADDON_RequiresGameLoop(const AddonInstance_Game* instance) 1041 { 1042 return static_cast<CInstanceGame*>(instance->toAddon->addonInstance)->RequiresGameLoop(); 1043 } 1044 ADDON_RunFrame(const AddonInstance_Game * instance)1045 inline static GAME_ERROR ADDON_RunFrame(const AddonInstance_Game* instance) 1046 { 1047 return static_cast<CInstanceGame*>(instance->toAddon->addonInstance)->RunFrame(); 1048 } 1049 ADDON_Reset(const AddonInstance_Game * instance)1050 inline static GAME_ERROR ADDON_Reset(const AddonInstance_Game* instance) 1051 { 1052 return static_cast<CInstanceGame*>(instance->toAddon->addonInstance)->Reset(); 1053 } 1054 1055 1056 // --- Hardware rendering operations ------------------------------------------- 1057 ADDON_HwContextReset(const AddonInstance_Game * instance)1058 inline static GAME_ERROR ADDON_HwContextReset(const AddonInstance_Game* instance) 1059 { 1060 return static_cast<CInstanceGame*>(instance->toAddon->addonInstance)->HwContextReset(); 1061 } 1062 ADDON_HwContextDestroy(const AddonInstance_Game * instance)1063 inline static GAME_ERROR ADDON_HwContextDestroy(const AddonInstance_Game* instance) 1064 { 1065 return static_cast<CInstanceGame*>(instance->toAddon->addonInstance)->HwContextDestroy(); 1066 } 1067 1068 1069 // --- Input operations -------------------------------------------------------- 1070 ADDON_HasFeature(const AddonInstance_Game * instance,const char * controller_id,const char * feature_name)1071 inline static bool ADDON_HasFeature(const AddonInstance_Game* instance, 1072 const char* controller_id, 1073 const char* feature_name) 1074 { 1075 return static_cast<CInstanceGame*>(instance->toAddon->addonInstance) 1076 ->HasFeature(controller_id, feature_name); 1077 } 1078 ADDON_GetTopology(const AddonInstance_Game * instance)1079 inline static game_input_topology* ADDON_GetTopology(const AddonInstance_Game* instance) 1080 { 1081 return static_cast<CInstanceGame*>(instance->toAddon->addonInstance)->GetTopology(); 1082 } 1083 ADDON_FreeTopology(const AddonInstance_Game * instance,game_input_topology * topology)1084 inline static void ADDON_FreeTopology(const AddonInstance_Game* instance, 1085 game_input_topology* topology) 1086 { 1087 static_cast<CInstanceGame*>(instance->toAddon->addonInstance)->FreeTopology(topology); 1088 } 1089 ADDON_SetControllerLayouts(const AddonInstance_Game * instance,const game_controller_layout * controllers,unsigned int controller_count)1090 inline static void ADDON_SetControllerLayouts(const AddonInstance_Game* instance, 1091 const game_controller_layout* controllers, 1092 unsigned int controller_count) 1093 { 1094 if (controllers == nullptr) 1095 return; 1096 1097 std::vector<GameControllerLayout> controllerList; 1098 for (unsigned int i = 0; i < controller_count; ++i) 1099 controllerList.push_back(controllers[i]); 1100 1101 static_cast<CInstanceGame*>(instance->toAddon->addonInstance) 1102 ->SetControllerLayouts(controllerList); 1103 } 1104 ADDON_EnableKeyboard(const AddonInstance_Game * instance,bool enable,const char * controller_id)1105 inline static bool ADDON_EnableKeyboard(const AddonInstance_Game* instance, 1106 bool enable, 1107 const char* controller_id) 1108 { 1109 return static_cast<CInstanceGame*>(instance->toAddon->addonInstance) 1110 ->EnableKeyboard(enable, controller_id); 1111 } 1112 ADDON_EnableMouse(const AddonInstance_Game * instance,bool enable,const char * controller_id)1113 inline static bool ADDON_EnableMouse(const AddonInstance_Game* instance, 1114 bool enable, 1115 const char* controller_id) 1116 { 1117 return static_cast<CInstanceGame*>(instance->toAddon->addonInstance) 1118 ->EnableMouse(enable, controller_id); 1119 } 1120 ADDON_ConnectController(const AddonInstance_Game * instance,bool connect,const char * port_address,const char * controller_id)1121 inline static bool ADDON_ConnectController(const AddonInstance_Game* instance, 1122 bool connect, 1123 const char* port_address, 1124 const char* controller_id) 1125 { 1126 return static_cast<CInstanceGame*>(instance->toAddon->addonInstance) 1127 ->ConnectController(connect, port_address, controller_id); 1128 } 1129 ADDON_InputEvent(const AddonInstance_Game * instance,const game_input_event * event)1130 inline static bool ADDON_InputEvent(const AddonInstance_Game* instance, 1131 const game_input_event* event) 1132 { 1133 return static_cast<CInstanceGame*>(instance->toAddon->addonInstance)->InputEvent(*event); 1134 } 1135 1136 1137 // --- Serialization operations ------------------------------------------------ 1138 ADDON_SerializeSize(const AddonInstance_Game * instance)1139 inline static size_t ADDON_SerializeSize(const AddonInstance_Game* instance) 1140 { 1141 return static_cast<CInstanceGame*>(instance->toAddon->addonInstance)->SerializeSize(); 1142 } 1143 ADDON_Serialize(const AddonInstance_Game * instance,uint8_t * data,size_t size)1144 inline static GAME_ERROR ADDON_Serialize(const AddonInstance_Game* instance, 1145 uint8_t* data, 1146 size_t size) 1147 { 1148 return static_cast<CInstanceGame*>(instance->toAddon->addonInstance)->Serialize(data, size); 1149 } 1150 ADDON_Deserialize(const AddonInstance_Game * instance,const uint8_t * data,size_t size)1151 inline static GAME_ERROR ADDON_Deserialize(const AddonInstance_Game* instance, 1152 const uint8_t* data, 1153 size_t size) 1154 { 1155 return static_cast<CInstanceGame*>(instance->toAddon->addonInstance)->Deserialize(data, size); 1156 } 1157 1158 1159 // --- Cheat operations -------------------------------------------------------- 1160 ADDON_CheatReset(const AddonInstance_Game * instance)1161 inline static GAME_ERROR ADDON_CheatReset(const AddonInstance_Game* instance) 1162 { 1163 return static_cast<CInstanceGame*>(instance->toAddon->addonInstance)->CheatReset(); 1164 } 1165 ADDON_GetMemory(const AddonInstance_Game * instance,GAME_MEMORY type,uint8_t ** data,size_t * size)1166 inline static GAME_ERROR ADDON_GetMemory(const AddonInstance_Game* instance, 1167 GAME_MEMORY type, 1168 uint8_t** data, 1169 size_t* size) 1170 { 1171 return static_cast<CInstanceGame*>(instance->toAddon->addonInstance) 1172 ->GetMemory(type, *data, *size); 1173 } 1174 ADDON_SetCheat(const AddonInstance_Game * instance,unsigned int index,bool enabled,const char * code)1175 inline static GAME_ERROR ADDON_SetCheat(const AddonInstance_Game* instance, 1176 unsigned int index, 1177 bool enabled, 1178 const char* code) 1179 { 1180 return static_cast<CInstanceGame*>(instance->toAddon->addonInstance) 1181 ->SetCheat(index, enabled, code); 1182 } 1183 1184 AddonInstance_Game* m_instanceData; 1185 }; 1186 1187 } /* namespace addon */ 1188 } /* namespace kodi */ 1189 1190 #endif /* __cplusplus */ 1191