/*
 *  Copyright (C) 2014-2025 Team Kodi
 *  This file is part of Kodi - https://kodi.tv
 *
 *  SPDX-License-Identifier: GPL-2.0-or-later
 *  See LICENSES/README.md for more information.
 */

#ifndef C_API_ADDONINSTANCE_GAME_H
#define C_API_ADDONINSTANCE_GAME_H

#include "../addon_base.h"

#include <stddef.h> /* size_t */
#include <stdint.h>

#ifdef __cplusplus
extern "C"
{
#endif /* __cplusplus */

  //============================================================================
  /// @ingroup cpp_kodi_addon_game_Defs
  /// @brief **Game add-on error codes**
  ///
  /// Used as return values from most game-related functions.
  ///
  typedef enum GAME_ERROR
  {
    /// @brief No error occurred
    GAME_ERROR_NO_ERROR,

    /// @brief An unknown error occurred
    GAME_ERROR_UNKNOWN,

    /// @brief The method called by the frontend is not implemented
    GAME_ERROR_NOT_IMPLEMENTED,

    /// @brief The command was rejected by the game client
    GAME_ERROR_REJECTED,

    /// @brief The parameters of the called method are invalid for this operation
    GAME_ERROR_INVALID_PARAMETERS,

    /// @brief The command failed
    GAME_ERROR_FAILED,

    /// @brief No game is loaded
    GAME_ERROR_NOT_LOADED,

    /// @brief Game requires restricted resources
    GAME_ERROR_RESTRICTED,
  } GAME_ERROR;
  //----------------------------------------------------------------------------

  //--==----==----==----==----==----==----==----==----==----==----==----==----==--
  /// @defgroup cpp_kodi_addon_game_Defs_AudioStream 1. Audio stream
  /// @ingroup cpp_kodi_addon_game_Defs
  /// @brief **Audio stream data system**
  ///
  /// Used to provide the add-on with the current audio stream configuration
  /// from Kodi and arrays to pass related data back to Kodi during callbacks.
  ///
  ///@{

  //============================================================================
  /// @brief **Stream Format**
  ///
  /// Audio sample format requested by Kodi.
  ///
  typedef enum GAME_PCM_FORMAT
  {
    GAME_PCM_FORMAT_UNKNOWN,

    /// @brief S16NE sample format
    GAME_PCM_FORMAT_S16NE,
  } GAME_PCM_FORMAT;
  //----------------------------------------------------------------------------

  //============================================================================
  /// @brief **Audio channel**
  ///
  /// Channel identification flags.
  ///
  typedef enum GAME_AUDIO_CHANNEL
  {
    /// @brief Channel list terminator
    GAME_CH_NULL,

    /// @brief Channel front left
    GAME_CH_FL,

    /// @brief Channel front right
    GAME_CH_FR,

    /// @brief Channel front center
    GAME_CH_FC,

    /// @brief Channel low frequency effects / subwoofer
    GAME_CH_LFE,

    /// @brief Channel back left
    GAME_CH_BL,

    /// @brief Channel back right
    GAME_CH_BR,

    /// @brief Channel front left over center
    GAME_CH_FLOC,

    /// @brief Channel front right over center
    GAME_CH_FROC,

    /// @brief Channel back center
    GAME_CH_BC,

    /// @brief Channel surround/side left
    GAME_CH_SL,

    /// @brief Channel surround/side right
    GAME_CH_SR,

    /// @brief Channel top front left
    GAME_CH_TFL,

    /// @brief Channel top front right
    GAME_CH_TFR,

    /// @brief Channel top front center
    GAME_CH_TFC,

    /// @brief Channel top center
    GAME_CH_TC,

    /// @brief Channel top back left
    GAME_CH_TBL,

    /// @brief Channel top back right
    GAME_CH_TBR,

    /// @brief Channel top back center
    GAME_CH_TBC,

    /// @brief Channel back left over center
    GAME_CH_BLOC,

    /// @brief Channel back right over center
    GAME_CH_BROC,
  } GAME_AUDIO_CHANNEL;
  //----------------------------------------------------------------------------

  //============================================================================
  /// @brief **Game audio stream properties**
  ///
  /// Used by Kodi to pass the currently required audio stream settings to the add-on
  ///
  typedef struct game_stream_audio_properties
  {
    GAME_PCM_FORMAT format;
    const GAME_AUDIO_CHANNEL* channel_map;
  } ATTR_PACKED game_stream_audio_properties;
  //----------------------------------------------------------------------------

  //============================================================================
  /// @brief **Audio stream packet**
  ///
  /// This packet contains audio stream data passed to Kodi.
  ///
  typedef struct game_stream_audio_packet
  {
    /// @brief Pointer to the audio stream data given to Kodi
    const uint8_t* data;

    /// @brief Size of the data array
    size_t size;
  } ATTR_PACKED game_stream_audio_packet;
  //----------------------------------------------------------------------------

  ///@}

  //--==----==----==----==----==----==----==----==----==----==----==----==----==--
  /// @defgroup cpp_kodi_addon_game_Defs_VideoStream 2. Video stream
  /// @ingroup cpp_kodi_addon_game_Defs
  /// @brief **Video stream data system**
  ///
  /// Used to provide the add-on with the current video stream configuration
  /// from Kodi and arrays to pass related data back to Kodi during callbacks.
  ///
  ///@{

  //============================================================================
  /// @brief **Pixel format**
  ///
  /// Video RGB color model format requested by Kodi.
  ///
  typedef enum GAME_PIXEL_FORMAT
  {
    GAME_PIXEL_FORMAT_UNKNOWN,

    /// @brief 0RGB8888 Format
    GAME_PIXEL_FORMAT_0RGB8888,

    /// @brief RGB565 Format
    GAME_PIXEL_FORMAT_RGB565,

    /// @brief 0RGB1555 Format
    GAME_PIXEL_FORMAT_0RGB1555,
  } GAME_PIXEL_FORMAT;
  //----------------------------------------------------------------------------

  //============================================================================
  /// @brief **Video rotation orientation**
  ///
  /// Defines how the video is rotated.
  ///
  typedef enum GAME_VIDEO_ROTATION
  {
    /// @brief 0° without rotation
    GAME_VIDEO_ROTATION_0,

    /// @brief Rotate 90° counterclockwise
    GAME_VIDEO_ROTATION_90_CCW,

    /// @brief Rotate 180° counterclockwise
    GAME_VIDEO_ROTATION_180_CCW,

    /// @brief Rotate 270° counterclockwise
    GAME_VIDEO_ROTATION_270_CCW,
  } GAME_VIDEO_ROTATION;
  //----------------------------------------------------------------------------

  //============================================================================
  /// @brief **Game video stream properties**
  ///
  /// Used by Kodi to pass the currently required video stream settings to the
  /// add-on.
  ///
  typedef struct game_stream_video_properties
  {
    /// @brief The stream's pixel format
    GAME_PIXEL_FORMAT format;

    /// @brief The nominal width, in pixels
    unsigned int nominal_width;

    /// @brief The nominal height, in pixels
    unsigned int nominal_height;

    /// @brief The nominal display aspect ratio (DAR) used to show the video frame
    ///
    /// An aspect ratio of 0.0 indicates square pixels, i.e. a DAR of W/H.
    ///
    float nominal_display_aspect_ratio;

    /// @brief The maximum width, in pixels
    unsigned int max_width;

    /// @brief The maximum height, in pixels
    unsigned int max_height;
  } ATTR_PACKED game_stream_video_properties;
  //----------------------------------------------------------------------------

  //============================================================================
  /// @brief **Video stream packet**
  ///
  /// This packet contains video stream data passed to Kodi.
  ///
  typedef struct game_stream_video_packet
  {
    /// @brief Video width, in pixels
    unsigned int width;

    /// @brief Video height, in pixels
    unsigned int height;

    /// @brief Display aspect ratio (DAR) to use when showing the video frame
    ///
    /// An aspect ratio of 0.0 indicates square pixels, i.e. a DAR of W/H.
    ///
    float display_aspect_ratio;

    /// @brief Video rotation angle defined by @ref GAME_VIDEO_ROTATION
    GAME_VIDEO_ROTATION rotation;

    /// @brief Pointer to the video stream data given to Kodi
    const uint8_t* data;

    /// @brief Size of the data array
    size_t size;
  } ATTR_PACKED game_stream_video_packet;
  //----------------------------------------------------------------------------

  ///@}

  //--==----==----==----==----==----==----==----==----==----==----==----==----==--
  /// @defgroup cpp_kodi_addon_game_Defs_HardwareFramebuffer 3. Hardware framebuffer stream
  /// @ingroup cpp_kodi_addon_game_Defs
  /// @brief **Hardware framebuffer stream data**
  ///
  ///@{

  //============================================================================
  /// @brief **Hardware framebuffer type**
  ///
  typedef enum GAME_HW_CONTEXT_TYPE
  {
    /// @brief No context
    GAME_HW_CONTEXT_NONE,

    /// @brief OpenGL 2.x. The driver can choose to use the latest compatibility context
    GAME_HW_CONTEXT_OPENGL,

    /// @brief OpenGL ES 2.0
    GAME_HW_CONTEXT_OPENGLES2,

    /// @brief Modern desktop core GL context. Use the major and minor fields to set the GL version
    GAME_HW_CONTEXT_OPENGL_CORE,

    /// @brief OpenGL ES 3.0
    GAME_HW_CONTEXT_OPENGLES3,

    /// @brief OpenGL ES 3.1+. Set major/minor fields.
    GAME_HW_CONTEXT_OPENGLES_VERSION,

    /// @brief Vulkan
    GAME_HW_CONTEXT_VULKAN
  } GAME_HW_CONTEXT_TYPE;
  //----------------------------------------------------------------------------

  //==============================================================================
  /// @brief **Hardware rendering properties**
  ///
  /// These properties are needed early on, so instead of passing them when the
  /// stream is opened, they are passed in EnableHardwareRendering(). As a
  /// result, the struct passed to OpenStream() is empty.
  ///
  typedef struct game_hw_rendering_properties
  {
    /// @brief The API to use
    ///
    GAME_HW_CONTEXT_TYPE context_type;

    /// @brief Set to true if render buffers should have a depth component attached
    ///
    /// @todo: Obsolete
    ///
    bool depth;

    /// @brief Set to true if stencil buffers should be attached
    ///
    /// If depth and stencil are true, a packed 24/8 buffer will be added.
    /// Only attaching stencil is invalid and will be ignored.
    ///
    /// @todo: Obsolete
    ///
    bool stencil;

    /// @brief Use the conventional bottom-left origin
    ///
    /// If false, standard top-left origin semantics are used.
    ///
    /// @todo: Move to GL specific interface
    ///
    bool bottom_left_origin;

    /// @brief Major version number for the core GL context or GLES 3.1+
    unsigned int version_major;

    /// @brief Minor version number for the core GL context or GLES 3.1+
    unsigned int version_minor;

    /// @brief If true, the frontend will go to great lengths to avoid
    /// resetting the context in scenarios like toggling fullscreen, etc.
    ///
    /// @todo: Obsolete? Maybe frontend should just always assume this...
    ///
    /// The reset callback might still be called in extreme situations such as
    /// if the context is lost beyond recovery.
    ///
    /// For optimal stability, set this to false, and allow context to be reset
    /// at any time.
    ///
    bool cache_context;

    /// @brief Creates a debug context
    bool debug_context;

  } ATTR_PACKED game_hw_rendering_properties;
  //------------------------------------------------------------------------------

  //==============================================================================
  /// @brief **Hardware framebuffer properties**
  ///
  /// This struct is empty because hardware rendering properties are passed via
  /// EnableHardwareRendering().
  ///
  typedef struct game_stream_hw_framebuffer_properties
  {
    char dummy; // Occupier for empty struct
  } ATTR_PACKED game_stream_hw_framebuffer_properties;
  //----------------------------------------------------------------------------

  //============================================================================
  /// @brief **Hardware framebuffer buffer**
  ///
  typedef struct game_stream_hw_framebuffer_buffer
  {
    /// @brief
    uintptr_t framebuffer;
  } ATTR_PACKED game_stream_hw_framebuffer_buffer;
  //----------------------------------------------------------------------------

  //============================================================================
  /// @brief **Hardware framebuffer packet**
  ///
  typedef struct game_stream_hw_framebuffer_packet
  {
    /// @brief
    uintptr_t framebuffer;
  } ATTR_PACKED game_stream_hw_framebuffer_packet;
  //----------------------------------------------------------------------------

  //============================================================================
  /// @brief **Hardware framebuffer process function address**
  ///
  typedef void (*game_proc_address_t)(void);
  //----------------------------------------------------------------------------

  ///@}

  //--==----==----==----==----==----==----==----==----==----==----==----==----==--
  /// @defgroup cpp_kodi_addon_game_Defs_SoftwareFramebuffer 4. Software framebuffer stream
  /// @ingroup cpp_kodi_addon_game_Defs
  /// @brief **Software framebuffer stream data**
  ///
  ///@{

  //============================================================================
  /// @brief **Game software framebuffer stream properties**
  ///
  /// Used by Kodi to pass the currently required video stream settings to the add-on
  ///
  typedef game_stream_video_properties game_stream_sw_framebuffer_properties;
  //----------------------------------------------------------------------------

  //============================================================================
  /// @brief **Software framebuffer type**
  ///
  typedef struct game_stream_sw_framebuffer_buffer
  {
    GAME_PIXEL_FORMAT format;
    uint8_t* data;
    size_t size;
  } ATTR_PACKED game_stream_sw_framebuffer_buffer;
  //----------------------------------------------------------------------------

  //============================================================================
  /// @brief **Software framebuffer packet**
  ///
  /// This packet contains video stream data passed to Kodi.
  ///
  typedef game_stream_video_packet game_stream_sw_framebuffer_packet;
  //----------------------------------------------------------------------------

  ///@}

  //--==----==----==----==----==----==----==----==----==----==----==----==----==--
  /// @defgroup cpp_kodi_addon_game_Defs_StreamTypes 5. Stream types
  /// @ingroup cpp_kodi_addon_game_Defs
  /// @brief **Stream types data**
  ///
  ///@{

  //============================================================================
  /// @brief **Game stream types**
  ///
  typedef enum GAME_STREAM_TYPE
  {
    /// @brief Unknown
    GAME_STREAM_UNKNOWN,

    /// @brief Audio stream
    GAME_STREAM_AUDIO,

    /// @brief Video stream
    GAME_STREAM_VIDEO,

    /// @brief Hardware framebuffer
    GAME_STREAM_HW_FRAMEBUFFER,

    /// @brief Software framebuffer
    GAME_STREAM_SW_FRAMEBUFFER,
  } GAME_STREAM_TYPE;
  //----------------------------------------------------------------------------

  //============================================================================
  /// @brief **Immutable stream metadata**
  ///
  /// This metadata is provided when the stream is opened. If any stream
  /// properties change, a new stream must be opened.
  ///
  typedef struct game_stream_properties
  {
    /// @brief The stream type
    GAME_STREAM_TYPE type;

    union
    {
      /// @brief The audio stream properties
      game_stream_audio_properties audio;

      /// @brief The video stream properties
      game_stream_video_properties video;

      /// @brief The hardware framebuffer properties
      game_stream_hw_framebuffer_properties hw_framebuffer;

      /// @brief The software framebuffer properties
      game_stream_sw_framebuffer_properties sw_framebuffer;
    };
  } ATTR_PACKED game_stream_properties;
  //----------------------------------------------------------------------------

  //============================================================================
  /// @brief **Stream buffers for hardware rendering and zero-copy support**
  ///
  typedef struct game_stream_buffer
  {
    /// @brief The stream type
    GAME_STREAM_TYPE type;

    union
    {
      /// @brief The audio stream packet
      game_stream_hw_framebuffer_buffer hw_framebuffer;

      /// @brief The video stream packet
      game_stream_sw_framebuffer_buffer sw_framebuffer;
    };
  } ATTR_PACKED game_stream_buffer;
  //----------------------------------------------------------------------------

  //============================================================================
  /// @brief **Stream packet and ephemeral metadata**
  ///
  /// This packet contains stream data and accompanying metadata. The metadata
  /// is ephemeral, meaning it only applies to the current packet and can change
  /// from packet to packet in the same stream.
  ///
  typedef struct game_stream_packet
  {
    /// @brief The stream type
    GAME_STREAM_TYPE type;

    union
    {
      /// @brief The audio stream packet
      game_stream_audio_packet audio;

      /// @brief The video stream packet
      game_stream_video_packet video;

      /// @brief The hardware framebuffer packet
      game_stream_hw_framebuffer_packet hw_framebuffer;

      /// @brief The software framebuffer packet
      game_stream_sw_framebuffer_packet sw_framebuffer;
    };
  } ATTR_PACKED game_stream_packet;
  //----------------------------------------------------------------------------

  ///@}

  //--==----==----==----==----==----==----==----==----==----==----==----==----==--
  /// @defgroup cpp_kodi_addon_game_Defs_GameTypes 6. Game types
  /// @ingroup cpp_kodi_addon_game_Defs
  /// @brief **Game types data**
  ///
  ///@{

  //============================================================================
  /// @brief **Game region definition**
  ///
  /// Returned from game_get_region()
  typedef enum GAME_REGION
  {
    /// @brief Game region unknown
    GAME_REGION_UNKNOWN,

    /// @brief Game region NTSC
    GAME_REGION_NTSC,

    /// @brief Game region PAL
    GAME_REGION_PAL,
  } GAME_REGION;
  //----------------------------------------------------------------------------

  //============================================================================
  /// @brief **Special game types passed into game_load_game_special().**
  ///
  /// @remark Only used when multiple ROMs are required.
  ///
  typedef enum SPECIAL_GAME_TYPE
  {
    /// @brief Game Type BSX
    SPECIAL_GAME_TYPE_BSX,

    /// @brief Game Type BSX slotted
    SPECIAL_GAME_TYPE_BSX_SLOTTED,

    /// @brief Game Type sufami turbo
    SPECIAL_GAME_TYPE_SUFAMI_TURBO,

    /// @brief Game Type super game boy
    SPECIAL_GAME_TYPE_SUPER_GAME_BOY,
  } SPECIAL_GAME_TYPE;
  //----------------------------------------------------------------------------

  //============================================================================
  /// @brief **Game Memory**
  ///
  typedef enum GAME_MEMORY
  {
    /// @brief Passed to game_get_memory_data/size(). If the memory type doesn't apply
    /// to the implementation NULL/0 can be returned.
    GAME_MEMORY_MASK = 0xff,

    /// @brief Regular save ram.
    ///
    /// This ram is usually found on a game cartridge, backed
    /// up by a battery. If save game data is too complex for a single memory
    /// buffer, the SYSTEM_DIRECTORY environment callback can be used.
    GAME_MEMORY_SAVE_RAM = 0,

    /// @brief Some games have a built-in clock to keep track of time.
    ///
    /// This memory is usually just a couple of bytes to keep track of time.
    GAME_MEMORY_RTC = 1,

    /// @brief System ram lets a frontend peek into a game systems main RAM
    GAME_MEMORY_SYSTEM_RAM = 2,

    /// @brief Video ram lets a frontend peek into a game systems video RAM (VRAM)
    GAME_MEMORY_VIDEO_RAM = 3,

    /// @brief Special memory type
    GAME_MEMORY_SNES_BSX_RAM = ((1 << 8) | GAME_MEMORY_SAVE_RAM),

    /// @brief Special memory type
    GAME_MEMORY_SNES_BSX_PRAM = ((2 << 8) | GAME_MEMORY_SAVE_RAM),

    /// @brief Special memory type
    GAME_MEMORY_SNES_SUFAMI_TURBO_A_RAM = ((3 << 8) | GAME_MEMORY_SAVE_RAM),

    /// @brief Special memory type
    GAME_MEMORY_SNES_SUFAMI_TURBO_B_RAM = ((4 << 8) | GAME_MEMORY_SAVE_RAM),

    /// @brief Special memory type
    GAME_MEMORY_SNES_GAME_BOY_RAM = ((5 << 8) | GAME_MEMORY_SAVE_RAM),

    /// @brief Special memory type
    GAME_MEMORY_SNES_GAME_BOY_RTC = ((6 << 8) | GAME_MEMORY_RTC),
  } GAME_MEMORY;
  //----------------------------------------------------------------------------

  //============================================================================
  /// @brief **ID values for SIMD CPU features**
  typedef enum GAME_SIMD
  {
    /// @brief SIMD CPU SSE
    GAME_SIMD_SSE = (1 << 0),

    /// @brief SIMD CPU SSE2
    GAME_SIMD_SSE2 = (1 << 1),

    /// @brief SIMD CPU VMX
    GAME_SIMD_VMX = (1 << 2),

    /// @brief SIMD CPU VMX128
    GAME_SIMD_VMX128 = (1 << 3),

    /// @brief SIMD CPU AVX
    GAME_SIMD_AVX = (1 << 4),

    /// @brief SIMD CPU NEON
    GAME_SIMD_NEON = (1 << 5),

    /// @brief SIMD CPU SSE3
    GAME_SIMD_SSE3 = (1 << 6),

    /// @brief SIMD CPU SSSE3
    GAME_SIMD_SSSE3 = (1 << 7),

    /// @brief SIMD CPU MMX
    GAME_SIMD_MMX = (1 << 8),

    /// @brief SIMD CPU MMXEXT
    GAME_SIMD_MMXEXT = (1 << 9),

    /// @brief SIMD CPU SSE4
    GAME_SIMD_SSE4 = (1 << 10),

    /// @brief SIMD CPU SSE42
    GAME_SIMD_SSE42 = (1 << 11),

    /// @brief SIMD CPU AVX2
    GAME_SIMD_AVX2 = (1 << 12),

    /// @brief SIMD CPU VFPU
    GAME_SIMD_VFPU = (1 << 13),
  } GAME_SIMD;
  //----------------------------------------------------------------------------

  ///@}

  //--==----==----==----==----==----==----==----==----==----==----==----==----==--
  /// @defgroup cpp_kodi_addon_game_Defs_InputTypes 7. Input types
  /// @ingroup cpp_kodi_addon_game_Defs
  /// @brief **Input types**
  ///
  /// Input consists of two categories: Input events and input topology.
  ///
  /// The events are the changes in that state. For example, a button press is
  /// an event.
  ///
  /// The topology is the tree that describes the entire hardware state of the
  /// virtual game console. This includes all port connections and physical
  /// properties of the devices.
  ///
  /// Ports can accept multiple devices and devices can have multiple ports, so
  /// the topology of possible configurations is a tree structure of alternating
  /// port and device nodes. The root of the controller tree is `/`.
  ///
  /// The port address combined with the controller ID identifies the controller
  /// by its path in the controller tree. For example, a controller attached to
  /// port `1` could be `/1/game.controller.default`.
  ///
  /// The keyboard and mouse are automatically assigned a port address and the
  /// "id" parameter in the game add-on's topology.xml is ignored. The keyboard
  /// is `/keyboard` and the mouse is `/mouse`.
  ///
  ///@{

  //==============================================================================
  /// @brief **Root address of the controller tree
#define ROOT_PORT_ADDRESS "/"
  //------------------------------------------------------------------------------

  //==============================================================================
  /// @brief **Port ID used when topology is unknown**
#define DEFAULT_PORT_ID "1"
  //------------------------------------------------------------------------------

  //==============================================================================
  /// @brief **Port ID used for the keyboard input device
#define KEYBOARD_PORT_ID "keyboard"
  //------------------------------------------------------------------------------

  //==============================================================================
  /// @brief **Port ID used for the mouse input device
#define MOUSE_PORT_ID "mouse"
  //------------------------------------------------------------------------------

  //==============================================================================
  /// @brief **Port address used when topology is unknown**
#define DEFAULT_PORT_ADDRESS "/1"
  //------------------------------------------------------------------------------

  //==============================================================================
  /// @brief **Port address used for the keyboard input device
#define KEYBOARD_PORT_ADDRESS "/keyboard"
  //------------------------------------------------------------------------------

  //==============================================================================
  /// @brief **Port address used for the mouse input device
#define MOUSE_PORT_ADDRESS "/mouse"
  //------------------------------------------------------------------------------

  //============================================================================
  /// @brief Type of input event
  typedef enum GAME_INPUT_EVENT_SOURCE
  {
    /// @brief Digital button press or release
    GAME_INPUT_EVENT_DIGITAL_BUTTON,

    /// @brief Analog button motion
    GAME_INPUT_EVENT_ANALOG_BUTTON,

    /// @brief Axis motion
    GAME_INPUT_EVENT_AXIS,

    /// @brief Analog stick motion
    GAME_INPUT_EVENT_ANALOG_STICK,

    /// @brief Accelerometer motion
    GAME_INPUT_EVENT_ACCELEROMETER,

    /// @brief Key press or release
    GAME_INPUT_EVENT_KEY,

    /// @brief Relative pointer motion
    GAME_INPUT_EVENT_RELATIVE_POINTER,

    /// @brief Absolute pointer motion
    GAME_INPUT_EVENT_ABSOLUTE_POINTER,

    /// @brief Motor vibration
    GAME_INPUT_EVENT_MOTOR,
  } GAME_INPUT_EVENT_SOURCE;
  //----------------------------------------------------------------------------

  //============================================================================
  /// @brief A modifier key pressed to give another key a special meaning
  typedef enum GAME_KEY_MOD
  {
    /// @brief No modifier key
    GAME_KEY_MOD_NONE = 0x0000,

    /// @brief Shift key
    GAME_KEY_MOD_SHIFT = 0x0001,

    /// @brief Control key
    GAME_KEY_MOD_CTRL = 0x0002,

    /// @brief Alt key
    GAME_KEY_MOD_ALT = 0x0004,

    /// @brief Meta key
    GAME_KEY_MOD_META = 0x0008,

    /// @brief Windows key
    GAME_KEY_MOD_SUPER = 0x0010,

    /// @brief Num Lock key
    GAME_KEY_MOD_NUMLOCK = 0x0100,

    /// @brief Caps Lock key
    GAME_KEY_MOD_CAPSLOCK = 0x0200,

    /// @brief Scroll Lock key
    GAME_KEY_MOD_SCROLLOCK = 0x0400,
  } GAME_KEY_MOD;
  //----------------------------------------------------------------------------

  //============================================================================
  /// @brief Type of port on the virtual game console
  typedef enum GAME_PORT_TYPE
  {
    /// @brief Game port unknown
    GAME_PORT_UNKNOWN,

    /// @brief Game port Keyboard
    GAME_PORT_KEYBOARD,

    /// @brief Game port mouse
    GAME_PORT_MOUSE,

    /// @brief Game port controller
    GAME_PORT_CONTROLLER,
  } GAME_PORT_TYPE;
  //----------------------------------------------------------------------------

  /*!
    * @brief "C" Game add-on controller layout.
    *
    * Structure used to interface in "C" between Kodi and the add-on.
    *
    * See @ref AddonGameControllerLayout for description of values.
    */
  typedef struct game_controller_layout
  {
    char* controller_id;
    bool provides_input; // False for multitaps
    char** digital_buttons;
    unsigned int digital_button_count;
    char** analog_buttons;
    unsigned int analog_button_count;
    char** analog_sticks;
    unsigned int analog_stick_count;
    char** accelerometers;
    unsigned int accelerometer_count;
    char** keys;
    unsigned int key_count;
    char** rel_pointers;
    unsigned int rel_pointer_count;
    char** abs_pointers;
    unsigned int abs_pointer_count;
    char** motors;
    unsigned int motor_count;
  } ATTR_PACKED game_controller_layout;

  struct game_input_port;

  //============================================================================
  /// @brief Device that can provide input
  typedef struct game_input_device
  {
    /// @brief ID used in the Kodi controller API, e.g. `game.controller.default`
    const char* controller_id;

    /// @brief The address of the port that the device is connected to
    const char* port_address;

    /// @brief The list of ports that the device can be connected to
    struct game_input_port* available_ports;

    /// @brief The number of ports in the available ports list
    unsigned int port_count;
  } ATTR_PACKED game_input_device;
  //----------------------------------------------------------------------------

  //============================================================================
  /// @brief Port that can provide input
  ///
  typedef struct game_input_port
  {
    /// @brief The type of port
    GAME_PORT_TYPE type;

    /// @brief Required for GAME_PORT_CONTROLLER type
    const char* port_id;

    /// @brief Flag to prevent a port from being disconnected
    ///
    /// Set to true to prevent a disconnection option from appearing in the
    /// GUI.
    ///
    bool force_connected;

    /// @brief Flag to auto-connect this port when a game session begins
    ///
    /// Set to false to start this port disconnected.
    ///
    bool autoconnect;

    /// @brief The list of devices that can be connected to the port
    game_input_device* accepted_devices;

    /// @brief The number of devices in the accepted devices list
    unsigned int device_count;
  } ATTR_PACKED game_input_port;
  //----------------------------------------------------------------------------

  //============================================================================
  /// @brief The input topology is the possible ways to connect input devices
  ///
  /// This represents the logical topology, which is the possible connections that
  /// the game client's logic can handle. It is strictly a subset of the physical
  /// topology. Loops are not allowed.
  ///
  typedef struct game_input_topology
  {
    /// @brief The list of ports on the virtual game console
    game_input_port* ports;

    /// @brief The number of ports
    unsigned int port_count;

    /// @brief A limit on the number of input-providing devices, or -1 for no limit
    int player_limit;
  } ATTR_PACKED game_input_topology;
  //----------------------------------------------------------------------------

  //============================================================================
  /// @brief A digital button event, such as a button press or release
  typedef struct game_digital_button_event
  {
    /// @brief True if the button is pressed, false if it is released
    bool pressed;
  } ATTR_PACKED game_digital_button_event;
  //----------------------------------------------------------------------------

  //============================================================================
  /// @brief An analog button event, such as a trigger press or release
  typedef struct game_analog_button_event
  {
    /// @brief The magnitude of the button press, from 0.0 to 1.0
    float magnitude;
  } ATTR_PACKED game_analog_button_event;
  //----------------------------------------------------------------------------

  //============================================================================
  /// @brief An axis event, such as a joystick or accelerometer
  typedef struct game_axis_event
  {
    /// @brief The position of the axis, from -1.0 to 1.0
    float position;
  } ATTR_PACKED game_axis_event;
  //----------------------------------------------------------------------------

  //============================================================================
  /// @brief An analog stick event, such as a joystick's motion
  ///
  /// Uses a right-handed coordinate system where positive X is right
  /// and positive Y is up.
  ///
  typedef struct game_analog_stick_event
  {
    /// @brief The position of the stick along the X axis, from -1.0 to 1.0
    float x;

    /// @brief The position of the stick along the Y axis, from -1.0 to 1.0
    float y;
  } ATTR_PACKED game_analog_stick_event;
  //----------------------------------------------------------------------------

  //============================================================================
  /// @brief An accelerometer event
  typedef struct game_accelerometer_event
  {
    /// @brief The accelerometer X axis, from -1.0 to 1.0
    float x;

    /// @brief The accelerometer Y axis, from -1.0 to 1.0
    float y;

    /// @brief The accelerometer Z axis, from -1.0 to 1.0
    float z;
  } ATTR_PACKED game_accelerometer_event;
  //----------------------------------------------------------------------------

  //============================================================================
  /// @brief A key event, such as a key press or release
  typedef struct game_key_event
  {
    /// @brief True if the key is pressed, false if it is released
    bool pressed;

    /// @brief If the keypress generates a printing character
    ///
    /// The unicode value contains the character generated. If the key is a
    /// non-printing character, e.g. a function or arrow key, the unicode value
    /// is zero.
    uint32_t unicode;

    /// @brief Modifier keys pressed with the event key
    GAME_KEY_MOD modifiers;
  } ATTR_PACKED game_key_event;
  //----------------------------------------------------------------------------

  //============================================================================
  /// @brief A relative pointer event, such as a mouse motion
  typedef struct game_rel_pointer_event
  {
    /// @brief The relative X position of the pointer
    int x;

    /// @brief The relative Y position of the pointer
    int y;
  } ATTR_PACKED game_rel_pointer_event;
  //----------------------------------------------------------------------------

  //============================================================================
  /// @brief An absolute pointer event, such as a touchscreen or tablet motion
  typedef struct game_abs_pointer_event
  {
    /// @brief True if the pointer is pressed, false if it is released
    bool pressed;

    /// @brief The absolute X position of the pointer
    float x;

    /// @brief The absolute Y position of the pointer
    float y;
  } ATTR_PACKED game_abs_pointer_event;
  //----------------------------------------------------------------------------

  //============================================================================
  /// @brief A motor vibration event
  typedef struct game_motor_event
  {
    /// @brief The magnitude of the vibration, from 0.0 to 1.0
    float magnitude;
  } ATTR_PACKED game_motor_event;
  //----------------------------------------------------------------------------

  //============================================================================
  /// @brief An input event
  typedef struct game_input_event
  {
    /// @brief The type of input event
    GAME_INPUT_EVENT_SOURCE type;

    /// @brief The ID of the controller that generated the event
    const char* controller_id;

    /// @brief The type of port that the controller is connected to
    GAME_PORT_TYPE port_type;

    /// @brief The address of the port that the controller is connected to
    const char* port_address;

    /// @brief The name of the feature that generated the event
    const char* feature_name;

    union
    {
      /// @brief Digital button event
      struct game_digital_button_event digital_button;

      /// @brief Analog button event
      struct game_analog_button_event analog_button;

      /// @brief Axis event
      struct game_axis_event axis;

      /// @brief Analog stick event
      struct game_analog_stick_event analog_stick;

      /// @brief Accelerometer event
      struct game_accelerometer_event accelerometer;

      /// @brief Key event
      struct game_key_event key;

      /// @brief Relative pointer event
      struct game_rel_pointer_event rel_pointer;

      /// @brief Absolute pointer event
      struct game_abs_pointer_event abs_pointer;

      /// @brief Motor vibration event
      struct game_motor_event motor;
    };
  } ATTR_PACKED game_input_event;
  //----------------------------------------------------------------------------

  ///@}

  //--==----==----==----==----==----==----==----==----==----==----==----==----==--
  /// @defgroup cpp_kodi_addon_game_Defs_EnvironmentTypes 8. Environment types
  /// @ingroup cpp_kodi_addon_game_Defs
  /// @brief **Environment types**
  ///
  ///@{

  //============================================================================
  /// @brief Game system timing
  ///
  struct game_system_timing
  {
    /// @brief FPS of video content.
    double fps;

    /// @brief Sampling rate of audio.
    double sample_rate;
  };
  //----------------------------------------------------------------------------

  ///@}

  //--==----==----==----==----==----==----==----==----==----==----==----==----==--
  /// @defgroup cpp_kodi_addon_game_Defs_RetroAchievementsTypes 9. RetroAchievements types
  /// @ingroup cpp_kodi_addon_game_Defs
  /// @brief **RetroAchievements types**
  ///
  /// The add-on owns the RetroAchievements client and reports events to Kodi
  /// through the `RCOn*()` callbacks of @ref AddonToKodiFuncTable_Game. Kodi is
  /// responsible for presentation only; it performs no RetroAchievements
  /// network I/O and holds no knowledge of the achievement runtime.
  ///
  /// @note All pointers handed to Kodi are owned by the add-on and are only
  /// valid for the duration of the callback. Kodi copies everything it needs to
  /// retain. Any `const char*` may be `NULL`, which Kodi treats as an empty
  /// string. Any array pointer may be `NULL`, in which case its count must be
  /// zero.
  ///
  ///@{

  //============================================================================
  /// @brief **Unlock state of an achievement**
  ///
  typedef enum GAME_RC_UNLOCK_STATE
  {
    /// @brief The achievement has not been earned by this player
    GAME_RC_UNLOCK_STATE_LOCKED = 0,

    /// @brief The achievement was earned outside of hardcore mode
    GAME_RC_UNLOCK_STATE_SOFTCORE = 1,

    /// @brief The achievement was earned in hardcore mode
    GAME_RC_UNLOCK_STATE_HARDCORE = 2,
  } GAME_RC_UNLOCK_STATE;
  //----------------------------------------------------------------------------

  //============================================================================
  /// @brief **A single achievement belonging to the loaded game**
  ///
  typedef struct game_rc_achievement
  {
    /// @brief Unique RetroAchievements ID of the achievement
    unsigned int id;

    /// @brief Title of the achievement, or `NULL` if unknown
    const char* title;

    /// @brief Description of how the achievement is earned, or `NULL`
    const char* description;

    /// @brief URL of the unlocked (full colour) badge, or `NULL`
    const char* badge_url;

    /// @brief URL of the locked (greyscale) badge, or `NULL`
    const char* badge_locked_url;

    /// @brief Point value of the achievement
    unsigned int points;

    /// @brief Whether and how the player has earned this achievement
    GAME_RC_UNLOCK_STATE unlock_state;

    /// @brief Unix time the achievement was earned, or 0 if it was not
    int64_t unlock_time;

    /// @brief Percentage of players who earned this achievement, 0.0 if unknown
    float rarity;

    /// @brief Percentage of players who earned this in hardcore, 0.0 if unknown
    float rarity_hardcore;
  } ATTR_PACKED game_rc_achievement;
  //----------------------------------------------------------------------------

  //============================================================================
  /// @brief **Payload of @ref AddonToKodiFuncTable_Game::RCOnGameLoaded**
  ///
  /// Sent once the add-on has identified the loaded game and resolved its
  /// achievement set.
  ///
  typedef struct game_rc_game_loaded
  {
    /// @brief Unique RetroAchievements ID of the game
    unsigned int game_id;

    /// @brief Title of the game as known to RetroAchievements, or `NULL`
    const char* title;

    /// @brief URL of the game's icon, or `NULL`
    const char* icon_url;

    /// @brief Achievements of the game, or `NULL` if @ref achievement_count is 0
    const game_rc_achievement* achievements;

    /// @brief Number of elements in @ref achievements
    unsigned int achievement_count;
  } ATTR_PACKED game_rc_game_loaded;
  //----------------------------------------------------------------------------

  //============================================================================
  /// @brief **Payload of @ref AddonToKodiFuncTable_Game::RCOnAchievementTriggered**
  ///
  typedef struct game_rc_achievement_triggered
  {
    /// @brief Unique RetroAchievements ID of the achievement
    unsigned int id;

    /// @brief Title of the achievement, or `NULL` if unknown
    const char* title;

    /// @brief Description of the achievement, or `NULL`
    const char* description;

    /// @brief URL of the unlocked badge, or `NULL`
    const char* badge_url;

    /// @brief Point value of the achievement
    unsigned int points;

    /// @brief True if the achievement was earned in hardcore mode
    bool hardcore;
  } ATTR_PACKED game_rc_achievement_triggered;
  //----------------------------------------------------------------------------

  //============================================================================
  /// @brief **Payload of @ref AddonToKodiFuncTable_Game::RCOnLoginResult**
  ///
  typedef struct game_rc_login_result
  {
    /// @brief True if the player was logged in
    bool success;

    /// @brief Account name of the player, or `NULL`
    const char* username;

    /// @brief Display name of the player, or `NULL`
    const char* display_name;

    /// @brief URL of the player's avatar, or `NULL` if the add-on has none
    const char* icon_url;

    /// @brief Total points earned by the player
    unsigned int points;

    /// @brief Reason the login failed, or `NULL` if it succeeded
    const char* error_message;

    /// @brief True if the account or token was rejected, rather than the
    /// attempt failing for some other reason
    ///
    /// Kodi drops the saved token only for this. A login that failed because
    /// RetroAchievements could not be reached leaves it alone, so an outage
    /// does not sign the player out and leave the add-on nothing to reconnect
    /// with.
    bool credentials_rejected;
  } ATTR_PACKED game_rc_login_result;
  //----------------------------------------------------------------------------

  //============================================================================
  /// @brief **Progress towards a single measured achievement**
  ///
  /// Only achievements whose trigger counts something ("Defeat 50 enemies")
  /// have progress worth reporting. The add-on omits the rest, so this array
  /// is usually much shorter than the game's achievement list.
  ///
  /// Sent separately from @ref game_rc_game_loaded because progress changes as
  /// the game is played, whereas the achievement list is resolved once.
  ///
  typedef struct game_rc_achievement_progress
  {
    /// @brief Unique RetroAchievements ID of the achievement
    unsigned int id;

    /// @brief Progress towards the achievement, from 0.0 to 100.0
    float measured_percent;

    /// @brief Human-readable progress such as "45/100", or `NULL`
    const char* measured_progress;
  } ATTR_PACKED game_rc_achievement_progress;
  //----------------------------------------------------------------------------

  ///@}

  //--==----==----==----==----==----==----==----==----==----==----==----==----==--

  /*!
   * @brief Game properties
   *
   * Not to be used outside this header.
   */
  typedef struct AddonProps_Game
  {
    /*!
     * @brief The path of the game client being loaded.
     */
    const char* game_client_dll_path;

    /*!
     * @brief Paths to proxy DLLs used to load the game client.
     */
    const char** proxy_dll_paths;

    /*!
     * @brief Number of proxy DLL paths provided.
     */
    unsigned int proxy_dll_count;

    /*!
     * @brief The "system" directories of the frontend
     *
     * These directories can be used to store system-specific ROMs such as
     * BIOSes, configuration data, etc.
     */
    const char** resource_directories;

    /*!
     * @brief Number of resource directories provided
     */
    unsigned int resource_directory_count;

    /*!
     * @brief The writable directory of the frontend.
     *
     * This directory can be used to store SRAM, memory cards, high scores,
     * etc.
     */
    const char* profile_directory;

    /*!
     * @brief The value of the <supports_vfs> property from addon.xml
     */
    bool supports_vfs;

    /*!
     * @brief The extensions in the <extensions> property from addon.xml
     */
    const char** extensions;

    /*!
     * @brief Number of extensions provided
     */
    unsigned int extension_count;
  } AddonProps_Game;

  typedef void* KODI_GAME_STREAM_HANDLE;

  /*!
   * @brief Structure to transfer the methods from kodi_game_dll.h to Kodi
   */
  struct AddonInstance_Game;

  /*!
   * @brief Game callbacks
   *
   * Not to be used outside this header.
   */
  typedef struct AddonToKodiFuncTable_Game
  {
    KODI_HANDLE kodiInstance;

    bool (*EnableHardwareRendering)(void*, const game_hw_rendering_properties*);
    void (*CloseGame)(KODI_HANDLE kodiInstance);
    double (*GetPlaybackSpeed)(KODI_HANDLE kodiInstance);
    void (*SetGameTiming)(KODI_HANDLE kodiInstance, const struct game_system_timing* timing_info);
    KODI_GAME_STREAM_HANDLE (*OpenStream)(KODI_HANDLE, const struct game_stream_properties*);
    bool (*GetStreamBuffer)(KODI_HANDLE,
                            KODI_GAME_STREAM_HANDLE,
                            unsigned int,
                            unsigned int,
                            struct game_stream_buffer*);
    void (*AddStreamData)(KODI_HANDLE, KODI_GAME_STREAM_HANDLE, const struct game_stream_packet*);
    void (*ReleaseStreamBuffer)(KODI_HANDLE, KODI_GAME_STREAM_HANDLE, struct game_stream_buffer*);
    void (*CloseStream)(KODI_HANDLE, KODI_GAME_STREAM_HANDLE);
    game_proc_address_t (*HwGetProcAddress)(KODI_HANDLE kodiInstance, const char* symbol);
    bool (*InputEvent)(KODI_HANDLE kodiInstance, const struct game_input_event* event);
    void (*RCOnGameLoaded)(KODI_HANDLE kodiInstance, const struct game_rc_game_loaded* data);
    void (*RCOnAchievementTriggered)(KODI_HANDLE kodiInstance,
                                     const struct game_rc_achievement_triggered* data);
    void (*RCOnGameCompleted)(KODI_HANDLE kodiInstance, const char* title, bool hardcore);
    void (*RCOnRichPresenceUpdated)(KODI_HANDLE kodiInstance, const char* evaluation);
    void (*RCOnLoginResult)(KODI_HANDLE kodiInstance, const struct game_rc_login_result* data);

    void (*RCOnAchievementProgress)(KODI_HANDLE kodiInstance,
                                    const struct game_rc_achievement_progress* progress,
                                    unsigned int count);
    void (*RCOnServerError)(KODI_HANDLE kodiInstance, const char* message, const char* api);
    void (*RCOnConnectionChanged)(KODI_HANDLE kodiInstance, bool connected);
  } AddonToKodiFuncTable_Game;

  /*!
   * @brief Game function hooks
   *
   * Not to be used outside this header.
   */
  typedef struct KodiToAddonFuncTable_Game
  {
    KODI_HANDLE addonInstance;

    GAME_ERROR(__cdecl* LoadGame)(const struct AddonInstance_Game*, const char*);
    GAME_ERROR(__cdecl* LoadGameSpecial)
    (const struct AddonInstance_Game*, enum SPECIAL_GAME_TYPE, const char**, size_t);
    GAME_ERROR(__cdecl* LoadStandalone)(const struct AddonInstance_Game*);
    GAME_ERROR(__cdecl* UnloadGame)(const struct AddonInstance_Game*);
    GAME_ERROR(__cdecl* GetGameTiming)
    (const struct AddonInstance_Game*, struct game_system_timing*);
    GAME_REGION(__cdecl* GetRegion)(const struct AddonInstance_Game*);
    bool(__cdecl* RequiresGameLoop)(const struct AddonInstance_Game*);
    GAME_ERROR(__cdecl* RunFrame)(const struct AddonInstance_Game*);
    GAME_ERROR(__cdecl* Reset)(const struct AddonInstance_Game*);
    GAME_ERROR(__cdecl* HwContextReset)(const struct AddonInstance_Game*);
    GAME_ERROR(__cdecl* HwContextDestroy)(const struct AddonInstance_Game*);
    GAME_ERROR(__cdecl* AudioAvailable)(const AddonInstance_Game*);
    bool(__cdecl* HasFeature)(const struct AddonInstance_Game*, const char*, const char*);
    game_input_topology*(__cdecl* GetTopology)(const struct AddonInstance_Game*);
    void(__cdecl* FreeTopology)(const struct AddonInstance_Game*, struct game_input_topology*);
    void(__cdecl* SetControllerLayouts)(const struct AddonInstance_Game*,
                                        const struct game_controller_layout*,
                                        unsigned int);
    bool(__cdecl* EnableKeyboard)(const struct AddonInstance_Game*, bool, const char*);
    bool(__cdecl* EnableMouse)(const struct AddonInstance_Game*, bool, const char*);
    bool(__cdecl* ConnectController)(const struct AddonInstance_Game*,
                                     bool,
                                     const char*,
                                     const char*);
    bool(__cdecl* InputEvent)(const struct AddonInstance_Game*, const struct game_input_event*);
    size_t(__cdecl* SerializeSize)(const struct AddonInstance_Game*);
    GAME_ERROR(__cdecl* Serialize)(const struct AddonInstance_Game*, uint8_t*, size_t);
    GAME_ERROR(__cdecl* Deserialize)(const struct AddonInstance_Game*, const uint8_t*, size_t);
    GAME_ERROR(__cdecl* CheatReset)(const struct AddonInstance_Game*);
    GAME_ERROR(__cdecl* GetMemory)
    (const struct AddonInstance_Game*, enum GAME_MEMORY, uint8_t**, size_t*);
    GAME_ERROR(__cdecl* SetCheat)
    (const struct AddonInstance_Game*, unsigned int, bool, const char*);
    bool(__cdecl* GetEjectState)(const AddonInstance_Game*);
    GAME_ERROR(__cdecl* SetEjectState)(const AddonInstance_Game*, bool);
    unsigned int(__cdecl* GetImageIndex)(const AddonInstance_Game*);
    GAME_ERROR(__cdecl* SetImageIndex)(const AddonInstance_Game*, unsigned int);
    unsigned int(__cdecl* GetImageCount)(const AddonInstance_Game*);
    GAME_ERROR(__cdecl* AddImageIndex)(const AddonInstance_Game*);
    GAME_ERROR(__cdecl* ReplaceImageIndex)(const AddonInstance_Game*, unsigned int, const char*);
    GAME_ERROR(__cdecl* RemoveImageIndex)(const AddonInstance_Game*, unsigned int);
    GAME_ERROR(__cdecl* SetInitialImage)(const AddonInstance_Game*, unsigned int, const char*);
    char*(__cdecl* GetImagePath)(const AddonInstance_Game*, unsigned int);
    char*(__cdecl* GetImageLabel)(const AddonInstance_Game*, unsigned int);
    GAME_ERROR(__cdecl* SetRetroAchievementsCredentials)
    (const AddonInstance_Game*, const char*, const char*);
    GAME_ERROR(__cdecl* ActivateAchievement)(const AddonInstance_Game*, unsigned int, const char*);
    GAME_ERROR(__cdecl* GetCheevoUrlId)
    (const AddonInstance_Game*,
     void(__cdecl*)(const void*, const char*, unsigned int),
     const void*);
    size_t(__cdecl* AchievementStateSize)(const struct AddonInstance_Game*);
    GAME_ERROR(__cdecl* SerializeAchievements)
    (const struct AddonInstance_Game*, uint8_t*, size_t);
    GAME_ERROR(__cdecl* DeserializeAchievements)
    (const struct AddonInstance_Game*, const uint8_t*, size_t);
    void(__cdecl* FreeString)(const AddonInstance_Game*, char*);
  } KodiToAddonFuncTable_Game;

  /*!
   * @brief Game instance
   *
   * Not to be used outside this header.
   */
  typedef struct AddonInstance_Game
  {
    struct AddonProps_Game* props;
    struct AddonToKodiFuncTable_Game* toKodi;
    struct KodiToAddonFuncTable_Game* toAddon;
  } AddonInstance_Game;

#ifdef __cplusplus
}
#endif /* __cplusplus */

#endif /* !C_API_ADDONINSTANCE_GAME_H */
