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