pax_global_header00006660000000000000000000000064144514564150014523gustar00rootroot0000000000000052 comment=2dcc3e2e9f0d7be38442bdcb6afbd15298ec677f game.libretro-20.2.4-Nexus/000077500000000000000000000000001445145641500154425ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/.github/000077500000000000000000000000001445145641500170025ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/.github/workflows/000077500000000000000000000000001445145641500210375ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/.github/workflows/sync-addon-metadata-translations.yml000066400000000000000000000023771445145641500301270ustar00rootroot00000000000000name: Sync addon metadata translations on: push: branches: [ Matrix, Nexus ] paths: - '**addon.xml' - '**resource.language.**strings.po' jobs: default: if: github.repository == 'kodi-game/game.libretro' runs-on: ubuntu-latest steps: - name: Checkout repository uses: actions/checkout@v2 with: path: project - name: Set up Python uses: actions/setup-python@v2 with: python-version: '3.9' - name: Install dependencies run: | python -m pip install --upgrade pip python -m pip install git+https://github.com/xbmc/sync_addon_metadata_translations.git - name: Run sync-addon-metadata-translations run: | sync-addon-metadata-translations working-directory: ./project - name: Create PR for sync-addon-metadata-translations changes uses: peter-evans/create-pull-request@v3.10.0 with: commit-message: Sync of addon metadata translations title: Sync of addon metadata translations body: Sync of addon metadata translations triggered by ${{ github.sha }} branch: amt-sync delete-branch: true path: ./project reviewers: gade01game.libretro-20.2.4-Nexus/.gitignore000066400000000000000000000011041445145641500174260ustar00rootroot00000000000000# build artifacts build/ game.*/addon.xml # Debian build files debian/changelog debian/files debian/*.log debian/*.substvars debian/.debhelper/ debian/tmp/ debian/kodi-game-*/ obj-x86_64-linux-gnu/ # commonly used editors # vim *.swp # Eclipse *.project *.cproject .classpath *.sublime-* .settings/ # KDevelop 4 *.kdev4 # gedit *~ # CLion /.idea # clion .idea/ # to prevent add after a "git format-patch VALUE" and "git add ." call /*.patch # to prevent add if project code opened by Visual Studio over CMake file .vs/ # General MacOS .DS_Store .AppleDouble .LSOverride game.libretro-20.2.4-Nexus/.travis.yml000066400000000000000000000043371445145641500175620ustar00rootroot00000000000000language: cpp # # Define the build matrix # # Travis defaults to building on Ubuntu Trusty when building on # Linux. We need Xenial in order to get up to date versions of # cmake and g++. # env: global: - app_id=game.libretro matrix: include: - os: linux dist: xenial sudo: required compiler: gcc - os: linux dist: xenial sudo: required compiler: clang - os: linux dist: bionic sudo: required compiler: gcc env: DEBIAN_BUILD=true - os: linux dist: focal sudo: required compiler: gcc env: DEBIAN_BUILD=true - os: osx osx_image: xcode10.2 before_install: - if [[ $DEBIAN_BUILD == true ]]; then sudo add-apt-repository -y ppa:team-xbmc/ppa; fi - if [[ $DEBIAN_BUILD == true ]]; then sudo apt-get update; fi - if [[ $DEBIAN_BUILD == true ]]; then sudo apt-get install fakeroot; fi # # The addon source is automatically checked out in $TRAVIS_BUILD_DIR, # we'll put the Kodi source on the same level # before_script: - if [[ $DEBIAN_BUILD != true ]]; then cd $TRAVIS_BUILD_DIR/..; fi - if [[ $DEBIAN_BUILD != true ]]; then git clone --branch master --depth=1 https://github.com/xbmc/xbmc.git; fi - if [[ $DEBIAN_BUILD != true ]]; then cd ${app_id} && mkdir build && cd build; fi - if [[ $DEBIAN_BUILD != true ]]; then mkdir -p definition/${app_id}; fi - if [[ $DEBIAN_BUILD != true ]]; then echo ${app_id} $TRAVIS_BUILD_DIR $TRAVIS_COMMIT > definition/${app_id}/${app_id}.txt; fi - if [[ $DEBIAN_BUILD != true ]]; then cmake -DADDONS_TO_BUILD=${app_id} -DADDON_SRC_PREFIX=$TRAVIS_BUILD_DIR/.. -DADDONS_DEFINITION_DIR=$TRAVIS_BUILD_DIR/build/definition -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=$TRAVIS_BUILD_DIR/../xbmc/addons -DPACKAGE_ZIP=1 $TRAVIS_BUILD_DIR/../xbmc/cmake/addons; fi - if [[ $DEBIAN_BUILD == true ]]; then wget https://raw.githubusercontent.com/xbmc/xbmc/master/xbmc/addons/kodi-dev-kit/tools/debian-addon-package-test.sh && chmod +x ./debian-addon-package-test.sh; fi - if [[ $DEBIAN_BUILD == true ]]; then sudo apt-get build-dep $TRAVIS_BUILD_DIR; fi script: - if [[ $DEBIAN_BUILD != true ]]; then make; fi - if [[ $DEBIAN_BUILD == true ]]; then ./debian-addon-package-test.sh $TRAVIS_BUILD_DIR; fi game.libretro-20.2.4-Nexus/CMakeLists.txt000066400000000000000000000106751445145641500202130ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.5) project(game.libretro) list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake) find_package(Kodi REQUIRED) find_package(LibretroCommon REQUIRED) find_package(TinyXML REQUIRED) find_package(Rcheevos REQUIRED) include_directories(${KODI_INCLUDE_DIR} ${PROJECT_SOURCE_DIR}/src ${LIBRETRO_COMMON_INCLUDE_DIRS} ${TINYXML_INCLUDE_DIRS} ${RCHEEVOS_INCLUDE_DIRS}) list(APPEND DEPLIBS ${TINYXML_LIBRARIES}) list(APPEND DEPLIBS ${RCHEEVOS_LIBRARIES}) if(WIN32) find_package(dlfcn-win32 REQUIRED) list(APPEND DEPLIBS ${dlfcn-win32_LIBRARIES}) include_directories(${dlfcn-win32_INCLUDE_DIRS}) endif() set(LIBRETRO_SOURCES src/client.cpp src/audio/AudioStream.cpp src/audio/SingleFrameAudio.cpp src/cheevos/Cheevos.cpp src/cheevos/CheevosEnvironment.cpp src/cheevos/CheevosFrontendBridge.cpp src/GameInfoLoader.cpp src/input/ButtonMapper.cpp src/input/ControllerLayout.cpp src/input/ControllerTopology.cpp src/input/DefaultControllerTranslator.cpp src/input/DefaultKeyboardTranslator.cpp src/input/InputManager.cpp src/input/InputTranslator.cpp src/input/LibretroDevice.cpp src/input/LibretroDeviceInput.cpp src/libretro/ClientBridge.cpp src/libretro/FrontendBridge.cpp src/libretro/LibretroDLL.cpp src/libretro/LibretroEnvironment.cpp src/libretro/LibretroResources.cpp src/libretro/LibretroTranslator.cpp src/libretro/MemoryMap.cpp src/log/Log.cpp src/log/LogAddon.cpp src/log/LogConsole.cpp src/settings/LanguageGenerator.cpp src/settings/LibretroSetting.cpp src/settings/LibretroSettings.cpp src/settings/Settings.cpp src/settings/SettingsGenerator.cpp src/utils/Timer.cpp src/video/VideoGeometry.cpp src/video/VideoStream.cpp) set(LIBRETRO_HEADERS src/GameInfoLoader.h src/audio/AudioStream.h src/audio/SingleFrameAudio.h src/input/ButtonMapper.h src/cheevos/Cheevos.h src/input/ControllerLayout.h src/input/ControllerTopology.h src/input/DefaultControllerDefines.h src/input/DefaultControllerTranslator.h src/input/DefaultKeyboardDefines.h src/input/DefaultKeyboardTranslator.h src/input/InputDefinitions.h src/input/InputManager.h src/input/InputTranslator.h src/input/InputTypes.h src/input/LibretroDevice.h src/input/LibretroDeviceInput.h src/libretro/ClientBridge.h src/libretro/FrontendBridge.h src/libretro/LibretroDefines.h src/libretro/LibretroDLL.h src/libretro/LibretroEnvironment.h src/libretro/LibretroResources.h src/libretro/LibretroTranslator.h src/libretro/MemoryMap.h src/log/ILog.h src/log/LogAddon.h src/log/LogConsole.h src/log/Log.h src/settings/LanguageGenerator.h src/settings/LibretroSetting.h src/settings/LibretroSettings.h src/settings/SettingsGenerator.h src/settings/Settings.h src/settings/SettingsTypes.h src/utils/Timer.h src/video/VideoGeometry.h src/video/VideoStream.h) build_addon(${PROJECT_NAME} LIBRETRO DEPLIBS) if(ENABLE_INTERNAL_LIBRETROCOMMON) add_dependencies(${PROJECT_NAME} libretro-common) endif() if(ENABLE_INTERNAL_RCHEEVOS) add_dependencies(${PROJECT_NAME} rcheevos) endif() include(CPack) game.libretro-20.2.4-Nexus/Jenkinsfile000066400000000000000000000001241445145641500176230ustar00rootroot00000000000000buildPlugin(version: "Nexus", ppa_depends_tarballs: ['libretro-common','rcheevos']) game.libretro-20.2.4-Nexus/LICENSE.md000066400000000000000000000355061445145641500170570ustar00rootroot00000000000000The GNU General Public License, Version 2, June 1991 (GPLv2) ============================================================ > Copyright (C) 1989, 1991 Free Software Foundation, Inc. > 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble -------- The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. Terms And Conditions For Copying, Distribution And Modification --------------------------------------------------------------- **0.** This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. **1.** You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. **2.** You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: * **a)** You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. * **b)** You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. * **c)** If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. **3.** You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: * **a)** Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, * **b)** Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, * **c)** Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. **4.** You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. **5.** You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. **6.** Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. **7.** If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. **8.** If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. **9.** The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. **10.** If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. No Warranty ----------- **11.** BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. **12.** IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. game.libretro-20.2.4-Nexus/Readme.md000066400000000000000000000130451445145641500171640ustar00rootroot00000000000000# Libretro wrapper for Kodi's Game API This add-on provides a wrapper that allows Libretro cores to be loaded as game add-ons. Libretro cores are shared libraries that use the Libretro API, so the wrapper is responsible for translating function calls between the Libretro API and the Game API. This add-on depends on the Game API, which was added in Kodi 18 (Leia). [![License: GPL-2.0-or-later](https://img.shields.io/badge/License-GPL%20v2+-blue.svg)](LICENSE.md) [![Build Status](https://dev.azure.com/teamkodi/kodi-game/_apis/build/status/kodi-game.game.libretro?branchName=Nexus)](https://dev.azure.com/teamkodi/kodi-game/_build/latest?definitionId=25&branchName=Nexus) [![Build Status](https://jenkins.kodi.tv/view/Addons/job/kodi-game/job/game.libretro/job/Nexus/badge/icon)](https://jenkins.kodi.tv/blue/organizations/jenkins/kodi-game%2Fgame.libretro/branches/) ## Loading mechanism In Kodi, a game add-on can import another game add-on in its `addon.xml` file. The imported add-on will be loaded instead of the actual add-on, and it is given the original add-on's path as a parameter. If multiple game add-ons are imported, the first will be loaded and given the list of imports, starting with itself and ending with the original game add-on. Using this strategy, Libretro cores import game.libretro, so Kodi loads game.libretro's library in place of the libretro core and passes it the path to the core. game.libretro in turns loads the Libretro core and begins translating function calls to and from the core. ## Building Building this add-on requires Kodi's internal CMake-based build system for binary add-ons. If you are cross-compiling or just packaging the add-on, it is recommended that you use the Makefile provided with Kodi. The Makefile will download, build and install the add-on and its dependencies. There is no need to manually clone the add-on if Kodi's source is available. The version fetched by Kodi's build system is defined by a text file included with Kodi at [project/cmake/addons/addons/game.libretro](https://github.com/garbear/xbmc/tree/retroplayer-15.2/project/cmake/addons/addons/game.libretro) or fetched from the [binary add-ons repo](https://github.com/xbmc/repo-binary-addons) specified in [cmake/addons/bootstrap/repositories/binary-addons.txt](https://github.com/xbmc/xbmc/blob/master/cmake/addons/bootstrap/repositories/binary-addons.txt). ### Building on Linux First, make sure Kodi's add-on build system is installed somewhere. You can perform a system install (to `/usr/local`) or a local install (I prefer `$HOME/kodi`). Specify this when you build Kodi: ```shell ./bootstrap ./configure --prefix=$HOME/kodi make make install ``` Now, run the Makefile with the path to the build system: ```shell cd tools/depends/target/binary-addons make PREFIX=$HOME/kodi ADDONS="game.libretro" ``` You can specify multiple add-ons, and wildcards are accepted too. For example, `ADDONS="pvr.*"` will build all pvr add-ons. On Linux this performs a cross-compile install, so to package the add-on you'll need to copy the library and add-on files manually: ```shell mkdir game.libretro cp -r $HOME/kodi/share/kodi/addons/game.libretro/ . cp -r $HOME/kodi/lib/kodi/addons/game.libretro/ . ``` To rebuild the add-on or compile a different one, clean the build directory: ```shell make clean ``` ### Building on OSX Building on OSX is similar to Linux, but all the paths are determined for you. This command will download, build and install the add-on to the `addons/` directory in your Kodi repo: ```shell cd tools/depends/target/binary-addons make ADDONS="game.libretro" ``` ### Building on Windows First, download and install [CMake](http://www.cmake.org/download/). To compile on windows, open a command prompt at `tools\buildsteps\win32` and run the script: ``` make-addons.bat install game.libretro ``` ## Developing When developing, compiling from a git repo is more convenient than repeatedly pushing changes to a remote one for Kodi's Makefile. ### Developing on Linux The add-on requires several dependencies to build properly. Like Kodi's build system, you can perform a system install or a local one. With these dependencies in place, the add-on can be built: ```shell git clone https://github.com/kodi-game/game.libretro.git cd game.libretro mkdir build cd build cmake -DCMAKE_BUILD_TYPE=Debug \ -DCMAKE_PREFIX_PATH=$HOME/kodi \ -DCMAKE_INSTALL_PREFIX=$HOME/workspace/kodi/addons \ -DPACKAGE_ZIP=1 \ .. make make install ``` where `$HOME/workspace/kodi` symlinks to the directory you cloned Kodi into. ### Developing on Windows This instructions here came from this helpful [forum post](http://forum.kodi.tv/showthread.php?tid=173361&pid=2097898#pid2097898). First, open `tools\windows\prepare-binary-addons-dev.bat` and change `-DCMAKE_BUILD_TYPE=Debug ^` to `-DCMAKE_BUILD_TYPE=Release ^`. Open a command prompt at `tools\windows` and run the script: ```shell prepare-binary-addons-dev.bat game.libretro ``` Open `cmake\addons\build\kodi-addons.sln` and build the solution. This downloads the add-on from the version specified in its text file (see above) and creates a Visual Studio project for it. If the build fails, try running it twice. This should package and copy the add-on to the `addons/` directory. If not, you can try opening the solution `cmake\addons\build\-prefix\src\-build\.sln` and building the INSTALL project or, worse case, copy by hand. game.libretro-20.2.4-Nexus/Schema.md000066400000000000000000000033351445145641500171700ustar00rootroot00000000000000# Schema for button map and controller topology Data is provided in two files: 1. buttonmap.xml 2. topology.xml ## buttonmap.xml A button map has the following properties: 1. Button map schema version 2. List of controllers A controller has the following properties: 1. Controller ID (equal to Kodi add-on ID) 2. Libretro device type (from the libretro API) 3. Libretro subclass index (defined by the core) 4. List of features The purpose of the properties is to assign the libretro device type and subclass to the specified add-on ID. A `` tag maps a feature name to a libretro constant. It has the following properties: 1. Feature name (from the kodi-game-controllers repo) 2. Libretro constant (from the libretro API) ## topology.xml The controller topology defines the possible ways that input devices can be connected. The root tag is `` because this describes the topology that the emulator's logic is capable of. The topology has the following properties: * Player limit (max number of players handled by the core, needed for FCEUmm) The topology of the emulator is a tree structure, with hubs and daisy-chainable controllers as nodes. The root of the topology is a list of ports on the virtual game console. Ports have the following properties: 1. Port type 2. Port ID (optional for keyboard and mouse) 3. List of accepted controllers The port type is one of the following: * `keyboard` * `mouse` * `controller` The port ID is derived from the port's physical connector or the 1-indexed player number on the virtual console. Accepted controllers have the following properties: 1. Add-on ID 2. List of ports Ports accept controllers and controllers have ports, so data can be operated on recursively. game.libretro-20.2.4-Nexus/appveyor.yml000066400000000000000000000030121445145641500200260ustar00rootroot00000000000000version: BuildNr.{build} image: Visual Studio 2022 shallow_clone: true clone_folder: c:\projects\game.libretro environment: app_id: game.libretro matrix: - GENERATOR: "Visual Studio 17 2022" ARCHITECTURE: Win32 CONFIGURATION: Release CMAKE_DEFINES: -DCMAKE_SYSTEM_NAME=Windows -DCMAKE_SYSTEM_VERSION="10.0.22000.0" - GENERATOR: "Visual Studio 17 2022" ARCHITECTURE: x64 CONFIGURATION: Release CMAKE_DEFINES: -DCMAKE_SYSTEM_NAME=Windows -DCMAKE_SYSTEM_VERSION="10.0.22000.0" - GENERATOR: "Visual Studio 17 2022" ARCHITECTURE: x64 CONFIGURATION: Release CMAKE_DEFINES: -DCMAKE_SYSTEM_NAME=WindowsStore -DCMAKE_SYSTEM_VERSION="10.0.22000.0" - GENERATOR: "Visual Studio 17 2022" ARCHITECTURE: ARM64 CONFIGURATION: Release CMAKE_DEFINES: -DCMAKE_SYSTEM_NAME=WindowsStore -DCMAKE_SYSTEM_VERSION="10.0.22000.0" build_script: - cd .. - git clone --branch master --depth=1 https://github.com/xbmc/xbmc.git - cd %app_id% - mkdir build - cd build - mkdir -p definition\%app_id% - echo %app_id% %APPVEYOR_BUILD_FOLDER% %APPVEYOR_REPO_COMMIT% > definition\%app_id%\%app_id%.txt - cmake -T host=x64 -G "%GENERATOR%" -A %ARCHITECTURE% %CMAKE_DEFINES% -DADDONS_TO_BUILD=%app_id% -DCMAKE_BUILD_TYPE=%CONFIGURATION% -DADDONS_DEFINITION_DIR=%APPVEYOR_BUILD_FOLDER%/build/definition -DADDON_SRC_PREFIX=../.. -DCMAKE_INSTALL_PREFIX=../../xbmc/addons -DPACKAGE_ZIP=1 ../../xbmc/cmake/addons - cmake --build . --config %CONFIGURATION% --target %app_id% game.libretro-20.2.4-Nexus/azure-pipelines.yml000066400000000000000000000035371445145641500213110ustar00rootroot00000000000000variables: app_id: 'game.libretro' trigger: branches: include: - Nexus - releases/* paths: include: - '*' exclude: - 'debian/*' jobs: - job: Windows pool: vmImage: 'windows-2022' strategy: matrix: Win32: GENERATOR: "Visual Studio 17 2022" ARCHITECTURE: Win32 CONFIGURATION: Release Win64: GENERATOR: "Visual Studio 17 2022" ARCHITECTURE: x64 CONFIGURATION: Release Win64-UWP: GENERATOR: "Visual Studio 17 2022" ARCHITECTURE: x64 CONFIGURATION: Release WINSTORE: -DCMAKE_SYSTEM_NAME=WindowsStore -DCMAKE_SYSTEM_VERSION="10.0.17763.0" ARM64-UWP: GENERATOR: "Visual Studio 17 2022" ARCHITECTURE: ARM64 CONFIGURATION: Release WINSTORE: -DCMAKE_SYSTEM_NAME=WindowsStore -DCMAKE_SYSTEM_VERSION="10.0.17763.0" workspace: clean: all steps: - script: | cd .. git clone --branch master --depth=1 https://github.com/xbmc/xbmc.git kodi cd $(Build.SourcesDirectory) mkdir build cd build mkdir "definition/$(app_id)" echo $(app_id) . . > definition/$(app_id)/$(app_id).txt mklink /J "$(Pipeline.Workspace)/$(app_id)" "$(Build.SourcesDirectory)" - task: CMake@1 inputs: workingDirectory: 'build' cmakeArgs: '-T host=x64 -G "$(GENERATOR)" -A $(ARCHITECTURE) $(WINSTORE) -DADDONS_TO_BUILD=$(app_id) -DCMAKE_BUILD_TYPE=$(CONFIGURATION) -DADDONS_DEFINITION_DIR=$(Pipeline.Workspace)/$(app_id)/build/definition -DADDON_SRC_PREFIX=../.. -DCMAKE_INSTALL_PREFIX=../../kodi/addons -DPACKAGE_ZIP=1 ../../kodi/cmake/addons' - task: CMake@1 inputs: workingDirectory: 'build' cmakeArgs: '--build . --config $(CONFIGURATION) --target $(app_id)' game.libretro-20.2.4-Nexus/cmake/000077500000000000000000000000001445145641500165225ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/cmake/FindLibretroCommon.cmake000066400000000000000000000040241445145641500232600ustar00rootroot00000000000000# FindLibretroCommon.cmake # ------- # Finds the libretro-common headers # # This will define the following variables: # # LIBRETRO_COMMON_FOUND - libretro-common was found # LIBRETRO_COMMON_INCLUDE_DIRS - the libretro include directory containing libretro.h # if(ENABLE_INTERNAL_LIBRETROCOMMON) include(ExternalProject) file(STRINGS ${CMAKE_SOURCE_DIR}/depends/common/libretro-common/libretro-common.txt libretrocommonurl REGEX "^libretro-common[\t ]*.+$") string(REGEX REPLACE "^libretro-common[\t ]*(.+)[\t ]*$" "\\1" url "${libretrocommonurl}") # allow user to override the download URL with a local tarball # needed for offline build envs if(LIBRETROCOMMON_URL) get_filename_component(LIBRETROCOMMON_URL "${LIBRETROCOMMON_URL}" ABSOLUTE) else() set(LIBRETROCOMMON_URL ${url}) endif() if(VERBOSE) message(STATUS "LIBRETROCOMMON_URL: ${LIBRETROCOMMON_URL}") endif() set(LIBRETRO_COMMON_INCLUDE_DIR ${CMAKE_BINARY_DIR}/build/depends/include/libretro-common) externalproject_add(libretro-common URL ${LIBRETROCOMMON_URL} DOWNLOAD_DIR ${CMAKE_BINARY_DIR}/download PREFIX ${CMAKE_BINARY_DIR}/build/libretro-common CONFIGURE_COMMAND "" BUILD_COMMAND "" INSTALL_COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_BINARY_DIR}/build/libretro-common/src/libretro-common/include ${LIBRETRO_COMMON_INCLUDE_DIR} BUILD_BYPRODUCTS ${LIBRETRO_COMMON_INCLUDE_DIR}/libretro.h BUILD_IN_SOURCE 1) else() find_path(LIBRETRO_COMMON_INCLUDE_DIR NAMES libretro.h PATH_SUFFIXES libretro-common) endif() include(FindPackageHandleStandardArgs) find_package_handle_standard_args( LibretroCommon REQUIRED_VARS LIBRETRO_COMMON_INCLUDE_DIR ) if(LibretroCommon_FOUND) set(LIBRETRO_COMMON_FOUND true) set(LIBRETRO_COMMON_INCLUDE_DIRS ${LIBRETRO_COMMON_INCLUDE_DIR}) endif() mark_as_advanced(LIBRETRO_COMMON_INCLUDE_DIR) game.libretro-20.2.4-Nexus/cmake/FindRcheevos.cmake000066400000000000000000000042741445145641500221120ustar00rootroot00000000000000# FindRcheevos # ----------- # Finds the Rcheevos library # # This will define the following variables:: # # RCHEEVOS_FOUND - system has Rcheevos # RCHEEVOS_INCLUDE_DIRS - the Rcheevos include directory # RCHEEVOS_LIBRARIES - the Rcheevos libraries # if(ENABLE_INTERNAL_RCHEEVOS) include(ExternalProject) file(STRINGS ${CMAKE_SOURCE_DIR}/depends/common/rcheevos/rcheevos.txt rcheevosurl REGEX "^rcheevos[\t ]*.+$") string(REGEX REPLACE "^rcheevos[\t ]*(.+)[\t ]*$" "\\1" url "${rcheevosurl}") # allow user to override the download URL with a local tarball # needed for offline build envs if(RCHEEVOS_URL) get_filename_component(RCHEEVOS_URL "${RCHEEVOS_URL}" ABSOLUTE) else() set(RCHEEVOS_URL ${url}) endif() if(VERBOSE) message(STATUS "RCHEEVOS_URL: ${RCHEEVOS_URL}") endif() set(RCHEEVOS_INCLUDE_DIR ${CMAKE_BINARY_DIR}/build/depends/include) set(RCHEEVOS_LIBRARY ${CMAKE_BINARY_DIR}/build/depends/lib/librcheevoslib.a) externalproject_add(rcheevos URL ${RCHEEVOS_URL} DOWNLOAD_DIR ${CMAKE_BINARY_DIR}/download PREFIX ${CMAKE_BINARY_DIR}/build/rcheevos PATCH_COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/depends/common/rcheevos/CMakeLists.txt ${CMAKE_BINARY_DIR}/build/rcheevos/src/rcheevos/ CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${CMAKE_BINARY_DIR}/build/depends -DCMAKE_POSITION_INDEPENDENT_CODE=ON BUILD_BYPRODUCTS ${RCHEEVOS_LIBRARY}) else() find_path(RCHEEVOS_INCLUDE_DIR rcheevos.h PATH_SUFFIXES rcheevos PATHS ${PC_RCHEEVOS_INCLUDEDIR}) find_library(RCHEEVOS_LIBRARY NAMES rcheevoslib PATH_SUFFIXES rcheevos PATHS ${PC_RCHEEVOS_LIBDIR}) endif() include(FindPackageHandleStandardArgs) find_package_handle_standard_args(Rcheevos REQUIRED_VARS RCHEEVOS_LIBRARY RCHEEVOS_INCLUDE_DIR) if(RCHEEVOS_FOUND) set(RCHEEVOS_INCLUDE_DIRS ${RCHEEVOS_INCLUDE_DIR}) set(RCHEEVOS_LIBRARIES ${RCHEEVOS_LIBRARY}) endif() mark_as_advanced(RCHEEVOS_LIBRARY RCHEEVOS_INCLUDE_DIR) game.libretro-20.2.4-Nexus/cmake/FindTinyXML.cmake000066400000000000000000000020761445145641500216360ustar00rootroot00000000000000# FindTinyXML # ----------- # Finds the TinyXML library # # This will define the following variables:: # # TINYXML_FOUND - system has TinyXML # TINYXML_INCLUDE_DIRS - the TinyXML include directory # TINYXML_LIBRARIES - the TinyXML libraries # if(PKG_CONFIG_FOUND) pkg_check_modules(PC_TINYXML tinyxml QUIET) endif() find_path(TINYXML_INCLUDE_DIR tinyxml.h PATH_SUFFIXES tinyxml PATHS ${PC_TINYXML_INCLUDEDIR}) find_library(TINYXML_LIBRARY NAMES tinyxml tinyxmlSTL PATH_SUFFIXES tinyxml PATHS ${PC_TINYXML_LIBDIR}) set(TINYXML_VERSION ${PC_TINYXML_VERSION}) include(FindPackageHandleStandardArgs) find_package_handle_standard_args(TinyXML REQUIRED_VARS TINYXML_LIBRARY TINYXML_INCLUDE_DIR VERSION_VAR TINYXML_VERSION) if(TINYXML_FOUND) set(TINYXML_INCLUDE_DIRS ${TINYXML_INCLUDE_DIR}) set(TINYXML_LIBRARIES ${TINYXML_LIBRARY}) endif() mark_as_advanced(TINYXML_INCLUDE_DIR TINYXML_LIBRARY) game.libretro-20.2.4-Nexus/debian/000077500000000000000000000000001445145641500166645ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/debian/changelog.in000066400000000000000000000003131445145641500211400ustar00rootroot00000000000000kodi-game-libretro (#PACKAGEVERSION#-#TAGREV#~#DIST#) #DIST#; urgency=low [ kodi ] * autogenerated dummy changelog -- Garrett Brown Tue, 22 May 2018 21:00:00 +0200 game.libretro-20.2.4-Nexus/debian/compat000066400000000000000000000000021445145641500200620ustar00rootroot000000000000009 game.libretro-20.2.4-Nexus/debian/control000066400000000000000000000012211445145641500202630ustar00rootroot00000000000000Source: kodi-game-libretro Priority: extra Maintainer: Garrett Brown Build-Depends: debhelper (>= 9.0.0), cmake, kodi-addon-dev, libtinyxml-dev Standards-Version: 4.1.2 Section: libs Package: kodi-game-libretro Section: libs Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends} Description: Libretro wrapper for Kodi's Game API Libretro wrapper for Kodi's Game API Package: kodi-game-libretro-dbg Section: debug Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends} Description: debug symbols for Libretro wrapper for Kodi's Game API debug symbols for Libretro wrapper for Kodi's Game API game.libretro-20.2.4-Nexus/debian/copyright000066400000000000000000000016531445145641500206240ustar00rootroot00000000000000Format: http://dep.debian.net/deps/dep5 Upstream-Name: game.libretro Source: https://github.com/kodi-game/game.libretro Files: * Copyright: 2014-2021 Team Kodi License: GPL-2+ This package is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. . This package is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. . You should have received a copy of the GNU General Public License along with this program. If not, see . On Debian systems, the complete text of the GNU General Public License version 2 can be found in "/usr/share/common-licenses/GPL-2". game.libretro-20.2.4-Nexus/debian/kodi-game-libretro.install000066400000000000000000000000261445145641500237270ustar00rootroot00000000000000usr/lib/* usr/share/* game.libretro-20.2.4-Nexus/debian/rules000077500000000000000000000014051445145641500177440ustar00rootroot00000000000000#!/usr/bin/make -f # -*- makefile -*- # Sample debian/rules that uses debhelper. # This file was originally written by Joey Hess and Craig Small. # As a special exception, when this file is copied by dh-make into a # dh-make output file, you may use that output file without restriction. # This special exception was added by Craig Small in version 0.37 of dh-make. # Uncomment this to turn on verbose mode. #export DH_VERBOSE=1 %: dh $@ override_dh_auto_configure: dh_auto_configure -- -DCMAKE_BUILD_TYPE=RelWithDebInfo -DBUILD_SHARED_LIBS=1 -DUSE_LTO=1 -DENABLE_INTERNAL_LIBRETROCOMMON=ON -DLIBRETROCOMMON_URL=libretro-common.tar.gz -DENABLE_INTERNAL_RCHEEVOS=ON -DRCHEEVOS_URL=rcheevos.tar.gz override_dh_installdocs: dh_installdocs --link-doc=kodi-game-libretro game.libretro-20.2.4-Nexus/debian/source/000077500000000000000000000000001445145641500201645ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/debian/source/format000066400000000000000000000000151445145641500213730ustar00rootroot000000000000003.0 (native) game.libretro-20.2.4-Nexus/depends/000077500000000000000000000000001445145641500170645ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/depends/common/000077500000000000000000000000001445145641500203545ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/depends/common/libretro-common/000077500000000000000000000000001445145641500234645ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/depends/common/libretro-common/CMakeLists.txt000066400000000000000000000002041445145641500262200ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.0) project(libretro-common) INSTALL( DIRECTORY include/ DESTINATION include/${PROJECT_NAME} ) game.libretro-20.2.4-Nexus/depends/common/libretro-common/libretro-common.sha256000066400000000000000000000001011445145641500275160ustar00rootroot00000000000000042986fad22dc37188df7a186d17a258edfe8e552353f9b509a47418e8dfa623 game.libretro-20.2.4-Nexus/depends/common/libretro-common/libretro-common.txt000066400000000000000000000001641445145641500273360ustar00rootroot00000000000000libretro-common https://github.com/libretro/libretro-common/archive/50c15a88eb741cbe675743a282d8cc4c89421e3f.tar.gz game.libretro-20.2.4-Nexus/depends/common/rcheevos/000077500000000000000000000000001445145641500221725ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/depends/common/rcheevos/CMakeLists.txt000066400000000000000000000017671445145641500247450ustar00rootroot00000000000000project(rcheevos) cmake_minimum_required(VERSION 3.0) # Disable Lua for now add_definitions(-DRC_DISABLE_LUA) include_directories( include ) add_library(${PROJECT_NAME}lib src/rcheevos/alloc.c src/rcheevos/compat.c src/rcheevos/condition.c src/rcheevos/condset.c src/rcheevos/consoleinfo.c src/rcheevos/format.c src/rcheevos/lboard.c src/rcheevos/memref.c src/rcheevos/operand.c src/rcheevos/richpresence.c src/rcheevos/runtime.c src/rcheevos/runtime_progress.c src/rcheevos/trigger.c src/rcheevos/value.c src/rhash/cdreader.c src/rhash/hash.c src/rhash/md5.c src/rurl/url.c ) #add_dependencies(rcheevos # lua # TODO #) #target_link_libraries(rcheevos # lua #) install(TARGETS ${PROJECT_NAME}lib ARCHIVE DESTINATION lib DESTINATION lib ) install( FILES include/rcheevos.h include/rconsoles.h include/rhash.h include/rurl.h DESTINATION include/${PROJECT_NAME} ) #install( # DIRECTORY # include # DESTINATION # include #) game.libretro-20.2.4-Nexus/depends/common/rcheevos/rcheevos.sha256000066400000000000000000000001011445145641500247320ustar00rootroot00000000000000c8ed6ca74f905ea0c256250e46cced579922880001337e7c3d3d68179ad89d4e game.libretro-20.2.4-Nexus/depends/common/rcheevos/rcheevos.txt000066400000000000000000000001151445145641500245460ustar00rootroot00000000000000rcheevos https://github.com/RetroAchievements/rcheevos/archive/v9.2.0.tar.gz game.libretro-20.2.4-Nexus/depends/common/tinyxml/000077500000000000000000000000001445145641500220605ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/depends/common/tinyxml/CMakeLists.txt000066400000000000000000000011171445145641500246200ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.5) project(tinyxml) set(SOURCES src/tinystr.cpp src/tinyxml.cpp src/tinyxmlerror.cpp src/tinyxmlparser.cpp) if(WIN32) add_definitions(-DWIN32 -D_LIB) endif() add_definitions(-DTIXML_USE_STL) add_library(tinyxml ${SOURCES}) include_directories(${PROJECT_SOURCE_DIR}/include) set(HEADERS ${PROJECT_SOURCE_DIR}/include/tinystr.h ${PROJECT_SOURCE_DIR}/include/tinyxml.h) install(FILES ${HEADERS} DESTINATION ${CMAKE_INSTALL_PREFIX}/include) install(TARGETS tinyxml DESTINATION ${CMAKE_INSTALL_PREFIX}/lib) game.libretro-20.2.4-Nexus/depends/common/tinyxml/tinyxml.sha256000066400000000000000000000001011445145641500245060ustar00rootroot000000000000008164c9ad48b9028667768a584d62f7760cfbfb90d0dd6214ad174403058da10c game.libretro-20.2.4-Nexus/depends/common/tinyxml/tinyxml.txt000066400000000000000000000001111445145641500243160ustar00rootroot00000000000000tinyxml http://mirrors.kodi.tv/build-deps/sources/tinyxml-2.6.2_2.tar.gz game.libretro-20.2.4-Nexus/depends/windows/000077500000000000000000000000001445145641500205565ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/depends/windows/dlfcn-win32/000077500000000000000000000000001445145641500226045ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/depends/windows/dlfcn-win32/0001-dlopen_with_widechar.patch000066400000000000000000000017741445145641500303760ustar00rootroot00000000000000diff --git a/dlfcn.c b/dlfcn.c index 69670d1..8d2dbc0 100644 --- a/dlfcn.c +++ b/dlfcn.c @@ -264,8 +264,19 @@ void *dlopen( const char *file, int mode ) * to UNIX's search paths (start with system folders instead of current * folder). */ - hModule = LoadLibraryExA(lpFileName, NULL, - LOAD_WITH_ALTERED_SEARCH_PATH ); + int wide_len = MultiByteToWideChar(CP_UTF8, 0, lpFileName, -1, 0, 0); + if (wide_len > 0) + { + wchar_t* lpFileNameW = (wchar_t*)malloc(wide_len * sizeof(wchar_t)); + MultiByteToWideChar(CP_UTF8, 0, lpFileName, -1, lpFileNameW, wide_len); + + hModule = LoadLibraryExW(lpFileNameW, NULL, + LOAD_WITH_ALTERED_SEARCH_PATH ); + + free(lpFileNameW); + } + else + hModule = 0; if( MyEnumProcessModules( hCurrentProc, NULL, 0, &dwProcModsAfter ) == 0 ) dwProcModsAfter = 0; game.libretro-20.2.4-Nexus/depends/windows/dlfcn-win32/dlfcn-win32.sha256000066400000000000000000000001011445145641500255540ustar00rootroot00000000000000f18a412e84d8b701e61a78252411fe8c72587f52417c1ef21ca93604de1b9c55 game.libretro-20.2.4-Nexus/depends/windows/dlfcn-win32/dlfcn-win32.txt000066400000000000000000000001151445145641500253700ustar00rootroot00000000000000dlfcn-win32 https://github.com/dlfcn-win32/dlfcn-win32/archive/v1.2.0.tar.gz game.libretro-20.2.4-Nexus/depends/windows/dlfcn-win32/flags.txt000066400000000000000000000000301445145641500244320ustar00rootroot00000000000000-DBUILD_SHARED_LIBS=OFF game.libretro-20.2.4-Nexus/depends/windowsstore/000077500000000000000000000000001445145641500216335ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/depends/windowsstore/dlfcn-win32/000077500000000000000000000000001445145641500236615ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/depends/windowsstore/dlfcn-win32/0001-win10-fixed-uwp-build.patch000066400000000000000000000115531445145641500312260ustar00rootroot00000000000000From f85366b1044fff7b4ea9162c3edcd8278c3e06ff Mon Sep 17 00:00:00 2001 From: Alwin Esch Date: Thu, 22 Aug 2019 19:30:12 +0100 Subject: [PATCH] [win10] fixed uwp build --- dlfcn.c | 43 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 38 insertions(+), 5 deletions(-) diff --git a/dlfcn.c b/dlfcn.c index 69670d1..2d77ca8 100644 --- a/dlfcn.c +++ b/dlfcn.c @@ -19,6 +19,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#define _CRT_SECURE_NO_WARNINGS #ifdef _DEBUG #define _CRTDBG_MAP_ALLOC #include @@ -193,6 +194,7 @@ static void save_err_ptr_str( const void *ptr ) /* Load Psapi.dll at runtime, this avoids linking caveat */ static BOOL MyEnumProcessModules( HANDLE hProcess, HMODULE *lphModule, DWORD cb, LPDWORD lpcbNeeded ) { +#if !defined(WINAPI_FAMILY) || (WINAPI_FAMILY != WINAPI_FAMILY_APP) static BOOL (WINAPI *EnumProcessModulesPtr)(HANDLE, HMODULE *, DWORD, LPDWORD); HMODULE psapi; @@ -206,20 +208,26 @@ static BOOL MyEnumProcessModules( HANDLE hProcess, HMODULE *lphModule, DWORD cb, } return EnumProcessModulesPtr( hProcess, lphModule, cb, lpcbNeeded ); +#else + return 0; +#endif } void *dlopen( const char *file, int mode ) { - HMODULE hModule; - UINT uMode; + HMODULE hModule = NULL; + UINT uMode = 0; current_error = NULL; /* Do not let Windows display the critical-error-handler message box */ +#if !defined(WINAPI_FAMILY) || (WINAPI_FAMILY != WINAPI_FAMILY_APP) uMode = SetErrorMode( SEM_FAILCRITICALERRORS ); +#endif if( file == 0 ) { +#if !defined(WINAPI_FAMILY) || (WINAPI_FAMILY != WINAPI_FAMILY_APP) // what is replacement of GMH on UWP? /* POSIX says that if the value of file is 0, a handle on a global * symbol object must be provided. That object must be able to access * all symbols from the original program file, and any objects loaded @@ -234,6 +242,7 @@ void *dlopen( const char *file, int mode ) if( !hModule ) save_err_ptr_str( file ); +#endif } else { @@ -264,11 +273,29 @@ void *dlopen( const char *file, int mode ) * to UNIX's search paths (start with system folders instead of current * folder). */ +#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) + int result = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, lpFileName, strlen(lpFileName), NULL, 0); + if (result == 0) + return NULL; + + wchar_t* newStr = (wchar_t*)malloc(result*sizeof(wchar_t)); + result = MultiByteToWideChar( CP_UTF8, MB_ERR_INVALID_CHARS, lpFileName, strlen(lpFileName), newStr, result ); + if (result == 0) + { + free( newStr ); + return NULL; + } + + hModule = LoadPackagedLibrary( newStr, 0 ); + free( newStr ); + dwProcModsAfter = 0; +#else // WINAPI_PARTITION_DESKTOP hModule = LoadLibraryExA(lpFileName, NULL, LOAD_WITH_ALTERED_SEARCH_PATH ); if( MyEnumProcessModules( hCurrentProc, NULL, 0, &dwProcModsAfter ) == 0 ) dwProcModsAfter = 0; +#endif /* If the object was loaded with RTLD_LOCAL, add it to list of local * objects, so that its symbols cannot be retrieved even if the handle for @@ -288,7 +315,9 @@ void *dlopen( const char *file, int mode ) } /* Return to previous state of the error-mode bit flags. */ +#if !defined(WINAPI_FAMILY) || (WINAPI_FAMILY != WINAPI_FAMILY_APP) SetErrorMode( uMode ); +#endif return (void *) hModule; } @@ -321,12 +350,14 @@ void *dlsym( void *handle, const char *name ) { FARPROC symbol; HMODULE hCaller; - HMODULE hModule; - HANDLE hCurrentProc; + HMODULE hModule = 0; + HANDLE hCurrentProc = 0; current_error = NULL; symbol = NULL; hCaller = NULL; + +#if !defined(WINAPI_FAMILY) || (WINAPI_FAMILY != WINAPI_FAMILY_APP) // what is replacement of GMH on UWP? hModule = GetModuleHandle( NULL ); hCurrentProc = GetCurrentProcess( ); @@ -358,6 +389,7 @@ void *dlsym( void *handle, const char *name ) if(!hCaller) goto end; } +#endif if( handle != RTLD_NEXT ) { @@ -370,7 +402,7 @@ void *dlsym( void *handle, const char *name ) /* If the handle for the original program file is passed, also search * in all globally loaded objects. */ - +#if !defined(WINAPI_FAMILY) || (WINAPI_FAMILY != WINAPI_FAMILY_APP) if( hModule == handle || handle == RTLD_NEXT ) { HMODULE *modules; @@ -410,6 +442,7 @@ void *dlsym( void *handle, const char *name ) } } } +#endif end: if( symbol == NULL ) -- 2.19.2.windows.1 game.libretro-20.2.4-Nexus/depends/windowsstore/dlfcn-win32/dlfcn-win32.sha256000066400000000000000000000001011445145641500266310ustar00rootroot00000000000000f18a412e84d8b701e61a78252411fe8c72587f52417c1ef21ca93604de1b9c55 game.libretro-20.2.4-Nexus/depends/windowsstore/dlfcn-win32/dlfcn-win32.txt000066400000000000000000000001151445145641500264450ustar00rootroot00000000000000dlfcn-win32 https://github.com/dlfcn-win32/dlfcn-win32/archive/v1.2.0.tar.gz game.libretro-20.2.4-Nexus/depends/windowsstore/dlfcn-win32/flags.txt000066400000000000000000000000301445145641500255070ustar00rootroot00000000000000-DBUILD_SHARED_LIBS=OFF game.libretro-20.2.4-Nexus/game.libretro/000077500000000000000000000000001445145641500201745ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/game.libretro/addon.xml.in000066400000000000000000000046161445145641500224170ustar00rootroot00000000000000 @ADDON_DEPENDS@ @PLATFORM@ GPL-2.0-or-later https://github.com/kodi-game/game.libretro icon.png Libretro kompatibilitetslag til Kodi's Game API Libretro-Kompatibilitätsschicht für Kodis Spiele-API Libretro compatibility layer for Kodi's Game API Capa de compatibilidad de Libretro para la API de juegos de Kodi Couche de compatibilité Libretro pour l'API de jeu de Kodi Libreto Kompatibilis réteg Kodi Játék API-jának Compatibilità libretro per l'API di gioco di Kodi 用于 Kodi æ¸¸æˆ API çš„ Libretro 兼容层 Dette add-on giver en wrapper til libretro-kerner, sÃ¥ de kan indlæses som spil-add-ons. Dieses Addon bietet einen Umwandler für Libretro-Cores, mit dem sie als Spielsystem Add-Ons für Kodi geladen und genutzt werden können. This add-on provides a wrapper for libretro cores, allowing them to be loaded as game add-ons. Este add-on proporciona una capa para los núcleos libretro, lo que les permite ser cargados como add-ons del juego. Cet add-on fournit un wrapper pour les cÅ“urs libretro, leur permettant d'être chargés en tant qu'add-ons de jeu. Questo add-on fornisce un modulo sodtware per i core libretro, consentendo loro di essere caricati come add-on di gioco. 这个æ’件为 libretro 内核æä¾›äº†ä¸€ä¸ªåŒ…装器,å…è®¸å®ƒä»¬ä½œä¸ºæ¸¸æˆæ’件加载。 game.libretro-20.2.4-Nexus/game.libretro/icon.png000066400000000000000000000515301445145641500216360ustar00rootroot00000000000000‰PNG  IHDRôxÔú pHYs  šœ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFRÞIDATxÚìÝy|\õaïýÏ‘F‹µX–dËò&ï¶l¼±`—BnH›¤ IÚz¹·4·I @ ´$’òjÈ“äöi³=éà&·Y lcð"K²dkY»4š‘fŸÑœç3šŒŽ—Ñhû¾_/½šžßÁ3sÖïùßb˜¦‰ˆˆˆÌ.9Ú""" """¢ """ """¢ """ """¢ """ """¢ """ """¢ """ """¢ """ """¢ """ """¢ """ """ """¢ """ """¢ """ """¢ """ """¢ """ """¢ """ """¢ """ """¢ """ """¢ """ """ """¢ """ """¢ """ """¢ """ """¢ """ """¢ """ """¢ """ """¢ """ """¢ """ """ """¢ """ """¢ """ """¢ """ """¢ """ """¢ """ """¢ """ """¢ """ """¢ """ """ """¢ """ """¢ """ """¢ """ """¢ """ """¢ """ """¢ """ """¢ """ """¢ """ """ Ú""" """¢ """ """¢ """ """¢ """ """¢ """ """¢ """ """¢ """ """¢ """ """¢ """ """ """¢ """ """¢ """ """¢ """ """¢ """ """¢ """ """¢ """ """¢ """ """¢ """ """ """¢ """ """¢ """ """¢ """ """¢ """ """¢ """ """¢ """ """¢ """ """¢ """ """ """¢ """ """¢ """ """¢ """SžK›@¦±< X ,…@=Ïr“ÿý0Ð ¸ ˜ÚäSjß—K’û~!0çöýØõ0Ý@{òð^À¿)¢ ’a¥ÀÀ‡[ê úœW_¿ê’Á@&Wp pðG@Í}Nðð3àP2ŠÌ†iê¡F¦åÓßuÀw€UYúÌNà‘ä ¡/ù¤)Ù•Ÿ¼Ùx4‹Ÿû:ð`¯jd&Q™Ž*“7UYüÌ%ÉÀq'Vu³dÿæ¿x(Ë7€+“µ eÚ ¢ 2¹–bUûO†¿>ˆõþY²wZ Ü ||’¾Ã­À"í ™If}€ ybÆÿôòL×·û쉔íÏv؎˰½óöÙg9tè~¿ŸââbòòòÎyû›¦I `½æ]²d Û·oç†n ¨¨È¾êÓX ÅþÝ4Í¡Iøý§=Î÷x|»cël?c~{VíË_f/ïììä—¿ü%‡ÆëõR\\L~~þy[±X ¯×˼yó¸öÚk¹ýöÛÓW¹(yÜÍäïÏô5BD@²ž2 N÷ï%—ŸR{èÐ!^~ùe¼^/†a¤þÎõ÷$Ö«ý¼¼<þã?þƒk¯½–{µk×ÚWÿ€˜a?3MS 'NUò©ÿ3ö‚={öðµ¯}úúz‰DÃ0ÈÉ9¿ŠÍÑÑQ Ã`Þ¼yÌ›7ÏÊNwlëF. "ÙqJkì5kÖðÒK/Ñ××G,ËÈ…9''‡ÁÁA¼^/ßøÆ7¨¨¨°¯ò 0bƯLÓT ñÌ?ýÏÞÃ;ÿ={öð¹Ï}Žææf<££çß6/ý¦^RRBEEµµµN«úµWd&Q™Ž:íã÷½ï}TWWSPPpÊÅý|ÿFGGéîîfÏž=<ù䓸ý§\ÿ‹¯W†1G»%£7ÿààö²ÆÆFvíÚESS}}}Äãñ ÚÏãvhq1×_=·Ýv›ýc›í™Ir~øam…ó¿H]PùD~v¶wú²ó©~?ÇÏ7µX­Â(//gÙ²e¼ù曌ŒŒF3öyáp˜ŽŽ<W]uyyyéÅåÉïò¦a½L@÷ÀLg²^6·d˜ºøP2î.ÜÜÌ®]»xã7èïïÏh;„ŠŠ .¹äžxâ ,X`/þ1ðs¬¶Sê|QP˜2 ŸÁêýÁôå«V­¢ººšúúzü~?‘H$#Ÿ7::J(¢³³Ã0¸êª«ì«,ÅAîMÀ§pA¿ÕlKÖ¬¬K/óx<ìÚµ‹Ý»wÓÛÛK<ÏÈgæää°`Á.¹äž~úiV­:¥w©x h<]ÀSÛ2û_†Œ†ÑÄkÓ jkk)//çСCŒŒŒdì&Ç …BtttP^^ΦM›ì«\ ô†Ñ„ÎëwæËû€w§—% þáþŸýìgtuue´†§¬¬ŒM›6ñÌ3ÏœîÝÿß¿1M34ÏG€YS4 £;yÃ÷¤xÑE122Bss3~¿ÿ‚ˆÙC@$¡©©‰ªª*§›ÅM@‹a-@XàœoþË€»OØË¿ÿýïóýŽB¡Ìå«üü|V¯^Íßÿýß³}ûv§U>üèíº{*ˆ€€@v¿Ç0ІÕ`izÙ¦M›èììÄív3<œ¹^z‘H„p8LSS—^z)ÕÕ§LAð Á0ŒV 2•޳)ÿxÐ^öÜsÏñÔSOÑÞÞžÑ}YXXÈÒ¥K¹óÎ;ùØÇ>æ´ÊÀ÷LÓìÊ磈€À´~-0jF?p¸ kˆàÔÅ}Û¶mìÛ·¾¾¾ŒµˆF£D£Qúúúؾ};sçε¯r3Po†;Ù^Áñ÷+¤þí àvà+ö²ƒòÐCÑÔÔÄððpFý-]º”|àÜwß}Nƒ}kÀ§“œÅ, ¢  }qÃ0z°¦n}Vc<ÀêÓ½|ùröîÝK("fäbš&ñxœááaúûû¹ôÒK)..N_Å܈5ƒœ«­Âyo§™’}ýÿ«Åÿ8<ñÄ_Æn&±XŒ@ @OO—\r .׸Á5«ÒdMÀgQ•<[@²¯ÿ5XÕì•ée===üíßþ-¯¼ò ½½½ãFv¼PóæÍcݺu<þøã§kôw7ðË ÙQ@²ÿB@Öä1ÓËjkkq»Ý´··‡3FGG‰D"´¶¶b†ÓMå" ÔÓyœM•`F>pÖ;ÿqý)}>_ùÊWøÕ¯~ÅÉ“'Ss3dBaa!Ë–-ã¾ûîãÝï~·Ó*Ÿ~lš¦wºž›" Ó>¼ÝkÓ}ža~¬†[“6c`nn.kÖ¬I2öN9 …hiiañâÅNݯÂFöçÑ=p&€dw¿µÀ°ºMŽóÔSOñ£ýˆ®®®ŒáPPPÀ’%Kx÷»ßÍ'?ùI{M XC?kšfÏD›" ûûG ÃZ“7˜Të¼òòrÖ¬YÃ믿ÎððpÆÚŒ…€H$‰'ظq#K—.µ¯r3Vo…Ös 3%†‘ ¬ÀXç/ìå?ùÉOøÖ·¾EkkkF{määä°páB®»î:xà§Fÿørrß$¦òy/¢ 0+€­áß™V%{tãfu©®®¦ªªŠ7Þxƒ@ ñ9¢Ñ(ä²Ë.£ªªÊ¾Ê{ Õ4ÍH¶³)–ÕÈnœçŸž/ùË´¶¶ 3zÜ”——³aþò•¯8MëÜܼy¦FçÚ@UD@@`òD ÃèÄÇ}\£ÀuëÖ …8~ü8¡P(£ÌÂá0@€“'O²cÇ{÷@€wu†a¸±ÚÌŠìëÿQ¬îuãìÙ³‡‡zˆææfFFF2z”••±zõj}ôÑÓ5úûðë3 ó{®¿_@&_Ð0Œ¬–ø—¤lݺ•þþ~Z[[ÉX{€D"A0Äï÷¸âŠ+ìƒÌä;’!à$ËÖq6Y Ù×ÿýœfjßÏ|æ3466244”Ñ?gÎV­ZŽ÷ÞËûÞ÷>§U~òvÃü*ˆ€(LÑp¦ªY[£À%©»p^[¶láÈ‘#ôõõe¼Ú9‰ÐÞÞÎÐÐÓ%X­àß2 £Ë0ŒÑ™ Ã(þðOö²ºº:î¹çŽ9‚ÇãÉè(999ÔÔÔð‰O|‚»îºËi•¾Þè/S ûD@@`j쇄aC@'Ö8ýcÅÅŬ\¹’}ûö2:ÉL<gdd„®®.rrrœ¦®Lþ½ x8ÃÓ5$ûú_<‹50RJOO÷Ýwû÷ïÏè(c᮪ªŠ›nº‰xÀi˜ß±ýµ¤o÷3ýFQ€)ÎÐP+žœ9°k¸à”Å‹³zõj8€ÏçËh£ÀD"A(¢­­ÂÂB.¾øbû*ë°^á cLÇìë)Ö„:«ÓËü~??þ8¿ùÍoRƒ(eRuu5W^y%?ü0‹-²·aÍð÷–išñ3ýÆôÿ_@D`úÕŒ‰$Þ bë¾bÅ JKKyë­·ðù||&hjj¢¤¤„­[·ÚW¹è1 ãš  Ù×=𶘑H„'žx‚û·Ëx_€¹sç²aÞ|òI6lØ`/Žü×™ýeà÷ëâ( S(„“s%ŸNS6nÜÈÀÀ@j¤ÀLÞ˜b±Á`'NpÑEQSSc_å& Å0Œ8Œ0 À"¬î~wÚ˾÷½ïñý'Ofô•ËØÍ¿¦¦†|;v8­ò¿€çMÓ™à߯‹£(Èù_(2ùN4Û¿ål¿ûDþþÓ5 L6 lVkÒ׿ä’KÀívãóù2º}Æ :zôèéÆxÐhF›} áLþþ,•ÀÇ€S.,¿øÅ/xòÉ'imm%dôs‹‹‹Y±bwÞy'wÜq‡Ó*_~hšæàtzˆ™ÐãoºÝh2-¿?›'ñTÜ_Óð"–5ÍÿÆ=Ž÷ôôð‰O|‚Ý»wãõz3Z››Kuu5W\q_ÿú×jÂÀDZF¦óOÃÓ©øðM{ÁîÝ»yðÁilld`` £ÇžË墦¦†;û‚ûjßÃŽ9ˆ(d8óùà pcÓ›šœÛ,pFò¬w– k@›øTÛ_†õã‹’¿»:ù¿Íä…v*\%XÝÓNé#¶wï^>ýéOÓÚÚÊàà`FC@^^‹-âÿøyì±Ç())±¯2ŒõîüHrûåLƒÓ(¸€+€¿³666r÷ÝwsìØ±ŒNí Ö?•••ìØ±ƒ§Ÿ~š 8­ö9¬Þ£StûÉýœƒÕ(Ô—<ç8ËÁ¢&ÁØõnQòz—s×:#ùßÅ“Çïÿí ©° xÖ¤/'OŠLˆb¿Ø—ü¿o÷3‹7ÿJàrà†äõ¶d˜ö~üãóÔSOqüøñŒ¿((( ¦¦†Ûo¿ûï¿ß)ŒM ’Sú4J ­ã¸Ýn¾øÅ/òâ‹/ÒßߟÑQsss™?~jzß«¯¾z¦\–No{€×°f’ôM‘ïV†5ƒã;°´ºŒ´I·2pýöW“¿½~ ýöGmÎÿæ—“¼Ñ«*ù&¬YÎJ3¹€Éë­Àµ@Grt»è$þv—aK±ª«ÿ ¸X†5ÊÝŒ°nÝ:ü~?MMM„B!‰DÆ^¿ŒM!ÜÙÙI<?Ó+gºœN {zzxâ‰'x饗èééÉèÍ?''‡ÒÒRV¬XÁç>÷9ÞùÎwΤËË\ kØèÛ/Ö¼&·V­,ù}¾ü V7Ö’ GeÀà]É¿.ÀÍyÌ¢) gõ6Oþ‹€¿ÄšÓÜ•¥¯;kHÛ× Ãè4 ÃÌt㻳ÙNÀRàX «f$—ËEaa!{öìÁï÷‰D2Zu‹Å‡Ã¸Ýn غuëŒjæóùøÚ×¾ÆÏ~ö3º»»3:»_úÓÿ7ÞÈŸÿùŸ;͹0S·A¬é¤‡'é{äcÕô}?yÊVº-YÒ†^ d\Ž6Áy)Lž LÂg¯Æ6Ím–ÍI~þggÃŽž;w.ùùùäädþTñûýtttðÍo~“§Ÿ~·Û=#¶YKK ßøÆ7xî¹çèêêÊxw¿±@š——ǼyófË5ç!`gòÚ3`Õv–fùs àÁdmƒdúAG›à¼,Äjíü”‘«^zé%ššš2:“æØ ýƒü Û¶mK/º XŒ5”·d*HkœóÁéVØË^yåz{{'äBWYYé˜ ìOçÓ ñUcu÷Kinnæµ×^KUŠÈ…‰Åb òòË/;M–t)V×ã¬ÕJœéz˜ÉɳÆ>ohhˆãÇÛ‹Öc´K&CVŸÏ‡Çã™*âÊÊJ.»ì2ûâ`2{ÖÛÓ´´´044¤£B$ƒâñ8^¯×é¡b³ÓÓxôÙ\sÍ5Ò3‘Hœn–È‹°z#ˆÀ¤YŒ5øMJww÷„´tž3gUUU¬_¿Þ^ô*Ö€Ù”œ2•Ýk¯½†Çã™òïªE¦chkk³­Æj„œmØúâoÙ²…ÊÊJû»ú 6::JCC~ÿ)£a߮0S5z»¿´íµ[—”#GŽLÈûÛ‚‚¶lÙâ4RÜ’ï²Ø¦ëýcJ?/½ô}}}ïç-2›E£Q<uuuNÅ©›àÙ¾öËÀu¢ k$Ò”µk×RQQAQQfÿŒD"¿þõ¯éïïÏh @~~>ìܹ“êêSfÚÜŸ^p®'Ö¹üÁ¸‰n°ÿö¦¦&ÕˆLp @CCƒSñ À¼ó9¿/@ÖÅH"k×ríµ×NHCÀÁÁA>ìT¼H#*dÛüdêNéîîÆãñ022’Ñ'á±på•W:¿ašf¶GÛŒ5ôpÊñãÇiooW €È ¼úê«´´´Ø‹ÞIöÆ ¯ÛnÙ²…9sædôƒFGGñûý§k¹b«e °ߤŒ5‚Ëô{øüü|6oÞÌš5§Ôºÿ [Cœ,(Ä¡çÃ믿Ž×ëU €ÈÖøý~Ž?ξ}ûìÅËq‘t‚%€#ÀÁô…ëÖ­£¸¸8ã]’#‘ÍÍÍN 7bM, /y`/À6g{{û„tÿËËËcíÚµN³ýÙÿ_en·›W_}ŸÏ§î"( Ñ××ÇK/½äT¼6[OÂi9ÀkéeK–,¡¨¨ˆÜÜÌ7IƒNƒ!] ,Ök€lÉÅê{;NOOÏ„Tçææž®û_=ÙŸ¤¸8}AGG---øý~(2âñ8>ŸúúúÓuœ›þ ’…X㤰hÑ¢ ápØ©!`mòO÷/€¬<ýWb›/‰ÐÒÒ2!UàN k4®lÿö…XíRZZZðù|„B!4´ÈÄ ‡ÃŒŒŒ8u‰«*3tc?«ZÓ48ÌÈ·lÙ²Œvû¼p8LSS“SñÕ@‰Ž€lØ„5vŠÛí¦¹¹9ã 77—ââb-Zd/jà<[ÿ_ S†"t»Ýøý~5É‚±¡CXKÚÌ€Yªè·/X³f eee¯…B¼õÖ[¸Ýn{ÑÀ -Ûà?Äçóeô&˜››ËܹsY²d žÒÕõ(ÙŸ {Öä#)‰D‚ººº iü("§¯p¸ VLÒMð$¶¶H[·n¥ªªŠ’’’Œ…€±FõõõNÃoVêÈP˜håÀ¸ùxûûûùÝï~‡×ëÍx÷¿ÊÊJvîÜéTÖ³uÓM>)TàÐõ±­­mB&?g‘Hätm Îu| €qãÔÖÖrÅW0oÞ¼ŒÖƒAúúúxõÕWŠ×¡î€ ì”Fpn·›C‡e¼\~~>ååålذÁ©¸)ùþ-›ª°~ØÓÓC Põ¿HE£Qèìì´]“¼FeÓ ¶žeee\sÍ5”••áreîž‹Åðz½ì߿ߩ;àE¨€À?/Àš ¥££ƒááaB¡PÆ€a²téRV¯^m/~hÏV·—´ÏY†m°‘––B¡‘,ŠÅbtvvÒØØh/Ú ¬³_&¸6 †5%ù86l`îܹ `µðûýô÷÷;Õ”ëè8ª>9»§àqZ[[ñûým˜“““š]kíÚµöâß½YþÝùتÿÇ~{¦'>:Ó6ÉÍÍÅår‘››› &“ÙöÀ0 LÓdtt”xö—í££ŒŒŒÐØØÈÎ;íÅ[ß‘Ý)ÂÏïSSòeË8zôhÆûØÜ+WŽ{í¿ÛpÈ¢Iy8Œ¶U__ÏððpFÁ1 ƒââb6oÞìT¼«ÿm6-v¤/èïï§¹¹9k`Μ9TUU±hÑ"6nÜHUUÑhtÒÚäååQPP€ßïçÈ‘#œŸ7Þxƒgžy†½{÷f=ŒŽŽ¨¯¯§««Ë¶U†aôg#$™¦‰a1 Ù^¶~ýúŒÖk€¦¦&n½õV§ëÔKY®ý˜1Ôà̪“é:¥««‹‘‘‘Œ?çåå±hÑ"jjN™ßãU¬V·Ù”oÿÝo½õ'k5EEEÜrË-Sîæ°iÓ&n¾ùfòóóu–dò‰Ä墼¼œ[o½uÊÜüÁjä¶sçNn¾ùæŒÏ|w.OÁ^¯—'N8Ý'£;`'0”¾`ÅŠg¼ ‰P__O0´íÀj§% · X?îq¼±Ñé ¼`………ÔÖÖ:]\Ž#“Ðýïòôåýýý¼ð ŸúøLßÃår±bÅŠ){p,[¶lB†?Í Ã`Þ¼yNaM 555äååMÊgG£Q<SŸx°&JÕøeiP ^à=”——STT”ÑÑ ÇzA8Lü>û5Z2¡«jmœcÇŽMH•ïœ9sXµj•SQíwaû ¥¥…ÎÎÎŒ}ðv¦ò 6Ó­Å’ŸŸŸjü7Õäåå1Y“ÐÄãq†‡‡9|ø°ÓëÇUÉkV6 `͘²páÂÔ쀙܇cÝ8àT¼ ½Î>¿k˜6ÁiUצ/èìì䨱c6þuµcw^Ï$üöغÿuttdýæÏ‡³ü™Û€ÿ®ÓbÒ¼ü ‹Ÿg›¿šJ!‰ÐÓÓÃàà Œ«ù^”}Yü:A¬Þã®cëׯgÏž=äææf¬¡ôX/ˆ£Gâóùì3¥nKþöA& ,™ð×aõ±Mikk£¥¥%ã5”””8€Às!ÕÿçùßVØôôôL•þÿ&ð#àå,î “ê9à™,æ5À_`›|2§¡ëç¶`µˆïëª:¡'¡Õ0‘¼F³nÝ:æÎK~~~Æ^ŽŽŽ 9tèÝÝÝö°kÂ2€s¤WÎòp¨þ?xð CCCïÿ_ZZÊ‚ X²ä”vŸJB¡Sc8˜œ)r»°z*ýán¼u+×_=%%%«- ¼ùæ›N÷±Å:C2e1¶VðÍÍÍtttd¼ °°ªª*vìØáT|ˆfëG'OÖÀ¸Î¶G¥¯¯oJ‘Ù* ²gÏZ[[íE7K²`|8¼Ž»úê«)--Íèë’X,ÆÐÐS«ÖR¯´2bÉn5cÆÁÅb±Œ>!œnøßÿÂ(›òíÁàСCøHDÎ?477søð)í`·`›¾; âX5•ãz¬\¹2ã㘦I(ÂívãóùìűŠÀ?ŸÒ®££ƒp8œù;n~>6l°ìÖèVÝYNóóí §§'5—jD&_(b``€={ö8o4 #+¤]›N»ÓË.\ÈÂ… 3>f‚išƒA:::ìE—au_€ Þ&§Œ/Ýßß?!ï].K—.u*:„³üÛÙ@{{{j.½™|±X ŸÏǾ}ûðxNé%¼˜›å¯Æ O8Ö­y"ÆÊˆF£œ ¿½ «QJGG@`Bæ>‘ Ç©¯¯§§§Ç^tÙŸ"×ìK_PQQÁ5×\CyyyF{D£Q¼^/{öìqê8 fˆXsk§œúúNi*5 §-U•Œ¿¸œ2okk+###D"‘Œ€ÜÜ\ŠŠŠØ¶m›S€RàjÃ0Öeñç'€ÙvttdtØã‰ºLdµ­^#ÈT•H$œ8q‚«¯¾Ú~]¿Ó0ŒùYþJ+°¦.Oþ³bÅ -ZDSSSF?(‹ éëë³¢¶(×Ñ¡p®òRsCCCƺ\.ÊËËyç;ßé4ÐàÛ“½1|>MMMS6ˆÌv£££øý~Ž9B0´O¾óñäߤª©©ášk®aïÞ½ÿ·#‘ˆS/ˆJÆqg³þ@Z•apqzYÿ„ ƒër¹X°`Û·oŸ²Û¥±±‘úúúiñ àL ÃÔ pæÐ¤M§€ááa^{í5Ün÷”ýž[¶l¡°°0ãÿn(:]ÍÂ=Ü*œ«EXÃI¦´´´àõz3Þ Þ0 JJJ&dŒLH$ì޽ǣ™–a6H$ƒAØ·oß”ýž.—kBx4¥®®¿ßo/Ú†æP8GË€šôn·›P(”ñ>𣣣twwóÆoLÉ‹Ê /¼ÀóÏ?ŸšüHD¦¦H$‚×ëå‡?ü¡S¿ø)ñýöîÝ;!5‰ñx·ÛíÔò5‡p¦MXÿl°/lmm°·§§‡Gy„Ý»w³xñâq­d³=éNnn.†aÇinnæ•W^¡»»{FL¤á‹gŽ·{ŠÌd/ét|ŒŒpüøqî½÷^nºé&*++S×™É|ê« ÕK/½ÄÈÈHÆ?cìHCC[·nM/Z•¼žÁjà, gT•L)‡æææ 9‰âñ8ýýýøý~ZZZR'ËØ…'Û7­±wä‰D‚X,F8&g´çƒˆLÜSvoo/~¿ŸcÇŽ¥®'“9z§a˜¦I,# 3þc½ œŠ/~ŒèQ8c‚6 £xOúòææf'¤`ìÝ]0œ2Oc'ìty‡š­ï˜<>t¥)ktttÜMvldÑÉ>'úóÇ~÷믿Nss³½;à;°z((œñÆ—‡mô?€ƒ2444aàÆN=a‹(ôerûL÷×vçB¡ýýý´´´ØÀ•XmºŽëÌ9=5´ºÿëçñxøÝï~‡ÇãQ#8‘)*‰044D}}½SñJm!€·³ë}QÊXõ¿×ëÔ†4""rz±XŒ¡¡!öíÛçÔæa P ­¤p&UÀòôn·ÇC(R½ˆÈ5Öžª½½ÁÁA{ñ:¬^Eà´N‹·­­mBº­ˆˆHæk‚Á ½½½ö¢dVD€iöû«ì Ož<©ðDD¦‰H$Bgg§}q-¶ÁÝD ]iò —&;::fMKZ‘™ÚÚÚœŠ. µ…œ,®O_pâÄ ººº¦¶·m˜¡ €fß>Ÿ€ýo¢‘䦅p8Ìo¼A¿½h'ÖÌÎ;Ó‹®Ö­ÚJ éæWÛîß¿¿ß¯ÖÿS$äåå9ý©ðý&bŠSíóÓîó«Î×É' SÏØ€@¯¿þº=Œ…÷ßjØe3›_Tc ™RWWÇo¼A0T À0ÖÅgªRPÌ<Ó4 SzŸëÚ0õD£Q†††xñÅ^\Œº*Ø,¶¤/hoog``€p8¬#c ˆÅb§›ècJ¨¯¯×@Qúzzzhmm’ßm¢æ‘ ß7@ÇãÔð"ÔPÀf…}ÁÑ£G" éȘO‚Á`çž{Ž—^ziJÕƒA^~ùeþÏÿù?ê.šañxœÁÁA~üããv»§Ì÷jmmå§?ý)ÿú¯ÿ:¥k(f{-€×ëu긨Ô:Õlm0k”¨q ²®®¿ß¯ñÿ§Ð¶££ƒ/}éKlذòòr¢Ñè¤Ýt ਨ¯×Kcc£Æ‹˜ àñxøéOÊXµjUêXÈæëÃ0p¹\Äãq¢Ñ(ƒƒƒtvv¦¦ñ–©ûÐà\ªPH7Øš¾ »»›ãÇ+ÝO!‘H„þþ~n·—ËE"‘˜´w°†a““Ãèè(Ñh”@  °˜a‰D‚‘‘:::èïïçÍ7ßL-ÏvHŸ"{lŸ‡Ãa½"œâµ'Nœp*Zž¼ßéÕØºuµµµáóùtrO¡4Ç%ë×=™ ïÒo Ù¾)Í–‰DˆÅb O©¹íÓÿdjŠÇã>|¿ßOIIIzÑf¬ž_m%€E؆îèè  ©…ï c7Z™]û]qÉù;ƒƒƒ´µµ±iÓ¦ô¢«°~+¤™ó€µö…n·[­{ED¦±±ÞÇ·­OþÉ, €kÒøý~ÚÚÚô>WDdš€`0H}}½Sñe@±¶ÒìµÀûÒœ8q‚£GªE·ˆÈ ¨8pà€ÓXW µ•foÈ.±/|ã7ðx< ""Ó<øý~ÚÛÛ9v옽ø¬Þ2K@9pyúÇÃîݻҨn""Ó˜išD"†††N7Šè*m¥ÙÛ@kk+ ø|>µ<™æb±^¯—ýû÷;õ Z5œÌÂP ¬L_ÐÜÜŒÇãÑ@""3¤  ÒÖÖFww·½ø" B[iv€S†ƒliiaxxX7‘" pªм³0äâд¥¥Ec{‹ˆÌ ‰D‚P(DOO½h5Ö€@2Ë@)¶ €"‘'NœPë‘&‰ÐÞÞîTt1P¨-4»ÀRàÚô­­­øý~5þ™aB¡û÷ïÇã9eôßXíÁfÑïÜŒ5PÊ‘#GTý/"2…ÃaŽ9Â[o½e/º <«@)ðûƒ¦fš‘™#244”šRÚæb _`vX ìH_ÐØØÈáÇ …BšÞSDd†›Rúõ×_§¿¿ß^| ÖÀp ³À `Kú‚cÇŽÑÕÕE0Ô™""2ÃŒŽŽ¦†îêêr ³~^€Ùrq˜þwÏž=ô÷÷+ˆˆÌP@€¾¾>šššìE«QCÀYækÒƒA<ÈÈȈzˆˆÌP¦i¦¦{w0ëGtÍ‚ßX€mä§@ @ `tt”ÜÜ\rr&&¥7.œŒv†a`¦i¦þ‰Dê‹È,{âËÉ!777um»6eêz0×¼óý7Ó¯u^¯×i•Yßp6€Q ”¾ 77—ššº»» ‡Ã¸\®ÔA6“zŒ›D"A$! ‡‰Åb "³ŒaPTTDQQyyyÖr†Ö‚Æb1FGG)--eÑ¢EN«Œ(Ì| 1}AEEÿøÇY¸p!‡’’’Ôßåš9›¤  —Ë…×ëåðáÃôöö200Àèè¨æ>™… ¨¨ˆÅ‹³víZÖ¯_aù@044D  ¶¶–믿Þ^ìºfý11Kžw¿b–ÿèóùxõÕWùêW¿ÊñãÇéëë#‹éŠ(2‹äääPSSÃ{ßû^î¾ûnjkkgóæø)pÏl³¥àà+³u'—••qË-·pýõ×SPP +¡È,UTTÄ-·Ü2Ûoþ/³>Î’ß9üðï³9ýÏŸ?ŸÑÑQ½ÿ™Å×êêYßûí1àe`ÖÏçšE¿õ8ð0°øÖ@³ŠÛíÆï÷ëý¿È,dš&ÑhŸÏ7[7Á?~ t눘] ÔmÀÏ•XA&Hþß™ðx\|X0¶ ‰°oß>†‡‡U 2K@0äÍ7ßäºë®³¾ DfÈÏÍáÝü†€Î䵿Ðèo³0ŒñõÉ¿™jðgé ¹¹ŸÏ§Æ"³X(bß¾}ôôôØ_ô?Úµ•fU*ž)ÒÆ0¨Å6õqCCƒ†=™å¢Ñ(---=zÔvë€öétMÔL®&G›`Æ).·/ljj"‰hëˆÌbñxœááa>ìT¼ÈÓVRi(™Üã^ðµ¶¶RWWG8ÖF™Åb±~¿Ÿ£GâñxìÅÛ€2m%™¾ÖWØŸþ[[[U 2Ë% B¡ÇŽ£¯¯Ï^¼‰´vC¢ ÓˆaùÀÅö寽öƒƒƒD£Qm$‘YÂá0Çi†¼­ÀBm%™ž*ËÒôôôðâ‹/Ò××§ "D"O×`qúL2³¹´ f”…À–ô 022¢þÿ"’jXWWçT\“¼/ĵ¥T Ó¯`eú‚“'Oâ÷ûuó‘qµ­­­N£n@ dzIVÙUÚ—÷ôôhðÇ4MB¡ÝݧŒˆ{Ö©¢ ÓHžýé ««‹ÑÑQm9¥ ½ý”ÿ6&ÿrµ…džäÏæÏáép}úr¿ßOss³jDı ¾ÞqDô€25Téc psú‚ãÇÓÖÖF<®ö<"2^0dÿþý¸Ýn{ÑûÕÚB ’å§þóTˆmð€}ûöáóùô @DNhhh`ïÞ½ö¢*à"m!™ªìÀívó»ßýŸÏ§q¬èííå׿þ5‰DÂ^¼(ÐVR©¯Û€´´´à÷ûNn™åâñ8^¯—£G288h/^ƒº*Hv™¦yVc’¯ óÓÿ––|>¡PHcˆˆ£p8ÌÈȈSX”«!à̦‘§ÈMÿ-¶/p»ÝUÿ‹È¯=ápØ)¬ʵ…T S[a2­§$ Ž=ªêy[‘HÄ©'@9V×bQ©&­×@ÖÀ)}}}´¶¶´¡DäŒÂáð鿨”è5€€L]5ÀÕé :;;ñûýšýODÞV,£¡¡žž{ÑíÀZm!™šrMØÞÕµ´´ …´uDä¬@gg'ÇŽ³-¶j )ÈÔ4«š.%‘HPWWG0ÔÖ‘·‰Dðz½¼ùæ›Nm†6ÅÚJ 2õ,.O_P__Ïoû[†††´uDämÅãqz{{yá…œ&ÚŠÃ,£¢ “(Ùu°8R:;; ‡Ã¨áŽˆœ­D"A8ÆãñØ‹æbõ4’HãLo> ´î:«V­â†n° “óäææ’›;=g÷4 ƒœ+§Æb1B¡@€@ @$™œ“ÆåbΜ9”––RTT„Ë¥Óh¢Bn$! á÷û …B“Ò­5''‡‚‚ŠŠŠ(..NíóD"1m»Ùš¦I<Ç0 \.¥¥¥¼ë]ïbåÊSfo¼:g&c¶7¿a¥ÀÃÀ½éËc±ƒƒƒŒŒŒd,¤O(4‘aÂþ9.—‹üü|¢Ñ(ÍÍÍüêW¿âÅ_Äívãñx²¾ÿ\.•••ÔÔÔpûí·³cÇÊËË'ì÷O•}”­ýoÿÌ––^|ñÅqû<Ûòó󩨨`Ù²eÜvÛmÜ|óÍ,Y²„ÑÑQ¢Ñè¸Á¶&3hŸË>M­Ÿ››Kii)ÕÕÕN«Þâô”Æí·ßÎÂ… )((ÈöyÆèè(½½½³ihíðYà°ŽÀ™+÷á‡ÖV˜Æ ÃÍ@#PË n±ÛÒÒ—¿üeêëëñù|Yè(??ŸÅ‹óñÜu×]:𲜳nÝ: g-ŽÕ4…Ãa‰W\qyyy3ysÿxø¿¦iz§úq!çO¯fF-@a?Û€ Àj  kNïQ œo}¹5èPHþ{Q÷^™ 1§8tè>ø ```€D"‘µê—ËÅÂ… ¹á†¸ãŽ;œV ofâzvÛy"÷Q¶öºBàÒô ,àþûïgpph4ê4rÝ„ˆÇã  …øáH0ä3ŸùÌ™^±üÙ¾žÃ>2’×þ±ëèL>í¿:MÓÔhb3=X«àÌùýÉ4l$/žeXÝ]É Bâ@úë¢ ù·Ng.ðÇÀßÚ 8À}÷ÝGSSÝÝÝYßgóçÏçÚk¯å©§žrzÿ{ø4С‹øùnç‰ÜGÙØÿN'×ßµìÞ½›ûî»úúú¬·(,,dñâÅÜ|óÍ<úè£TTTØWI¼ds,îsÙGc뎭F¯išÓjüpÕ((Lß°2f°øg†5þÔ§>ž}û"Ën{¤’’.ºè"žyæ.½ôR§U>üÜ4M ½˜ùã£ø8ðu{ù÷¾÷=žzê)ÚÛÛ³>êeaa!K–,á£ý(÷Þ{/eeeöU~ <Ô›¦K?Öí×› ½Íöë—À…Q™ìwp%ð$ÖØã)ýýý<þøã¼òÊ+tuue½ÏõܹsY½z5<ðôGä´Ê'€çMÓÑã# œÄªÚ¾2½|óæÍøý~Z[[SÝ]³%‡éééatt”í۷ۻݭò£†a ©¶D70™­'np ð8pYzy$á±ÇãùçŸO]h³ý”·fÍxàþôOÿÔi•/ÿlšæ öæ„' kVºÕ© Wn.Û·o§¯¯––†‡‡³ú½ÆB@[[óæÍcëÖSæÌ¹ŽþÓ=©ë¦0™Ô P&KVƒ¿{±Mg ðƒü€^x“'Of}Ä¿ÜÜ\.\ÈG?úQ>üá;­òCà¦iöi7N,Ó4G&à«@wzYAAŸüä'Ù°a•••Y¿ŒŒŒàv»ùÖ·¾Åž={œVyë‘ÆÒÕˆ$S{.V5ég€ÚËŸþyž|òIZ[[³~ów¹\TWWsõÕWóùÏžââS&B;<Ôc5´’‰?^F~¬aiÿ8ýÁ¥¤¤„uëÖqàÀ@Ö§Á ðСClذ¥K—ÚW¹h7 £«·ˆž`U  ³ú„]‚õþü¯íåÏ=÷>ú('Nœ`d$û¯Ö,XÀ%—\Â#<âÔ⿸kt´ˆöfv﵆aœÄêuq[zÁÒ¥KY±bÀëõf½¡h$axx˜C‡qõÕWSYyÊÿ­@“a-†aD ÃHݸtSPÙt–vÙËöîÝËC=DSSSÖßéæææRRRš5kxì±Ç¸ì²ËœVû+àEµøŸ´c'œ a^`\«ÌU«VpôèQB¡PVC@"‘  Fñz½\uÕUÌ™3Ǿڻ:À DtSPYs’&ÿæaUá~Ëéæ?Ö×ßëõfý;Λ7åË—óéOš÷¼ç=N«Üü‡išÃÚ£“*dFÖ8ÛÒ 6mÚ„×륣£ƒ@ õa{Ãá0ýýýtwwsÙe—Ù_å7` ´ÓÕ÷^70™'i1p 𿱺u¥ÔÕÕñÉO~’††¼^oÖû6²|ùrî¼óNîºë.§‹Ê×ï©Ñß”9žüÉš€ ¤uu¹\lÙ²…ÎÎNÜnwÖ_!% ô÷÷³cÇûÁs€uXíHú€„n` 2ÓOÒ9ÀàØúñx<|þóŸgÿþý fý柛›Ë‚ xÏ{ÞÃý÷ßï4ÑÌ/€¯mLüèwr–÷ZÃ0™Ö'eEò©ÿQ{ÙË/¿Ì®]»hmm”ÿ999,^¼˜Ûn»û￟üü|û*¿Æv¶5ú›.tÓ0 /V›?JÆ Š‹‹Ù°ao½õƒƒƒ“RÛ‡ ‡Ãœ8q‚«®ºÊiöÀ÷‡±šFu((È´;“s÷áÐ×ÿàÁƒ|îsŸãرc eýi  ¢¢‚믿žÇ{Ìi.÷£ÀçC¦iÆ´W§Õ=nFwò&úþô‚ÊÊJV¯^ÍïÿûI)Ð4MÂá0ÃÃÃtvv²mÛ6§p-p«gƒŽ=™v'b V·¬ïbMö“RWWÇ®]»8|ø0}}}Y¿ùçääPTTĺuëøû¿ÿ{§FYA¬÷þ»MÓTUì4¼ †Åš>ø$ÖÈ{)K—.×(0Ûƒ% Âá0ôöö:X lÅ# uTPit"æaÍÙþ `AzYOO?ü0¿ÿýïéëëËzc,€òòrÖ¬YÃC=Ä7Þè´Ê_ÿðkoNÛÖ{ô±ávw¤—_|ñÅD£QŽ?ÎÈÈHÖÃÑÑQB¡ýýýŒŽŽríµ×ÚWY€5FÀ€GGƒ€€Lø äвú\ÿÛ±©}L†€?ô¡ñ‰O|Âi•NÖZtëh˜1tÓ0Œ¬ž7`Íú÷kkkÙ¿?^¯—h4šõ×Q±XŒX,ÆñãÇ)++cÓ¦MöU®Ãj ÐŒº*(ÈK¿ÁªBç'?ù O?ý4n·¿?û5ëyyyTWWóŽw¼ƒx€¹sçÚWy ø; Ñ4M½sYô„aýX#þ·dP`îܹ¬_¿ž·Þz‹@ @ ýíH$B(¢¥¥åtcÜœ 'H›=Pdª€ÀÀìe{÷îå‘G¡©©iRúú†AEE›7of×®]¬]»Ö¾JK²Öb¿išêz53/èÑä A­Àmé‹/fÙ²eìß¿ŸÏ—õF`uL$ °uëVÊËËí«ÜŠÕ3¥]!@@@¦Ì dF%V_ÿ¯:ÝüxàŽ?ŽÇ39m™æÎ˪U«xøá‡¹êª«œVùð¢†ùÙtÃ0"X톰ÆHYµj±XŒÆÆFÂáð¤ GFñz½´¶¶r饗ڻæïÄêèFÝd²O ´¾þß¶—:tˆO}êSÔ××ãõz'¥¯ii)+V¬àî»ïæƒü Ó*ŸþÕ4Ía³â‚2 £«›ê¸Vw7ndppŽŽü~ÿ¤õ èííÅëõríµ×Ú§*Àš7àÖ°ÁñLoï3 ³¬  ºàŽ[¿ëýä³À¸+•Ûíæ _øo¾ù&ƒƒƒ“róÏËËcÉ’%üÙŸýwß}7.—˾ʷo›¦Ù£½?{.è†aø“OÑaõ ??Ÿ‹.ºˆ'NÐÙÙI0Ìúè”ñx¿ßÇã!‘HpÙe—ÙÛyÀZà Ї5“ n  ’½È0ŒB¬Ê߯ £×ÓÓþð^yåúúú&í·TUUqÓM7ñÐCQ\\l_e7ðVÃ*5ú›]†a aõöøoÉ'kJJJXµj¿ÿýï ƒ„Ãᬇ€±Ñ[ZZH$N¯­–bð&#ÀéüŸNµ ’…(Ù×+ð8Ö¿)‘H„‡~˜ÿüÏÿ¤»»{RžüÁš¾¶¶–G}”šš{ñhô§w©³Ó¨a½Xÿ/½ ªªŠ… rèÐ!ü~?‘HöÛÜÅb1FFFhoo§´´”­[·ÚWÙ„Õ–á(šBX5 Ú gsó¯Åzw~‹½üÛßþ6?øÁèè蘔QþÀzï¿~ýzüq.¿ür§UîÂjô§¹×g·ˆan kØê”uëÖ‘››Ë‘#Gž”cytt45qÐ’%Kœ†¬¾.ùÝg"((h+(œ©<XÜ ü¹½üÙgŸå™gž¡½½}RZQƒõwõêÕ|éK_â]ïz—Ó*Ÿþm¬Ñßtmð$ç.½*?m‡’Ý‹€ËÒ×ߺu+]]]´¶¶â÷û³þ*¬ž@€úúz6lØàT›õÎd-F³aá‰<ÿÓכТ ÿ3yç—¿ü%_þò—imm”iVÁæwéÒ¥Üyçüå_þ¥Ó*OßÃj<¥§ëcÿ;€Õª~3°,}ÚÚZ$ MÊ+­H$B$¡µµ•k®¹ÆiöÀ[cÉ ž¨ó_dö\í•ÀŸa5œgïÞ½<øàƒ477Oʘê.—‹åË—ó‘|„{ï½—¼¼<û*/O­fÚ£œ.z:Ö±† öbõ ¸ k6>ÀCâòË/§®®Ž¾¾¾I ·¡Pˆ@ pº1ÀjÌXoF[r¼QŒ\æ ü£ÓÍÿ³Ÿý,ÇŽchhòæÏ©ªªâÖ[oå‹_ü"¥¥¥öâ#X“6M3®‹ž8ì÷¸a=@ðÇéeee¬_¿ž={öàõz'e«±ÐßßOkk+×]w} á¬Á&ƒL<ƒç¿(È, ÅXó©ÿo`Ü ÍÍÍÜÿýÔ××3000)ïHdžù{ï¿bÅ û*¬ù ^1M3¢‹žœn¿†Nbu¼9½¬ººš‚‚Ž=J(š”6.‰D‚@ €×ë%sÍ5×›››¾JVï€CÉñ œÿ¢ ³ôYš|ªø&ÖÈi)n·›]»v±wïÞÔœæ“aÞ¼y¬^½šû￟o¼Ñi•ÿüÒ4M¿.zrû=dF+0 Œ; 6oÞL4¥¹¹ŸÏ7)íÆÆèèè  ²}ûvû@AUÀr¬×ý†aŒf`›ˆ€Ì² d°k ŸEée‡Gy„ßþö·ôööNJ•¨a²|ùrþæoþ†}ìcN«Ý üÄ4MŸ.zr¶û=Ù(°XˆÕ00õßlÞ¼·ÛÛí&OZ÷ÀP(D[[¦i: ´˜Æó¼Ðm" 2».k±¦Ç=e’üÇä§?ý)]]]“2H @QQ‹-âøŸúÔ§ìU¡ÿ/ðMÓ4{uÑ“sÝïÉÐ \¤¦æËÏÏgýúõ=z”ááaB¡Ð¤„€xË׿þuNœ81i7°Ze×ÖÖòw÷w¬ZµÊ^<|xݩџ.zrû=šœ9°«›]Juu5 .äõ×_ÇëõÇ'åw„Ãa†‡‡9tè«W¯v:F€W9‹‘u.Ìn9Ú’¼Ô`kõÒK/ñï|‡'N …&íû²téRî»ï>§jO’Áå峿×4ÍÔŸˆÃñáž²—íܹ“øÃ,Y²Ä>moVŒŒÐÒÒÂW¾òíÅ׋µ'åí¸´ $©‚´Ò8@0$///Õê8›O †a¤ªþï¸ãn½õÖÓÝüÎY¾ó9ËÐoƱF üŸéewÜqýýýüâ¿ ··7ë5cÁÕåráñxØ·oŸ=¯Æj(¢ gå”§ç•+W²mÛ6***p¹\då‹Äb1LÓ¤¤¤„Õ«WsË-·ðÎw¾ÓiÕþ?28=ªHš“Àw€-XïÖX°`_úҗزe ¿ùÍop»ÝY«ˆÅb$ Ã`ãÆTUUÙW í>yÛ‡¬Ù^ ªjàÔSýà‡ÀÅée­­­D"rssq¹\¬\¹rB¿‹ÛíNõ2(**bÉ’%§[uðWÀ!Ó4:•e‚ÎB¬0êôÀäñxL=‘gãüMÕ:8Mô"Öì—mowSmkèßÏàðÞs òw¿BÚu2ÁÊÏN“ï{O²æB熜‘ʘ¬wé»§ø÷<ŠõNöwºÀI– ÿ܉Õãd*û÷d €Î Q €œ“"¬QÐ>Ü=žۛɋۯFÀ¯Ý%YV\|øË)øý~禙½r±Æ¿¸kTÀùXƒë -@?o3ØÎù‹XU­«É¿kT³ƒ@ÖŒgºñËdr%χÀ%Éó£«' çÇØ¿.¬á~û±Áz8€5 °ˆ€\°âäE§(y± aU‡NÔ0h…ÉÏ+N~^ ùyjÑ,SQ07ùçÊâù1'ÔÓÏ=ñ‹€ˆˆˆ¼=5QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ‘àÿBèÀTrÛØãIEND®B`‚game.libretro-20.2.4-Nexus/game.libretro/resources/000077500000000000000000000000001445145641500222065ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/game.libretro/resources/language/000077500000000000000000000000001445145641500237715ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.af_za/000077500000000000000000000000001445145641500304615ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.af_za/strings.po000066400000000000000000000016631445145641500325200ustar00rootroot00000000000000# game.libretro language file # Addon Name: Libretro Compatibility # Addon id: game.libretro # Addon Provider: Garrett Brown msgid "" msgstr "" "Project-Id-Version: Libretro Compatibility\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: 2014-05-30 17:00+8\n" "PO-Revision-Date: 2014-05-30 17:00+8\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" "Language: af_za\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" msgctxt "Addon Summary" msgid "Libretro compatibility layer for Kodi's Game API" msgstr "" msgctxt "Addon Description" msgid "This add-on provides a wrapper for libretro cores, allowing them to be loaded as game add-ons." msgstr "" msgctxt "#30000" msgid "Crop overscan" msgstr "" msgctxt "#30001" msgid "Crop away invisible edges of the screen, if the game is aware of any." msgstr "" game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.am_et/000077500000000000000000000000001445145641500304665ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.am_et/strings.po000066400000000000000000000016621445145641500325240ustar00rootroot00000000000000# game.libretro language file # Addon Name: Libretro Compatibility # Addon id: game.libretro # Addon Provider: Garrett Brown msgid "" msgstr "" "Project-Id-Version: Libretro Compatibility\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: 2014-05-30 17:00+8\n" "PO-Revision-Date: 2014-05-30 17:00+8\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" "Language: am_et\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n > 1;\n" msgctxt "Addon Summary" msgid "Libretro compatibility layer for Kodi's Game API" msgstr "" msgctxt "Addon Description" msgid "This add-on provides a wrapper for libretro cores, allowing them to be loaded as game add-ons." msgstr "" msgctxt "#30000" msgid "Crop overscan" msgstr "" msgctxt "#30001" msgid "Crop away invisible edges of the screen, if the game is aware of any." msgstr "" game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.ar_sa/000077500000000000000000000000001445145641500304665ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.ar_sa/strings.po000066400000000000000000000017731445145641500325270ustar00rootroot00000000000000# game.libretro language file # Addon Name: Libretro Compatibility # Addon id: game.libretro # Addon Provider: Garrett Brown msgid "" msgstr "" "Project-Id-Version: Libretro Compatibility\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: 2014-05-30 17:00+8\n" "PO-Revision-Date: 2014-05-30 17:00+8\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" "Language: ar_sa\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 ? 4 : 5;\n" msgctxt "Addon Summary" msgid "Libretro compatibility layer for Kodi's Game API" msgstr "" msgctxt "Addon Description" msgid "This add-on provides a wrapper for libretro cores, allowing them to be loaded as game add-ons." msgstr "" msgctxt "#30000" msgid "Crop overscan" msgstr "" msgctxt "#30001" msgid "Crop away invisible edges of the screen, if the game is aware of any." msgstr "" game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.ast_es/000077500000000000000000000000001445145641500306575ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.ast_es/strings.po000066400000000000000000000016641445145641500327170ustar00rootroot00000000000000# game.libretro language file # Addon Name: Libretro Compatibility # Addon id: game.libretro # Addon Provider: Garrett Brown msgid "" msgstr "" "Project-Id-Version: Libretro Compatibility\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: 2014-05-30 17:00+8\n" "PO-Revision-Date: 2014-05-30 17:00+8\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" "Language: ast_es\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" msgctxt "Addon Summary" msgid "Libretro compatibility layer for Kodi's Game API" msgstr "" msgctxt "Addon Description" msgid "This add-on provides a wrapper for libretro cores, allowing them to be loaded as game add-ons." msgstr "" msgctxt "#30000" msgid "Crop overscan" msgstr "" msgctxt "#30001" msgid "Crop away invisible edges of the screen, if the game is aware of any." msgstr "" game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.az_az/000077500000000000000000000000001445145641500305055ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.az_az/strings.po000066400000000000000000000016631445145641500325440ustar00rootroot00000000000000# game.libretro language file # Addon Name: Libretro Compatibility # Addon id: game.libretro # Addon Provider: Garrett Brown msgid "" msgstr "" "Project-Id-Version: Libretro Compatibility\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: 2014-05-30 17:00+8\n" "PO-Revision-Date: 2014-05-30 17:00+8\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" "Language: az_az\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" msgctxt "Addon Summary" msgid "Libretro compatibility layer for Kodi's Game API" msgstr "" msgctxt "Addon Description" msgid "This add-on provides a wrapper for libretro cores, allowing them to be loaded as game add-ons." msgstr "" msgctxt "#30000" msgid "Crop overscan" msgstr "" msgctxt "#30001" msgid "Crop away invisible edges of the screen, if the game is aware of any." msgstr "" game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.be_by/000077500000000000000000000000001445145641500304615ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.be_by/strings.po000066400000000000000000000017751445145641500325240ustar00rootroot00000000000000# game.libretro language file # Addon Name: Libretro Compatibility # Addon id: game.libretro # Addon Provider: Garrett Brown msgid "" msgstr "" "Project-Id-Version: Libretro Compatibility\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: 2014-05-30 17:00+8\n" "PO-Revision-Date: 2014-05-30 17:00+8\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" "Language: be_by\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" msgctxt "Addon Summary" msgid "Libretro compatibility layer for Kodi's Game API" msgstr "" msgctxt "Addon Description" msgid "This add-on provides a wrapper for libretro cores, allowing them to be loaded as game add-ons." msgstr "" msgctxt "#30000" msgid "Crop overscan" msgstr "" msgctxt "#30001" msgid "Crop away invisible edges of the screen, if the game is aware of any." msgstr "" game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.bg_bg/000077500000000000000000000000001445145641500304415ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.bg_bg/strings.po000066400000000000000000000016631445145641500325000ustar00rootroot00000000000000# game.libretro language file # Addon Name: Libretro Compatibility # Addon id: game.libretro # Addon Provider: Garrett Brown msgid "" msgstr "" "Project-Id-Version: Libretro Compatibility\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: 2014-05-30 17:00+8\n" "PO-Revision-Date: 2014-05-30 17:00+8\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" "Language: bg_bg\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" msgctxt "Addon Summary" msgid "Libretro compatibility layer for Kodi's Game API" msgstr "" msgctxt "Addon Description" msgid "This add-on provides a wrapper for libretro cores, allowing them to be loaded as game add-ons." msgstr "" msgctxt "#30000" msgid "Crop overscan" msgstr "" msgctxt "#30001" msgid "Crop away invisible edges of the screen, if the game is aware of any." msgstr "" game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.bs_ba/000077500000000000000000000000001445145641500304475ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.bs_ba/strings.po000066400000000000000000000017751445145641500325120ustar00rootroot00000000000000# game.libretro language file # Addon Name: Libretro Compatibility # Addon id: game.libretro # Addon Provider: Garrett Brown msgid "" msgstr "" "Project-Id-Version: Libretro Compatibility\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: 2014-05-30 17:00+8\n" "PO-Revision-Date: 2014-05-30 17:00+8\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" "Language: bs_ba\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" msgctxt "Addon Summary" msgid "Libretro compatibility layer for Kodi's Game API" msgstr "" msgctxt "Addon Description" msgid "This add-on provides a wrapper for libretro cores, allowing them to be loaded as game add-ons." msgstr "" msgctxt "#30000" msgid "Crop overscan" msgstr "" msgctxt "#30001" msgid "Crop away invisible edges of the screen, if the game is aware of any." msgstr "" game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.ca_es/000077500000000000000000000000001445145641500304535ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.ca_es/strings.po000066400000000000000000000016631445145641500325120ustar00rootroot00000000000000# game.libretro language file # Addon Name: Libretro Compatibility # Addon id: game.libretro # Addon Provider: Garrett Brown msgid "" msgstr "" "Project-Id-Version: Libretro Compatibility\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: 2014-05-30 17:00+8\n" "PO-Revision-Date: 2014-05-30 17:00+8\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" "Language: ca_es\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" msgctxt "Addon Summary" msgid "Libretro compatibility layer for Kodi's Game API" msgstr "" msgctxt "Addon Description" msgid "This add-on provides a wrapper for libretro cores, allowing them to be loaded as game add-ons." msgstr "" msgctxt "#30000" msgid "Crop overscan" msgstr "" msgctxt "#30001" msgid "Crop away invisible edges of the screen, if the game is aware of any." msgstr "" game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.cs_cz/000077500000000000000000000000001445145641500305025ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.cs_cz/strings.po000066400000000000000000000017201445145641500325330ustar00rootroot00000000000000# game.libretro language file # Addon Name: Libretro Compatibility # Addon id: game.libretro # Addon Provider: Garrett Brown msgid "" msgstr "" "Project-Id-Version: Libretro Compatibility\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: 2014-05-30 17:00+8\n" "PO-Revision-Date: 2014-05-30 17:00+8\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" "Language: cs_cz\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" msgctxt "Addon Summary" msgid "Libretro compatibility layer for Kodi's Game API" msgstr "" msgctxt "Addon Description" msgid "This add-on provides a wrapper for libretro cores, allowing them to be loaded as game add-ons." msgstr "" msgctxt "#30000" msgid "Crop overscan" msgstr "" msgctxt "#30001" msgid "Crop away invisible edges of the screen, if the game is aware of any." msgstr "" game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.cy_gb/000077500000000000000000000000001445145641500304645ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.cy_gb/strings.po000066400000000000000000000017561445145641500325260ustar00rootroot00000000000000# game.libretro language file # Addon Name: Libretro Compatibility # Addon id: game.libretro # Addon Provider: Garrett Brown msgid "" msgstr "" "Project-Id-Version: Libretro Compatibility\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: 2014-05-30 17:00+8\n" "PO-Revision-Date: 2014-05-30 17:00+8\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" "Language: cy_gb\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=6; plural=(n==0) ? 0 : (n==1) ? 1 : (n==2) ? 2 : (n==3) ? 3 :(n==6) ? 4 : 5;\n" msgctxt "Addon Summary" msgid "Libretro compatibility layer for Kodi's Game API" msgstr "" msgctxt "Addon Description" msgid "This add-on provides a wrapper for libretro cores, allowing them to be loaded as game add-ons." msgstr "" msgctxt "#30000" msgid "Crop overscan" msgstr "" msgctxt "#30001" msgid "Crop away invisible edges of the screen, if the game is aware of any." msgstr "" game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.da_dk/000077500000000000000000000000001445145641500304435ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.da_dk/strings.po000066400000000000000000000024201445145641500324720ustar00rootroot00000000000000# game.libretro language file # Addon Name: Libretro Compatibility # Addon id: game.libretro # Addon Provider: Garrett Brown msgid "" msgstr "" "Project-Id-Version: Libretro Compatibility\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: 2014-05-30 17:00+8\n" "PO-Revision-Date: 2021-10-11 09:46+0000\n" "Last-Translator: Christian Gade \n" "Language-Team: Danish \n" "Language: da_dk\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" "X-Generator: Weblate 4.8\n" msgctxt "Addon Summary" msgid "Libretro compatibility layer for Kodi's Game API" msgstr "Libretro kompatibilitetslag til Kodi's Game API" msgctxt "Addon Description" msgid "This add-on provides a wrapper for libretro cores, allowing them to be loaded as game add-ons." msgstr "Dette add-on giver en wrapper til libretro-kerner, sÃ¥ de kan indlæses som spil-add-ons." msgctxt "#30000" msgid "Crop overscan" msgstr "Beskær overskandering" msgctxt "#30001" msgid "Crop away invisible edges of the screen, if the game is aware of any." msgstr "Beskær usynlige kanter af skærmen, hvis spillet er opmærksom pÃ¥ nogen." game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.de_de/000077500000000000000000000000001445145641500304415ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.de_de/strings.po000066400000000000000000000025251445145641500324760ustar00rootroot00000000000000# game.libretro language file # Addon Name: Libretro Compatibility # Addon id: game.libretro # Addon Provider: Garrett Brown msgid "" msgstr "" "Project-Id-Version: Libretro Compatibility\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: 2014-05-30 17:00+8\n" "PO-Revision-Date: 2023-02-17 22:59+0000\n" "Last-Translator: Demian \n" "Language-Team: German \n" "Language: de_de\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" "X-Generator: Weblate 4.15.2\n" msgctxt "Addon Summary" msgid "Libretro compatibility layer for Kodi's Game API" msgstr "Libretro-Kompatibilitätsschicht für Kodis Spiele-API" msgctxt "Addon Description" msgid "This add-on provides a wrapper for libretro cores, allowing them to be loaded as game add-ons." msgstr "Dieses Addon bietet einen Umwandler für Libretro-Cores, mit dem sie als Spielsystem Add-Ons für Kodi geladen und genutzt werden können." msgctxt "#30000" msgid "Crop overscan" msgstr "Overscan beschneiden" msgctxt "#30001" msgid "Crop away invisible edges of the screen, if the game is aware of any." msgstr "Unsichtbare Ränder des Bildschirms werden weggeschnitten, sofern das Spiel sie wahrnimmt." game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.el_gr/000077500000000000000000000000001445145641500304715ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.el_gr/strings.po000066400000000000000000000016631445145641500325300ustar00rootroot00000000000000# game.libretro language file # Addon Name: Libretro Compatibility # Addon id: game.libretro # Addon Provider: Garrett Brown msgid "" msgstr "" "Project-Id-Version: Libretro Compatibility\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: 2014-05-30 17:00+8\n" "PO-Revision-Date: 2014-05-30 17:00+8\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" "Language: el_gr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" msgctxt "Addon Summary" msgid "Libretro compatibility layer for Kodi's Game API" msgstr "" msgctxt "Addon Description" msgid "This add-on provides a wrapper for libretro cores, allowing them to be loaded as game add-ons." msgstr "" msgctxt "#30000" msgid "Crop overscan" msgstr "" msgctxt "#30001" msgid "Crop away invisible edges of the screen, if the game is aware of any." msgstr "" game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.en_au/000077500000000000000000000000001445145641500304705ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.en_au/strings.po000066400000000000000000000016631445145641500325270ustar00rootroot00000000000000# game.libretro language file # Addon Name: Libretro Compatibility # Addon id: game.libretro # Addon Provider: Garrett Brown msgid "" msgstr "" "Project-Id-Version: Libretro Compatibility\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: 2014-05-30 17:00+8\n" "PO-Revision-Date: 2014-05-30 17:00+8\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" "Language: en_au\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" msgctxt "Addon Summary" msgid "Libretro compatibility layer for Kodi's Game API" msgstr "" msgctxt "Addon Description" msgid "This add-on provides a wrapper for libretro cores, allowing them to be loaded as game add-ons." msgstr "" msgctxt "#30000" msgid "Crop overscan" msgstr "" msgctxt "#30001" msgid "Crop away invisible edges of the screen, if the game is aware of any." msgstr "" game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.en_gb/000077500000000000000000000000001445145641500304535ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.en_gb/strings.po000066400000000000000000000017611445145641500325110ustar00rootroot00000000000000# game.libretro language file # Addon Name: Libretro Compatibility # Addon id: game.libretro # Addon Provider: Team Kodi msgid "" msgstr "" "Project-Id-Version: Libretro Compatibility\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: 2014-05-30 17:00+8\n" "PO-Revision-Date: 2014-05-30 17:00+8\n" "Last-Translator: Kodi Translation Team\n" "Language-Team: English (United Kingdom) (https://kodi.weblate.cloud/languages/en_gb/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: en_GB\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" msgctxt "Addon Summary" msgid "Libretro compatibility layer for Kodi's Game API" msgstr "" msgctxt "Addon Description" msgid "This add-on provides a wrapper for libretro cores, allowing them to be loaded as game add-ons." msgstr "" msgctxt "#30000" msgid "Crop overscan" msgstr "" msgctxt "#30001" msgid "Crop away invisible edges of the screen, if the game is aware of any." msgstr "" game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.en_nz/000077500000000000000000000000001445145641500305125ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.en_nz/strings.po000066400000000000000000000016631445145641500325510ustar00rootroot00000000000000# game.libretro language file # Addon Name: Libretro Compatibility # Addon id: game.libretro # Addon Provider: Garrett Brown msgid "" msgstr "" "Project-Id-Version: Libretro Compatibility\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: 2014-05-30 17:00+8\n" "PO-Revision-Date: 2014-05-30 17:00+8\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" "Language: en_nz\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" msgctxt "Addon Summary" msgid "Libretro compatibility layer for Kodi's Game API" msgstr "" msgctxt "Addon Description" msgid "This add-on provides a wrapper for libretro cores, allowing them to be loaded as game add-ons." msgstr "" msgctxt "#30000" msgid "Crop overscan" msgstr "" msgctxt "#30001" msgid "Crop away invisible edges of the screen, if the game is aware of any." msgstr "" game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.en_us/000077500000000000000000000000001445145641500305125ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.en_us/strings.po000066400000000000000000000016631445145641500325510ustar00rootroot00000000000000# game.libretro language file # Addon Name: Libretro Compatibility # Addon id: game.libretro # Addon Provider: Garrett Brown msgid "" msgstr "" "Project-Id-Version: Libretro Compatibility\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: 2014-05-30 17:00+8\n" "PO-Revision-Date: 2014-05-30 17:00+8\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" "Language: en_us\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" msgctxt "Addon Summary" msgid "Libretro compatibility layer for Kodi's Game API" msgstr "" msgctxt "Addon Description" msgid "This add-on provides a wrapper for libretro cores, allowing them to be loaded as game add-ons." msgstr "" msgctxt "#30000" msgid "Crop overscan" msgstr "" msgctxt "#30001" msgid "Crop away invisible edges of the screen, if the game is aware of any." msgstr "" game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.eo/000077500000000000000000000000001445145641500300045ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.eo/strings.po000066400000000000000000000016601445145641500320400ustar00rootroot00000000000000# game.libretro language file # Addon Name: Libretro Compatibility # Addon id: game.libretro # Addon Provider: Garrett Brown msgid "" msgstr "" "Project-Id-Version: Libretro Compatibility\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: 2014-05-30 17:00+8\n" "PO-Revision-Date: 2014-05-30 17:00+8\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" "Language: eo\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" msgctxt "Addon Summary" msgid "Libretro compatibility layer for Kodi's Game API" msgstr "" msgctxt "Addon Description" msgid "This add-on provides a wrapper for libretro cores, allowing them to be loaded as game add-ons." msgstr "" msgctxt "#30000" msgid "Crop overscan" msgstr "" msgctxt "#30001" msgid "Crop away invisible edges of the screen, if the game is aware of any." msgstr "" game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.es_ar/000077500000000000000000000000001445145641500304725ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.es_ar/strings.po000066400000000000000000000016631445145641500325310ustar00rootroot00000000000000# game.libretro language file # Addon Name: Libretro Compatibility # Addon id: game.libretro # Addon Provider: Garrett Brown msgid "" msgstr "" "Project-Id-Version: Libretro Compatibility\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: 2014-05-30 17:00+8\n" "PO-Revision-Date: 2014-05-30 17:00+8\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" "Language: es_ar\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" msgctxt "Addon Summary" msgid "Libretro compatibility layer for Kodi's Game API" msgstr "" msgctxt "Addon Description" msgid "This add-on provides a wrapper for libretro cores, allowing them to be loaded as game add-ons." msgstr "" msgctxt "#30000" msgid "Crop overscan" msgstr "" msgctxt "#30001" msgid "Crop away invisible edges of the screen, if the game is aware of any." msgstr "" game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.es_es/000077500000000000000000000000001445145641500304775ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.es_es/strings.po000066400000000000000000000025251445145641500325340ustar00rootroot00000000000000# game.libretro language file # Addon Name: Libretro Compatibility # Addon id: game.libretro # Addon Provider: Garrett Brown msgid "" msgstr "" "Project-Id-Version: Libretro Compatibility\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: 2014-05-30 17:00+8\n" "PO-Revision-Date: 2023-06-30 15:19+0000\n" "Last-Translator: José Antonio Alvarado \n" "Language-Team: Spanish (Spain) \n" "Language: es_es\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" "X-Generator: Weblate 4.18\n" msgctxt "Addon Summary" msgid "Libretro compatibility layer for Kodi's Game API" msgstr "Capa de compatibilidad de Libretro para la API de juegos de Kodi" msgctxt "Addon Description" msgid "This add-on provides a wrapper for libretro cores, allowing them to be loaded as game add-ons." msgstr "Este add-on proporciona una capa para los núcleos libretro, lo que les permite ser cargados como add-ons del juego." msgctxt "#30000" msgid "Crop overscan" msgstr "Recortar overscan" msgctxt "#30001" msgid "Crop away invisible edges of the screen, if the game is aware of any." msgstr "Recorta los bordes invisibles de la pantalla, si el juego detecta alguno." game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.es_mx/000077500000000000000000000000001445145641500305145ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.es_mx/strings.po000066400000000000000000000022411445145641500325440ustar00rootroot00000000000000# game.libretro language file # Addon Name: Libretro Compatibility # Addon id: game.libretro # Addon Provider: Garrett Brown msgid "" msgstr "" "Project-Id-Version: Libretro Compatibility\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: 2014-05-30 17:00+8\n" "PO-Revision-Date: 2021-04-16 04:29+0000\n" "Last-Translator: Edson Armando \n" "Language-Team: Spanish (Mexico) \n" "Language: es_mx\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" "X-Generator: Weblate 4.5.3\n" msgctxt "Addon Summary" msgid "Libretro compatibility layer for Kodi's Game API" msgstr "" msgctxt "Addon Description" msgid "This add-on provides a wrapper for libretro cores, allowing them to be loaded as game add-ons." msgstr "" msgctxt "#30000" msgid "Crop overscan" msgstr "Quitar entrelazado" msgctxt "#30001" msgid "Crop away invisible edges of the screen, if the game is aware of any." msgstr "Quita los bordes invisibles de la pantalla, si es que el juego sabe de alguno." game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.et_ee/000077500000000000000000000000001445145641500304625ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.et_ee/strings.po000066400000000000000000000016631445145641500325210ustar00rootroot00000000000000# game.libretro language file # Addon Name: Libretro Compatibility # Addon id: game.libretro # Addon Provider: Garrett Brown msgid "" msgstr "" "Project-Id-Version: Libretro Compatibility\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: 2014-05-30 17:00+8\n" "PO-Revision-Date: 2014-05-30 17:00+8\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" "Language: et_ee\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" msgctxt "Addon Summary" msgid "Libretro compatibility layer for Kodi's Game API" msgstr "" msgctxt "Addon Description" msgid "This add-on provides a wrapper for libretro cores, allowing them to be loaded as game add-ons." msgstr "" msgctxt "#30000" msgid "Crop overscan" msgstr "" msgctxt "#30001" msgid "Crop away invisible edges of the screen, if the game is aware of any." msgstr "" game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.eu_es/000077500000000000000000000000001445145641500305015ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.eu_es/strings.po000066400000000000000000000016631445145641500325400ustar00rootroot00000000000000# game.libretro language file # Addon Name: Libretro Compatibility # Addon id: game.libretro # Addon Provider: Garrett Brown msgid "" msgstr "" "Project-Id-Version: Libretro Compatibility\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: 2014-05-30 17:00+8\n" "PO-Revision-Date: 2014-05-30 17:00+8\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" "Language: eu_es\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" msgctxt "Addon Summary" msgid "Libretro compatibility layer for Kodi's Game API" msgstr "" msgctxt "Addon Description" msgid "This add-on provides a wrapper for libretro cores, allowing them to be loaded as game add-ons." msgstr "" msgctxt "#30000" msgid "Crop overscan" msgstr "" msgctxt "#30001" msgid "Crop away invisible edges of the screen, if the game is aware of any." msgstr "" game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.fa_af/000077500000000000000000000000001445145641500304355ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.fa_af/strings.po000066400000000000000000000016621445145641500324730ustar00rootroot00000000000000# game.libretro language file # Addon Name: Libretro Compatibility # Addon id: game.libretro # Addon Provider: Garrett Brown msgid "" msgstr "" "Project-Id-Version: Libretro Compatibility\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: 2014-05-30 17:00+8\n" "PO-Revision-Date: 2014-05-30 17:00+8\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" "Language: fa_af\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n > 1;\n" msgctxt "Addon Summary" msgid "Libretro compatibility layer for Kodi's Game API" msgstr "" msgctxt "Addon Description" msgid "This add-on provides a wrapper for libretro cores, allowing them to be loaded as game add-ons." msgstr "" msgctxt "#30000" msgid "Crop overscan" msgstr "" msgctxt "#30001" msgid "Crop away invisible edges of the screen, if the game is aware of any." msgstr "" game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.fa_ir/000077500000000000000000000000001445145641500304615ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.fa_ir/strings.po000066400000000000000000000016621445145641500325170ustar00rootroot00000000000000# game.libretro language file # Addon Name: Libretro Compatibility # Addon id: game.libretro # Addon Provider: Garrett Brown msgid "" msgstr "" "Project-Id-Version: Libretro Compatibility\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: 2014-05-30 17:00+8\n" "PO-Revision-Date: 2014-05-30 17:00+8\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" "Language: fa_ir\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n > 1;\n" msgctxt "Addon Summary" msgid "Libretro compatibility layer for Kodi's Game API" msgstr "" msgctxt "Addon Description" msgid "This add-on provides a wrapper for libretro cores, allowing them to be loaded as game add-ons." msgstr "" msgctxt "#30000" msgid "Crop overscan" msgstr "" msgctxt "#30001" msgid "Crop away invisible edges of the screen, if the game is aware of any." msgstr "" game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.fi_fi/000077500000000000000000000000001445145641500304555ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.fi_fi/strings.po000066400000000000000000000021121445145641500325020ustar00rootroot00000000000000# game.libretro language file # Addon Name: Libretro Compatibility # Addon id: game.libretro # Addon Provider: Garrett Brown msgid "" msgstr "" "Project-Id-Version: Libretro Compatibility\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: 2014-05-30 17:00+8\n" "PO-Revision-Date: 2022-07-10 10:14+0000\n" "Last-Translator: Oskari Lavinto \n" "Language-Team: Finnish \n" "Language: fi_fi\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" "X-Generator: Weblate 4.13\n" msgctxt "Addon Summary" msgid "Libretro compatibility layer for Kodi's Game API" msgstr "" msgctxt "Addon Description" msgid "This add-on provides a wrapper for libretro cores, allowing them to be loaded as game add-ons." msgstr "" msgctxt "#30000" msgid "Crop overscan" msgstr "Yliskannauksen rajaus" msgctxt "#30001" msgid "Crop away invisible edges of the screen, if the game is aware of any." msgstr "" game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.fo_fo/000077500000000000000000000000001445145641500304715ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.fo_fo/strings.po000066400000000000000000000016631445145641500325300ustar00rootroot00000000000000# game.libretro language file # Addon Name: Libretro Compatibility # Addon id: game.libretro # Addon Provider: Garrett Brown msgid "" msgstr "" "Project-Id-Version: Libretro Compatibility\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: 2014-05-30 17:00+8\n" "PO-Revision-Date: 2014-05-30 17:00+8\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" "Language: fo_fo\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" msgctxt "Addon Summary" msgid "Libretro compatibility layer for Kodi's Game API" msgstr "" msgctxt "Addon Description" msgid "This add-on provides a wrapper for libretro cores, allowing them to be loaded as game add-ons." msgstr "" msgctxt "#30000" msgid "Crop overscan" msgstr "" msgctxt "#30001" msgid "Crop away invisible edges of the screen, if the game is aware of any." msgstr "" game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.fr_ca/000077500000000000000000000000001445145641500304535ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.fr_ca/strings.po000066400000000000000000000016621445145641500325110ustar00rootroot00000000000000# game.libretro language file # Addon Name: Libretro Compatibility # Addon id: game.libretro # Addon Provider: Garrett Brown msgid "" msgstr "" "Project-Id-Version: Libretro Compatibility\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: 2014-05-30 17:00+8\n" "PO-Revision-Date: 2014-05-30 17:00+8\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" "Language: fr_ca\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n > 1;\n" msgctxt "Addon Summary" msgid "Libretro compatibility layer for Kodi's Game API" msgstr "" msgctxt "Addon Description" msgid "This add-on provides a wrapper for libretro cores, allowing them to be loaded as game add-ons." msgstr "" msgctxt "#30000" msgid "Crop overscan" msgstr "" msgctxt "#30001" msgid "Crop away invisible edges of the screen, if the game is aware of any." msgstr "" game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.fr_fr/000077500000000000000000000000001445145641500304775ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.fr_fr/strings.po000066400000000000000000000024711445145641500325340ustar00rootroot00000000000000# game.libretro language file # Addon Name: Libretro Compatibility # Addon id: game.libretro # Addon Provider: Garrett Brown msgid "" msgstr "" "Project-Id-Version: Libretro Compatibility\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: 2014-05-30 17:00+8\n" "PO-Revision-Date: 2023-02-17 22:59+0000\n" "Last-Translator: skypichat \n" "Language-Team: French (France) \n" "Language: fr_fr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n > 1;\n" "X-Generator: Weblate 4.15.2\n" msgctxt "Addon Summary" msgid "Libretro compatibility layer for Kodi's Game API" msgstr "Couche de compatibilité Libretro pour l'API de jeu de Kodi" msgctxt "Addon Description" msgid "This add-on provides a wrapper for libretro cores, allowing them to be loaded as game add-ons." msgstr "Cet add-on fournit un wrapper pour les cÅ“urs libretro, leur permettant d'être chargés en tant qu'add-ons de jeu." msgctxt "#30000" msgid "Crop overscan" msgstr "Recadrage écran" msgctxt "#30001" msgid "Crop away invisible edges of the screen, if the game is aware of any." msgstr "Couper les bords invisibles de l'écran, si le jeu en a connaissance." game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.gl_es/000077500000000000000000000000001445145641500304725ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.gl_es/strings.po000066400000000000000000000016631445145641500325310ustar00rootroot00000000000000# game.libretro language file # Addon Name: Libretro Compatibility # Addon id: game.libretro # Addon Provider: Garrett Brown msgid "" msgstr "" "Project-Id-Version: Libretro Compatibility\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: 2014-05-30 17:00+8\n" "PO-Revision-Date: 2014-05-30 17:00+8\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" "Language: gl_es\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" msgctxt "Addon Summary" msgid "Libretro compatibility layer for Kodi's Game API" msgstr "" msgctxt "Addon Description" msgid "This add-on provides a wrapper for libretro cores, allowing them to be loaded as game add-ons." msgstr "" msgctxt "#30000" msgid "Crop overscan" msgstr "" msgctxt "#30001" msgid "Crop away invisible edges of the screen, if the game is aware of any." msgstr "" game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.he_il/000077500000000000000000000000001445145641500304615ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.he_il/strings.po000066400000000000000000000017561445145641500325230ustar00rootroot00000000000000# game.libretro language file # Addon Name: Libretro Compatibility # Addon id: game.libretro # Addon Provider: Garrett Brown msgid "" msgstr "" "Project-Id-Version: Libretro Compatibility\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: 2014-05-30 17:00+8\n" "PO-Revision-Date: 2014-05-30 17:00+8\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" "Language: he_il\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=(n == 1) ? 0 : ((n == 2) ? 1 : ((n > 10 && n % 10 == 0) ? 2 : 3));\n" msgctxt "Addon Summary" msgid "Libretro compatibility layer for Kodi's Game API" msgstr "" msgctxt "Addon Description" msgid "This add-on provides a wrapper for libretro cores, allowing them to be loaded as game add-ons." msgstr "" msgctxt "#30000" msgid "Crop overscan" msgstr "" msgctxt "#30001" msgid "Crop away invisible edges of the screen, if the game is aware of any." msgstr "" game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.hi_in/000077500000000000000000000000001445145641500304675ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.hi_in/strings.po000066400000000000000000000016621445145641500325250ustar00rootroot00000000000000# game.libretro language file # Addon Name: Libretro Compatibility # Addon id: game.libretro # Addon Provider: Garrett Brown msgid "" msgstr "" "Project-Id-Version: Libretro Compatibility\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: 2014-05-30 17:00+8\n" "PO-Revision-Date: 2014-05-30 17:00+8\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" "Language: hi_in\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n > 1;\n" msgctxt "Addon Summary" msgid "Libretro compatibility layer for Kodi's Game API" msgstr "" msgctxt "Addon Description" msgid "This add-on provides a wrapper for libretro cores, allowing them to be loaded as game add-ons." msgstr "" msgctxt "#30000" msgid "Crop overscan" msgstr "" msgctxt "#30001" msgid "Crop away invisible edges of the screen, if the game is aware of any." msgstr "" game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.hr_hr/000077500000000000000000000000001445145641500305035ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.hr_hr/strings.po000066400000000000000000000017751445145641500325460ustar00rootroot00000000000000# game.libretro language file # Addon Name: Libretro Compatibility # Addon id: game.libretro # Addon Provider: Garrett Brown msgid "" msgstr "" "Project-Id-Version: Libretro Compatibility\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: 2014-05-30 17:00+8\n" "PO-Revision-Date: 2014-05-30 17:00+8\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" "Language: hr_hr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" msgctxt "Addon Summary" msgid "Libretro compatibility layer for Kodi's Game API" msgstr "" msgctxt "Addon Description" msgid "This add-on provides a wrapper for libretro cores, allowing them to be loaded as game add-ons." msgstr "" msgctxt "#30000" msgid "Crop overscan" msgstr "" msgctxt "#30001" msgid "Crop away invisible edges of the screen, if the game is aware of any." msgstr "" game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.hu_hu/000077500000000000000000000000001445145641500305115ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.hu_hu/strings.po000066400000000000000000000021411445145641500325400ustar00rootroot00000000000000# game.libretro language file # Addon Name: Libretro Compatibility # Addon id: game.libretro # Addon Provider: Garrett Brown msgid "" msgstr "" "Project-Id-Version: Libretro Compatibility\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: 2014-05-30 17:00+8\n" "PO-Revision-Date: 2021-12-23 15:13+0000\n" "Last-Translator: Christian Gade \n" "Language-Team: Hungarian \n" "Language: hu_hu\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" "X-Generator: Weblate 4.10.1\n" msgctxt "Addon Summary" msgid "Libretro compatibility layer for Kodi's Game API" msgstr "Libreto Kompatibilis réteg Kodi Játék API-jának" msgctxt "Addon Description" msgid "This add-on provides a wrapper for libretro cores, allowing them to be loaded as game add-ons." msgstr "" msgctxt "#30000" msgid "Crop overscan" msgstr "" msgctxt "#30001" msgid "Crop away invisible edges of the screen, if the game is aware of any." msgstr "" game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.hy_am/000077500000000000000000000000001445145641500304765ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.hy_am/strings.po000066400000000000000000000016621445145641500325340ustar00rootroot00000000000000# game.libretro language file # Addon Name: Libretro Compatibility # Addon id: game.libretro # Addon Provider: Garrett Brown msgid "" msgstr "" "Project-Id-Version: Libretro Compatibility\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: 2014-05-30 17:00+8\n" "PO-Revision-Date: 2014-05-30 17:00+8\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" "Language: hy_am\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n > 1;\n" msgctxt "Addon Summary" msgid "Libretro compatibility layer for Kodi's Game API" msgstr "" msgctxt "Addon Description" msgid "This add-on provides a wrapper for libretro cores, allowing them to be loaded as game add-ons." msgstr "" msgctxt "#30000" msgid "Crop overscan" msgstr "" msgctxt "#30001" msgid "Crop away invisible edges of the screen, if the game is aware of any." msgstr "" game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.id_id/000077500000000000000000000000001445145641500304515ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.id_id/strings.po000066400000000000000000000016561445145641500325120ustar00rootroot00000000000000# game.libretro language file # Addon Name: Libretro Compatibility # Addon id: game.libretro # Addon Provider: Garrett Brown msgid "" msgstr "" "Project-Id-Version: Libretro Compatibility\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: 2014-05-30 17:00+8\n" "PO-Revision-Date: 2014-05-30 17:00+8\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" "Language: id_id\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" msgctxt "Addon Summary" msgid "Libretro compatibility layer for Kodi's Game API" msgstr "" msgctxt "Addon Description" msgid "This add-on provides a wrapper for libretro cores, allowing them to be loaded as game add-ons." msgstr "" msgctxt "#30000" msgid "Crop overscan" msgstr "" msgctxt "#30001" msgid "Crop away invisible edges of the screen, if the game is aware of any." msgstr "" game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.is_is/000077500000000000000000000000001445145641500305075ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.is_is/strings.po000066400000000000000000000017111445145641500325400ustar00rootroot00000000000000# game.libretro language file # Addon Name: Libretro Compatibility # Addon id: game.libretro # Addon Provider: Garrett Brown msgid "" msgstr "" "Project-Id-Version: Libretro Compatibility\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: 2014-05-30 17:00+8\n" "PO-Revision-Date: 2014-05-30 17:00+8\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" "Language: is_is\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n % 10 != 1 || n % 100 == 11;\n" msgctxt "Addon Summary" msgid "Libretro compatibility layer for Kodi's Game API" msgstr "" msgctxt "Addon Description" msgid "This add-on provides a wrapper for libretro cores, allowing them to be loaded as game add-ons." msgstr "" msgctxt "#30000" msgid "Crop overscan" msgstr "" msgctxt "#30001" msgid "Crop away invisible edges of the screen, if the game is aware of any." msgstr "" game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.it_it/000077500000000000000000000000001445145641500305115ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.it_it/strings.po000066400000000000000000000024671445145641500325530ustar00rootroot00000000000000# game.libretro language file # Addon Name: Libretro Compatibility # Addon id: game.libretro # Addon Provider: Garrett Brown msgid "" msgstr "" "Project-Id-Version: Libretro Compatibility\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: 2014-05-30 17:00+8\n" "PO-Revision-Date: 2023-03-04 08:16+0000\n" "Last-Translator: Massimo Pissarello \n" "Language-Team: Italian \n" "Language: it_it\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" "X-Generator: Weblate 4.15.2\n" msgctxt "Addon Summary" msgid "Libretro compatibility layer for Kodi's Game API" msgstr "Compatibilità libretro per l'API di gioco di Kodi" msgctxt "Addon Description" msgid "This add-on provides a wrapper for libretro cores, allowing them to be loaded as game add-ons." msgstr "Questo add-on fornisce un modulo sodtware per i core libretro, consentendo loro di essere caricati come add-on di gioco." msgctxt "#30000" msgid "Crop overscan" msgstr "Ritaglia overscan" msgctxt "#30001" msgid "Crop away invisible edges of the screen, if the game is aware of any." msgstr "Taglia i bordi invisibili dello schermo, se il gioco ne è a conoscenza." game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.ja_jp/000077500000000000000000000000001445145641500304645ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.ja_jp/strings.po000066400000000000000000000016561445145641500325250ustar00rootroot00000000000000# game.libretro language file # Addon Name: Libretro Compatibility # Addon id: game.libretro # Addon Provider: Garrett Brown msgid "" msgstr "" "Project-Id-Version: Libretro Compatibility\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: 2014-05-30 17:00+8\n" "PO-Revision-Date: 2014-05-30 17:00+8\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" "Language: ja_jp\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" msgctxt "Addon Summary" msgid "Libretro compatibility layer for Kodi's Game API" msgstr "" msgctxt "Addon Description" msgid "This add-on provides a wrapper for libretro cores, allowing them to be loaded as game add-ons." msgstr "" msgctxt "#30000" msgid "Crop overscan" msgstr "" msgctxt "#30001" msgid "Crop away invisible edges of the screen, if the game is aware of any." msgstr "" game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.kn_in/000077500000000000000000000000001445145641500304775ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.kn_in/strings.po000066400000000000000000000016621445145641500325350ustar00rootroot00000000000000# game.libretro language file # Addon Name: Libretro Compatibility # Addon id: game.libretro # Addon Provider: Garrett Brown msgid "" msgstr "" "Project-Id-Version: Libretro Compatibility\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: 2014-05-30 17:00+8\n" "PO-Revision-Date: 2014-05-30 17:00+8\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" "Language: kn_in\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n > 1;\n" msgctxt "Addon Summary" msgid "Libretro compatibility layer for Kodi's Game API" msgstr "" msgctxt "Addon Description" msgid "This add-on provides a wrapper for libretro cores, allowing them to be loaded as game add-ons." msgstr "" msgctxt "#30000" msgid "Crop overscan" msgstr "" msgctxt "#30001" msgid "Crop away invisible edges of the screen, if the game is aware of any." msgstr "" game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.ko_kr/000077500000000000000000000000001445145641500305065ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.ko_kr/strings.po000066400000000000000000000016561445145641500325470ustar00rootroot00000000000000# game.libretro language file # Addon Name: Libretro Compatibility # Addon id: game.libretro # Addon Provider: Garrett Brown msgid "" msgstr "" "Project-Id-Version: Libretro Compatibility\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: 2014-05-30 17:00+8\n" "PO-Revision-Date: 2014-05-30 17:00+8\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" "Language: ko_kr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" msgctxt "Addon Summary" msgid "Libretro compatibility layer for Kodi's Game API" msgstr "" msgctxt "Addon Description" msgid "This add-on provides a wrapper for libretro cores, allowing them to be loaded as game add-ons." msgstr "" msgctxt "#30000" msgid "Crop overscan" msgstr "" msgctxt "#30001" msgid "Crop away invisible edges of the screen, if the game is aware of any." msgstr "" game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.lt_lt/000077500000000000000000000000001445145641500305175ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.lt_lt/strings.po000066400000000000000000000020531445145641500325500ustar00rootroot00000000000000# game.libretro language file # Addon Name: Libretro Compatibility # Addon id: game.libretro # Addon Provider: Garrett Brown msgid "" msgstr "" "Project-Id-Version: Libretro Compatibility\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: 2014-05-30 17:00+8\n" "PO-Revision-Date: 2014-05-30 17:00+8\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" "Language: lt_lt\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n % 10 == 1 && (n % 100 < 11 || n % 100 > 19)) ? 0 : ((n % 10 >= 2 && n % 10 <= 9 && (n % 100 < 11 || n % 100 > 19)) ? 1 : 2);\n" msgctxt "Addon Summary" msgid "Libretro compatibility layer for Kodi's Game API" msgstr "" msgctxt "Addon Description" msgid "This add-on provides a wrapper for libretro cores, allowing them to be loaded as game add-ons." msgstr "" msgctxt "#30000" msgid "Crop overscan" msgstr "" msgctxt "#30001" msgid "Crop away invisible edges of the screen, if the game is aware of any." msgstr "" game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.lv_lv/000077500000000000000000000000001445145641500305235ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.lv_lv/strings.po000066400000000000000000000020131445145641500325500ustar00rootroot00000000000000# game.libretro language file # Addon Name: Libretro Compatibility # Addon id: game.libretro # Addon Provider: Garrett Brown msgid "" msgstr "" "Project-Id-Version: Libretro Compatibility\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: 2014-05-30 17:00+8\n" "PO-Revision-Date: 2014-05-30 17:00+8\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" "Language: lv_lv\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n % 10 == 0 || n % 100 >= 11 && n % 100 <= 19) ? 0 : ((n % 10 == 1 && n % 100 != 11) ? 1 : 2);\n" msgctxt "Addon Summary" msgid "Libretro compatibility layer for Kodi's Game API" msgstr "" msgctxt "Addon Description" msgid "This add-on provides a wrapper for libretro cores, allowing them to be loaded as game add-ons." msgstr "" msgctxt "#30000" msgid "Crop overscan" msgstr "" msgctxt "#30001" msgid "Crop away invisible edges of the screen, if the game is aware of any." msgstr "" game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.mi/000077500000000000000000000000001445145641500300065ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.mi/strings.po000066400000000000000000000016571445145641500320500ustar00rootroot00000000000000# game.libretro language file # Addon Name: Libretro Compatibility # Addon id: game.libretro # Addon Provider: Garrett Brown msgid "" msgstr "" "Project-Id-Version: Libretro Compatibility\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: 2014-05-30 17:00+8\n" "PO-Revision-Date: 2014-05-30 17:00+8\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" "Language: mi\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n > 1;\n" msgctxt "Addon Summary" msgid "Libretro compatibility layer for Kodi's Game API" msgstr "" msgctxt "Addon Description" msgid "This add-on provides a wrapper for libretro cores, allowing them to be loaded as game add-ons." msgstr "" msgctxt "#30000" msgid "Crop overscan" msgstr "" msgctxt "#30001" msgid "Crop away invisible edges of the screen, if the game is aware of any." msgstr "" game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.mk_mk/000077500000000000000000000000001445145641500304775ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.mk_mk/strings.po000066400000000000000000000017041445145641500325320ustar00rootroot00000000000000# game.libretro language file # Addon Name: Libretro Compatibility # Addon id: game.libretro # Addon Provider: Garrett Brown msgid "" msgstr "" "Project-Id-Version: Libretro Compatibility\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: 2014-05-30 17:00+8\n" "PO-Revision-Date: 2014-05-30 17:00+8\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" "Language: mk_mk\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n==1 || n%10==1 ? 0 : 1;\n" msgctxt "Addon Summary" msgid "Libretro compatibility layer for Kodi's Game API" msgstr "" msgctxt "Addon Description" msgid "This add-on provides a wrapper for libretro cores, allowing them to be loaded as game add-ons." msgstr "" msgctxt "#30000" msgid "Crop overscan" msgstr "" msgctxt "#30001" msgid "Crop away invisible edges of the screen, if the game is aware of any." msgstr "" game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.ml_in/000077500000000000000000000000001445145641500304775ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.ml_in/strings.po000066400000000000000000000016631445145641500325360ustar00rootroot00000000000000# game.libretro language file # Addon Name: Libretro Compatibility # Addon id: game.libretro # Addon Provider: Garrett Brown msgid "" msgstr "" "Project-Id-Version: Libretro Compatibility\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: 2014-05-30 17:00+8\n" "PO-Revision-Date: 2014-05-30 17:00+8\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" "Language: ml_in\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" msgctxt "Addon Summary" msgid "Libretro compatibility layer for Kodi's Game API" msgstr "" msgctxt "Addon Description" msgid "This add-on provides a wrapper for libretro cores, allowing them to be loaded as game add-ons." msgstr "" msgctxt "#30000" msgid "Crop overscan" msgstr "" msgctxt "#30001" msgid "Crop away invisible edges of the screen, if the game is aware of any." msgstr "" game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.mn_mn/000077500000000000000000000000001445145641500305055ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.mn_mn/strings.po000066400000000000000000000016631445145641500325440ustar00rootroot00000000000000# game.libretro language file # Addon Name: Libretro Compatibility # Addon id: game.libretro # Addon Provider: Garrett Brown msgid "" msgstr "" "Project-Id-Version: Libretro Compatibility\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: 2014-05-30 17:00+8\n" "PO-Revision-Date: 2014-05-30 17:00+8\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" "Language: mn_mn\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" msgctxt "Addon Summary" msgid "Libretro compatibility layer for Kodi's Game API" msgstr "" msgctxt "Addon Description" msgid "This add-on provides a wrapper for libretro cores, allowing them to be loaded as game add-ons." msgstr "" msgctxt "#30000" msgid "Crop overscan" msgstr "" msgctxt "#30001" msgid "Crop away invisible edges of the screen, if the game is aware of any." msgstr "" game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.ms_my/000077500000000000000000000000001445145641500305255ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.ms_my/strings.po000066400000000000000000000016561445145641500325660ustar00rootroot00000000000000# game.libretro language file # Addon Name: Libretro Compatibility # Addon id: game.libretro # Addon Provider: Garrett Brown msgid "" msgstr "" "Project-Id-Version: Libretro Compatibility\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: 2014-05-30 17:00+8\n" "PO-Revision-Date: 2014-05-30 17:00+8\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" "Language: ms_my\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" msgctxt "Addon Summary" msgid "Libretro compatibility layer for Kodi's Game API" msgstr "" msgctxt "Addon Description" msgid "This add-on provides a wrapper for libretro cores, allowing them to be loaded as game add-ons." msgstr "" msgctxt "#30000" msgid "Crop overscan" msgstr "" msgctxt "#30001" msgid "Crop away invisible edges of the screen, if the game is aware of any." msgstr "" game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.mt_mt/000077500000000000000000000000001445145641500305215ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.mt_mt/strings.po000066400000000000000000000017741445145641500325630ustar00rootroot00000000000000# game.libretro language file # Addon Name: Libretro Compatibility # Addon id: game.libretro # Addon Provider: Garrett Brown msgid "" msgstr "" "Project-Id-Version: Libretro Compatibility\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: 2014-05-30 17:00+8\n" "PO-Revision-Date: 2014-05-30 17:00+8\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" "Language: mt_mt\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=n==1 ? 0 : n==0 || ( n%100>1 && n%100<11) ? 1 : (n%100>10 && n%100<20 ) ? 2 : 3;\n" msgctxt "Addon Summary" msgid "Libretro compatibility layer for Kodi's Game API" msgstr "" msgctxt "Addon Description" msgid "This add-on provides a wrapper for libretro cores, allowing them to be loaded as game add-ons." msgstr "" msgctxt "#30000" msgid "Crop overscan" msgstr "" msgctxt "#30001" msgid "Crop away invisible edges of the screen, if the game is aware of any." msgstr "" game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.my_mm/000077500000000000000000000000001445145641500305175ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.my_mm/strings.po000066400000000000000000000016561445145641500325600ustar00rootroot00000000000000# game.libretro language file # Addon Name: Libretro Compatibility # Addon id: game.libretro # Addon Provider: Garrett Brown msgid "" msgstr "" "Project-Id-Version: Libretro Compatibility\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: 2014-05-30 17:00+8\n" "PO-Revision-Date: 2014-05-30 17:00+8\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" "Language: my_mm\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" msgctxt "Addon Summary" msgid "Libretro compatibility layer for Kodi's Game API" msgstr "" msgctxt "Addon Description" msgid "This add-on provides a wrapper for libretro cores, allowing them to be loaded as game add-ons." msgstr "" msgctxt "#30000" msgid "Crop overscan" msgstr "" msgctxt "#30001" msgid "Crop away invisible edges of the screen, if the game is aware of any." msgstr "" game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.nb_no/000077500000000000000000000000001445145641500304745ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.nb_no/strings.po000066400000000000000000000016631445145641500325330ustar00rootroot00000000000000# game.libretro language file # Addon Name: Libretro Compatibility # Addon id: game.libretro # Addon Provider: Garrett Brown msgid "" msgstr "" "Project-Id-Version: Libretro Compatibility\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: 2014-05-30 17:00+8\n" "PO-Revision-Date: 2014-05-30 17:00+8\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" "Language: nb_no\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" msgctxt "Addon Summary" msgid "Libretro compatibility layer for Kodi's Game API" msgstr "" msgctxt "Addon Description" msgid "This add-on provides a wrapper for libretro cores, allowing them to be loaded as game add-ons." msgstr "" msgctxt "#30000" msgid "Crop overscan" msgstr "" msgctxt "#30001" msgid "Crop away invisible edges of the screen, if the game is aware of any." msgstr "" game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.nl_nl/000077500000000000000000000000001445145641500305035ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.nl_nl/strings.po000066400000000000000000000016631445145641500325420ustar00rootroot00000000000000# game.libretro language file # Addon Name: Libretro Compatibility # Addon id: game.libretro # Addon Provider: Garrett Brown msgid "" msgstr "" "Project-Id-Version: Libretro Compatibility\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: 2014-05-30 17:00+8\n" "PO-Revision-Date: 2014-05-30 17:00+8\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" "Language: nl_nl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" msgctxt "Addon Summary" msgid "Libretro compatibility layer for Kodi's Game API" msgstr "" msgctxt "Addon Description" msgid "This add-on provides a wrapper for libretro cores, allowing them to be loaded as game add-ons." msgstr "" msgctxt "#30000" msgid "Crop overscan" msgstr "" msgctxt "#30001" msgid "Crop away invisible edges of the screen, if the game is aware of any." msgstr "" game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.oc_fr/000077500000000000000000000000001445145641500304715ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.oc_fr/strings.po000066400000000000000000000016631445145641500325300ustar00rootroot00000000000000# game.libretro language file # Addon Name: Libretro Compatibility # Addon id: game.libretro # Addon Provider: Garrett Brown msgid "" msgstr "" "Project-Id-Version: Libretro Compatibility\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: 2014-05-30 17:00+8\n" "PO-Revision-Date: 2014-05-30 17:00+8\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" "Language: oc_fr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" msgctxt "Addon Summary" msgid "Libretro compatibility layer for Kodi's Game API" msgstr "" msgctxt "Addon Description" msgid "This add-on provides a wrapper for libretro cores, allowing them to be loaded as game add-ons." msgstr "" msgctxt "#30000" msgid "Crop overscan" msgstr "" msgctxt "#30001" msgid "Crop away invisible edges of the screen, if the game is aware of any." msgstr "" game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.os_os/000077500000000000000000000000001445145641500305235ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.os_os/strings.po000066400000000000000000000016631445145641500325620ustar00rootroot00000000000000# game.libretro language file # Addon Name: Libretro Compatibility # Addon id: game.libretro # Addon Provider: Garrett Brown msgid "" msgstr "" "Project-Id-Version: Libretro Compatibility\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: 2014-05-30 17:00+8\n" "PO-Revision-Date: 2014-05-30 17:00+8\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" "Language: os_os\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" msgctxt "Addon Summary" msgid "Libretro compatibility layer for Kodi's Game API" msgstr "" msgctxt "Addon Description" msgid "This add-on provides a wrapper for libretro cores, allowing them to be loaded as game add-ons." msgstr "" msgctxt "#30000" msgid "Crop overscan" msgstr "" msgctxt "#30001" msgid "Crop away invisible edges of the screen, if the game is aware of any." msgstr "" game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.pl_pl/000077500000000000000000000000001445145641500305075ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.pl_pl/strings.po000066400000000000000000000017551445145641500325500ustar00rootroot00000000000000# game.libretro language file # Addon Name: Libretro Compatibility # Addon id: game.libretro # Addon Provider: Garrett Brown msgid "" msgstr "" "Project-Id-Version: Libretro Compatibility\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: 2014-05-30 17:00+8\n" "PO-Revision-Date: 2014-05-30 17:00+8\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" "Language: pl_pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" msgctxt "Addon Summary" msgid "Libretro compatibility layer for Kodi's Game API" msgstr "" msgctxt "Addon Description" msgid "This add-on provides a wrapper for libretro cores, allowing them to be loaded as game add-ons." msgstr "" msgctxt "#30000" msgid "Crop overscan" msgstr "" msgctxt "#30001" msgid "Crop away invisible edges of the screen, if the game is aware of any." msgstr "" game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.pt_br/000077500000000000000000000000001445145641500305075ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.pt_br/strings.po000066400000000000000000000016621445145641500325450ustar00rootroot00000000000000# game.libretro language file # Addon Name: Libretro Compatibility # Addon id: game.libretro # Addon Provider: Garrett Brown msgid "" msgstr "" "Project-Id-Version: Libretro Compatibility\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: 2014-05-30 17:00+8\n" "PO-Revision-Date: 2014-05-30 17:00+8\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" "Language: pt_br\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n > 1;\n" msgctxt "Addon Summary" msgid "Libretro compatibility layer for Kodi's Game API" msgstr "" msgctxt "Addon Description" msgid "This add-on provides a wrapper for libretro cores, allowing them to be loaded as game add-ons." msgstr "" msgctxt "#30000" msgid "Crop overscan" msgstr "" msgctxt "#30001" msgid "Crop away invisible edges of the screen, if the game is aware of any." msgstr "" game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.pt_pt/000077500000000000000000000000001445145641500305275ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.pt_pt/strings.po000066400000000000000000000016621445145641500325650ustar00rootroot00000000000000# game.libretro language file # Addon Name: Libretro Compatibility # Addon id: game.libretro # Addon Provider: Garrett Brown msgid "" msgstr "" "Project-Id-Version: Libretro Compatibility\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: 2014-05-30 17:00+8\n" "PO-Revision-Date: 2014-05-30 17:00+8\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" "Language: pt_pt\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n > 1;\n" msgctxt "Addon Summary" msgid "Libretro compatibility layer for Kodi's Game API" msgstr "" msgctxt "Addon Description" msgid "This add-on provides a wrapper for libretro cores, allowing them to be loaded as game add-ons." msgstr "" msgctxt "#30000" msgid "Crop overscan" msgstr "" msgctxt "#30001" msgid "Crop away invisible edges of the screen, if the game is aware of any." msgstr "" game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.ro_ro/000077500000000000000000000000001445145641500305215ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.ro_ro/strings.po000066400000000000000000000017431445145641500325570ustar00rootroot00000000000000# game.libretro language file # Addon Name: Libretro Compatibility # Addon id: game.libretro # Addon Provider: Garrett Brown msgid "" msgstr "" "Project-Id-Version: Libretro Compatibility\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: 2014-05-30 17:00+8\n" "PO-Revision-Date: 2014-05-30 17:00+8\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" "Language: ro_ro\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : (n==0 || (n%100 > 0 && n%100 < 20)) ? 1 : 2;\n" msgctxt "Addon Summary" msgid "Libretro compatibility layer for Kodi's Game API" msgstr "" msgctxt "Addon Description" msgid "This add-on provides a wrapper for libretro cores, allowing them to be loaded as game add-ons." msgstr "" msgctxt "#30000" msgid "Crop overscan" msgstr "" msgctxt "#30001" msgid "Crop away invisible edges of the screen, if the game is aware of any." msgstr "" game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.ru_ru/000077500000000000000000000000001445145641500305355ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.ru_ru/strings.po000066400000000000000000000023671445145641500325760ustar00rootroot00000000000000# game.libretro language file # Addon Name: Libretro Compatibility # Addon id: game.libretro # Addon Provider: Garrett Brown msgid "" msgstr "" "Project-Id-Version: Libretro Compatibility\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: 2014-05-30 17:00+8\n" "PO-Revision-Date: 2021-04-16 04:29+0000\n" "Last-Translator: Dmitry Petrov \n" "Language-Team: Russian \n" "Language: ru_ru\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" "X-Generator: Weblate 4.5.3\n" msgctxt "Addon Summary" msgid "Libretro compatibility layer for Kodi's Game API" msgstr "" msgctxt "Addon Description" msgid "This add-on provides a wrapper for libretro cores, allowing them to be loaded as game add-ons." msgstr "" msgctxt "#30000" msgid "Crop overscan" msgstr "Обрезать overscan" msgctxt "#30001" msgid "Crop away invisible edges of the screen, if the game is aware of any." msgstr "Убрать невидимые углы Ñкрана, еÑли игра об Ñтом знает." game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.si_lk/000077500000000000000000000000001445145641500305025ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.si_lk/strings.po000066400000000000000000000016621445145641500325400ustar00rootroot00000000000000# game.libretro language file # Addon Name: Libretro Compatibility # Addon id: game.libretro # Addon Provider: Garrett Brown msgid "" msgstr "" "Project-Id-Version: Libretro Compatibility\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: 2014-05-30 17:00+8\n" "PO-Revision-Date: 2014-05-30 17:00+8\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" "Language: si_lk\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n > 1;\n" msgctxt "Addon Summary" msgid "Libretro compatibility layer for Kodi's Game API" msgstr "" msgctxt "Addon Description" msgid "This add-on provides a wrapper for libretro cores, allowing them to be loaded as game add-ons." msgstr "" msgctxt "#30000" msgid "Crop overscan" msgstr "" msgctxt "#30001" msgid "Crop away invisible edges of the screen, if the game is aware of any." msgstr "" game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.sk_sk/000077500000000000000000000000001445145641500305135ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.sk_sk/strings.po000066400000000000000000000017201445145641500325440ustar00rootroot00000000000000# game.libretro language file # Addon Name: Libretro Compatibility # Addon id: game.libretro # Addon Provider: Garrett Brown msgid "" msgstr "" "Project-Id-Version: Libretro Compatibility\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: 2014-05-30 17:00+8\n" "PO-Revision-Date: 2014-05-30 17:00+8\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" "Language: sk_sk\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" msgctxt "Addon Summary" msgid "Libretro compatibility layer for Kodi's Game API" msgstr "" msgctxt "Addon Description" msgid "This add-on provides a wrapper for libretro cores, allowing them to be loaded as game add-ons." msgstr "" msgctxt "#30000" msgid "Crop overscan" msgstr "" msgctxt "#30001" msgid "Crop away invisible edges of the screen, if the game is aware of any." msgstr "" game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.sl_si/000077500000000000000000000000001445145641500305125ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.sl_si/strings.po000066400000000000000000000017471445145641500325540ustar00rootroot00000000000000# game.libretro language file # Addon Name: Libretro Compatibility # Addon id: game.libretro # Addon Provider: Garrett Brown msgid "" msgstr "" "Project-Id-Version: Libretro Compatibility\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: 2014-05-30 17:00+8\n" "PO-Revision-Date: 2014-05-30 17:00+8\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" "Language: sl_si\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3;\n" msgctxt "Addon Summary" msgid "Libretro compatibility layer for Kodi's Game API" msgstr "" msgctxt "Addon Description" msgid "This add-on provides a wrapper for libretro cores, allowing them to be loaded as game add-ons." msgstr "" msgctxt "#30000" msgid "Crop overscan" msgstr "" msgctxt "#30001" msgid "Crop away invisible edges of the screen, if the game is aware of any." msgstr "" game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.sq_al/000077500000000000000000000000001445145641500305005ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.sq_al/strings.po000066400000000000000000000016631445145641500325370ustar00rootroot00000000000000# game.libretro language file # Addon Name: Libretro Compatibility # Addon id: game.libretro # Addon Provider: Garrett Brown msgid "" msgstr "" "Project-Id-Version: Libretro Compatibility\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: 2014-05-30 17:00+8\n" "PO-Revision-Date: 2014-05-30 17:00+8\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" "Language: sq_al\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" msgctxt "Addon Summary" msgid "Libretro compatibility layer for Kodi's Game API" msgstr "" msgctxt "Addon Description" msgid "This add-on provides a wrapper for libretro cores, allowing them to be loaded as game add-ons." msgstr "" msgctxt "#30000" msgid "Crop overscan" msgstr "" msgctxt "#30001" msgid "Crop away invisible edges of the screen, if the game is aware of any." msgstr "" game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.sr_rs/000077500000000000000000000000001445145641500305315ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.sr_rs/strings.po000066400000000000000000000017751445145641500325740ustar00rootroot00000000000000# game.libretro language file # Addon Name: Libretro Compatibility # Addon id: game.libretro # Addon Provider: Garrett Brown msgid "" msgstr "" "Project-Id-Version: Libretro Compatibility\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: 2014-05-30 17:00+8\n" "PO-Revision-Date: 2014-05-30 17:00+8\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" "Language: sr_rs\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" msgctxt "Addon Summary" msgid "Libretro compatibility layer for Kodi's Game API" msgstr "" msgctxt "Addon Description" msgid "This add-on provides a wrapper for libretro cores, allowing them to be loaded as game add-ons." msgstr "" msgctxt "#30000" msgid "Crop overscan" msgstr "" msgctxt "#30001" msgid "Crop away invisible edges of the screen, if the game is aware of any." msgstr "" game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.sr_rs@latin/000077500000000000000000000000001445145641500316615ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.sr_rs@latin/strings.po000066400000000000000000000017771445145641500337260ustar00rootroot00000000000000# game.libretro language file # Addon Name: Libretro Compatibility # Addon id: game.libretro # Addon Provider: Garrett Brown msgid "" msgstr "" "Project-Id-Version: Libretro Compatibility\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: 2014-05-30 17:00+8\n" "PO-Revision-Date: 2014-05-30 17:00+8\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" "Language: sr_Latn\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" msgctxt "Addon Summary" msgid "Libretro compatibility layer for Kodi's Game API" msgstr "" msgctxt "Addon Description" msgid "This add-on provides a wrapper for libretro cores, allowing them to be loaded as game add-ons." msgstr "" msgctxt "#30000" msgid "Crop overscan" msgstr "" msgctxt "#30001" msgid "Crop away invisible edges of the screen, if the game is aware of any." msgstr "" game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.sv_se/000077500000000000000000000000001445145641500305205ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.sv_se/strings.po000066400000000000000000000016631445145641500325570ustar00rootroot00000000000000# game.libretro language file # Addon Name: Libretro Compatibility # Addon id: game.libretro # Addon Provider: Garrett Brown msgid "" msgstr "" "Project-Id-Version: Libretro Compatibility\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: 2014-05-30 17:00+8\n" "PO-Revision-Date: 2014-05-30 17:00+8\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" "Language: sv_se\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" msgctxt "Addon Summary" msgid "Libretro compatibility layer for Kodi's Game API" msgstr "" msgctxt "Addon Description" msgid "This add-on provides a wrapper for libretro cores, allowing them to be loaded as game add-ons." msgstr "" msgctxt "#30000" msgid "Crop overscan" msgstr "" msgctxt "#30001" msgid "Crop away invisible edges of the screen, if the game is aware of any." msgstr "" game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.szl/000077500000000000000000000000001445145641500302115ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.szl/strings.po000066400000000000000000000017531445145641500322500ustar00rootroot00000000000000# game.libretro language file # Addon Name: Libretro Compatibility # Addon id: game.libretro # Addon Provider: Garrett Brown msgid "" msgstr "" "Project-Id-Version: Libretro Compatibility\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: 2014-05-30 17:00+8\n" "PO-Revision-Date: 2014-05-30 17:00+8\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" "Language: szl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" msgctxt "Addon Summary" msgid "Libretro compatibility layer for Kodi's Game API" msgstr "" msgctxt "Addon Description" msgid "This add-on provides a wrapper for libretro cores, allowing them to be loaded as game add-ons." msgstr "" msgctxt "#30000" msgid "Crop overscan" msgstr "" msgctxt "#30001" msgid "Crop away invisible edges of the screen, if the game is aware of any." msgstr "" game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.ta_in/000077500000000000000000000000001445145641500304735ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.ta_in/strings.po000066400000000000000000000016631445145641500325320ustar00rootroot00000000000000# game.libretro language file # Addon Name: Libretro Compatibility # Addon id: game.libretro # Addon Provider: Garrett Brown msgid "" msgstr "" "Project-Id-Version: Libretro Compatibility\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: 2014-05-30 17:00+8\n" "PO-Revision-Date: 2014-05-30 17:00+8\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" "Language: ta_in\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" msgctxt "Addon Summary" msgid "Libretro compatibility layer for Kodi's Game API" msgstr "" msgctxt "Addon Description" msgid "This add-on provides a wrapper for libretro cores, allowing them to be loaded as game add-ons." msgstr "" msgctxt "#30000" msgid "Crop overscan" msgstr "" msgctxt "#30001" msgid "Crop away invisible edges of the screen, if the game is aware of any." msgstr "" game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.te_in/000077500000000000000000000000001445145641500304775ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.te_in/strings.po000066400000000000000000000016631445145641500325360ustar00rootroot00000000000000# game.libretro language file # Addon Name: Libretro Compatibility # Addon id: game.libretro # Addon Provider: Garrett Brown msgid "" msgstr "" "Project-Id-Version: Libretro Compatibility\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: 2014-05-30 17:00+8\n" "PO-Revision-Date: 2014-05-30 17:00+8\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" "Language: te_in\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" msgctxt "Addon Summary" msgid "Libretro compatibility layer for Kodi's Game API" msgstr "" msgctxt "Addon Description" msgid "This add-on provides a wrapper for libretro cores, allowing them to be loaded as game add-ons." msgstr "" msgctxt "#30000" msgid "Crop overscan" msgstr "" msgctxt "#30001" msgid "Crop away invisible edges of the screen, if the game is aware of any." msgstr "" game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.tg_tj/000077500000000000000000000000001445145641500305105ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.tg_tj/strings.po000066400000000000000000000016561445145641500325510ustar00rootroot00000000000000# game.libretro language file # Addon Name: Libretro Compatibility # Addon id: game.libretro # Addon Provider: Garrett Brown msgid "" msgstr "" "Project-Id-Version: Libretro Compatibility\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: 2014-05-30 17:00+8\n" "PO-Revision-Date: 2014-05-30 17:00+8\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" "Language: tg_tj\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" msgctxt "Addon Summary" msgid "Libretro compatibility layer for Kodi's Game API" msgstr "" msgctxt "Addon Description" msgid "This add-on provides a wrapper for libretro cores, allowing them to be loaded as game add-ons." msgstr "" msgctxt "#30000" msgid "Crop overscan" msgstr "" msgctxt "#30001" msgid "Crop away invisible edges of the screen, if the game is aware of any." msgstr "" game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.th_th/000077500000000000000000000000001445145641500305075ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.th_th/strings.po000066400000000000000000000016561445145641500325500ustar00rootroot00000000000000# game.libretro language file # Addon Name: Libretro Compatibility # Addon id: game.libretro # Addon Provider: Garrett Brown msgid "" msgstr "" "Project-Id-Version: Libretro Compatibility\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: 2014-05-30 17:00+8\n" "PO-Revision-Date: 2014-05-30 17:00+8\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" "Language: th_th\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" msgctxt "Addon Summary" msgid "Libretro compatibility layer for Kodi's Game API" msgstr "" msgctxt "Addon Description" msgid "This add-on provides a wrapper for libretro cores, allowing them to be loaded as game add-ons." msgstr "" msgctxt "#30000" msgid "Crop overscan" msgstr "" msgctxt "#30001" msgid "Crop away invisible edges of the screen, if the game is aware of any." msgstr "" game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.tr_tr/000077500000000000000000000000001445145641500305335ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.tr_tr/strings.po000066400000000000000000000016631445145641500325720ustar00rootroot00000000000000# game.libretro language file # Addon Name: Libretro Compatibility # Addon id: game.libretro # Addon Provider: Garrett Brown msgid "" msgstr "" "Project-Id-Version: Libretro Compatibility\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: 2014-05-30 17:00+8\n" "PO-Revision-Date: 2014-05-30 17:00+8\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" "Language: tr_tr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" msgctxt "Addon Summary" msgid "Libretro compatibility layer for Kodi's Game API" msgstr "" msgctxt "Addon Description" msgid "This add-on provides a wrapper for libretro cores, allowing them to be loaded as game add-ons." msgstr "" msgctxt "#30000" msgid "Crop overscan" msgstr "" msgctxt "#30001" msgid "Crop away invisible edges of the screen, if the game is aware of any." msgstr "" game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.uk_ua/000077500000000000000000000000001445145641500305055ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.uk_ua/strings.po000066400000000000000000000017751445145641500325500ustar00rootroot00000000000000# game.libretro language file # Addon Name: Libretro Compatibility # Addon id: game.libretro # Addon Provider: Garrett Brown msgid "" msgstr "" "Project-Id-Version: Libretro Compatibility\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: 2014-05-30 17:00+8\n" "PO-Revision-Date: 2014-05-30 17:00+8\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" "Language: uk_ua\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" msgctxt "Addon Summary" msgid "Libretro compatibility layer for Kodi's Game API" msgstr "" msgctxt "Addon Description" msgid "This add-on provides a wrapper for libretro cores, allowing them to be loaded as game add-ons." msgstr "" msgctxt "#30000" msgid "Crop overscan" msgstr "" msgctxt "#30001" msgid "Crop away invisible edges of the screen, if the game is aware of any." msgstr "" game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.uz_uz/000077500000000000000000000000001445145641500305555ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.uz_uz/strings.po000066400000000000000000000016631445145641500326140ustar00rootroot00000000000000# game.libretro language file # Addon Name: Libretro Compatibility # Addon id: game.libretro # Addon Provider: Garrett Brown msgid "" msgstr "" "Project-Id-Version: Libretro Compatibility\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: 2014-05-30 17:00+8\n" "PO-Revision-Date: 2014-05-30 17:00+8\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" "Language: uz_uz\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" msgctxt "Addon Summary" msgid "Libretro compatibility layer for Kodi's Game API" msgstr "" msgctxt "Addon Description" msgid "This add-on provides a wrapper for libretro cores, allowing them to be loaded as game add-ons." msgstr "" msgctxt "#30000" msgid "Crop overscan" msgstr "" msgctxt "#30001" msgid "Crop away invisible edges of the screen, if the game is aware of any." msgstr "" game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.vi_vn/000077500000000000000000000000001445145641500305225ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.vi_vn/strings.po000066400000000000000000000016561445145641500325630ustar00rootroot00000000000000# game.libretro language file # Addon Name: Libretro Compatibility # Addon id: game.libretro # Addon Provider: Garrett Brown msgid "" msgstr "" "Project-Id-Version: Libretro Compatibility\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: 2014-05-30 17:00+8\n" "PO-Revision-Date: 2014-05-30 17:00+8\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" "Language: vi_vn\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" msgctxt "Addon Summary" msgid "Libretro compatibility layer for Kodi's Game API" msgstr "" msgctxt "Addon Description" msgid "This add-on provides a wrapper for libretro cores, allowing them to be loaded as game add-ons." msgstr "" msgctxt "#30000" msgid "Crop overscan" msgstr "" msgctxt "#30001" msgid "Crop away invisible edges of the screen, if the game is aware of any." msgstr "" game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.zh_cn/000077500000000000000000000000001445145641500305025ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.zh_cn/strings.po000066400000000000000000000024011445145641500325300ustar00rootroot00000000000000# game.libretro language file # Addon Name: Libretro Compatibility # Addon id: game.libretro # Addon Provider: Garrett Brown msgid "" msgstr "" "Project-Id-Version: Libretro Compatibility\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: 2014-05-30 17:00+8\n" "PO-Revision-Date: 2021-09-12 18:42+0000\n" "Last-Translator: taxigps \n" "Language-Team: Chinese (China) \n" "Language: zh_cn\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" "X-Generator: Weblate 4.8\n" msgctxt "Addon Summary" msgid "Libretro compatibility layer for Kodi's Game API" msgstr "用于 Kodi æ¸¸æˆ API çš„ Libretro 兼容层" msgctxt "Addon Description" msgid "This add-on provides a wrapper for libretro cores, allowing them to be loaded as game add-ons." msgstr "这个æ’件为 libretro 内核æä¾›äº†ä¸€ä¸ªåŒ…装器,å…è®¸å®ƒä»¬ä½œä¸ºæ¸¸æˆæ’件加载。" msgctxt "#30000" msgid "Crop overscan" msgstr "è£å‰ªè¿‡åº¦æ‰«æ" msgctxt "#30001" msgid "Crop away invisible edges of the screen, if the game is aware of any." msgstr "è£å‰ªæŽ‰æ¸¸æˆä¸­å­˜åœ¨çš„å±å¹•ä¸å¯è§è¾¹ç¼˜ã€‚" game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.zh_tw/000077500000000000000000000000001445145641500305345ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/game.libretro/resources/language/resource.language.zh_tw/strings.po000066400000000000000000000016631445145641500325730ustar00rootroot00000000000000# game.libretro language file # Addon Name: Libretro Compatibility # Addon id: game.libretro # Addon Provider: Garrett Brown msgid "" msgstr "" "Project-Id-Version: Libretro Compatibility\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: 2014-05-30 17:00+8\n" "PO-Revision-Date: 2014-05-30 17:00+8\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" "Language: zh_tw\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" msgctxt "Addon Summary" msgid "Libretro compatibility layer for Kodi's Game API" msgstr "" msgctxt "Addon Description" msgid "This add-on provides a wrapper for libretro cores, allowing them to be loaded as game add-ons." msgstr "" msgctxt "#30000" msgid "Crop overscan" msgstr "" msgctxt "#30001" msgid "Crop away invisible edges of the screen, if the game is aware of any." msgstr "" game.libretro-20.2.4-Nexus/game.libretro/resources/settings.xml000066400000000000000000000006131445145641500245700ustar00rootroot00000000000000
false
game.libretro-20.2.4-Nexus/src/000077500000000000000000000000001445145641500162315ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/src/GameInfoLoader.cpp000066400000000000000000000063521445145641500215570ustar00rootroot00000000000000/* * Copyright (C) 2014-2021 Team Kodi (https://kodi.tv) * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSE.md for more information. */ #include "GameInfoLoader.h" #include "log/Log.h" #include #include using namespace LIBRETRO; #define READ_SIZE (100 * 1024) // Read from VFS 100KB at a time (if file size is unknown) #define MAX_READ_SIZE (100 * 1024 * 1024) // Read at most 100MB from VFS CGameInfoLoader::CGameInfoLoader(const std::string& path, bool bSupportsVFS) : m_path(path), m_bSupportsVfs(bSupportsVFS) { } bool CGameInfoLoader::Load(void) { if (!m_bSupportsVfs) return false; kodi::vfs::FileStatus statStruct; bool bExists = kodi::vfs::StatFile(m_path, statStruct); // Not all VFS protocols necessarily support StatFile(), so also check if file exists if (!bExists) { bExists = kodi::vfs::FileExists(m_path, true); if (bExists) { dsyslog("Failed to stat (but file exists): %s", m_path.c_str()); } else { esyslog("File doesn't exist: %s", m_path.c_str()); return false; } } kodi::vfs::CFile file; if (!file.OpenFile(m_path)) { esyslog("Failed to open file: %s", m_path.c_str()); return false; } uint64_t size = statStruct.GetSize(); if (size > 0) { // Size is known, read entire file at once (unless it is too big) if (size <= MAX_READ_SIZE) { m_dataBuffer.resize(static_cast(size)); file.Read(m_dataBuffer.data(), static_cast(size)); } else { dsyslog("File size (%d MB) is greater than memory limit (%d MB), loading by path", size / (1024 * 1024), MAX_READ_SIZE / (1024 * 1024)); return false; } } else { // Read file in chunks ssize_t bytesRead; uint8_t buffer[READ_SIZE]; while ((bytesRead = file.Read(buffer, sizeof(buffer))) > 0) { m_dataBuffer.insert(m_dataBuffer.end(), buffer, buffer + bytesRead); // If we read less than READ_SIZE, assume we hit the end of the file if (bytesRead < READ_SIZE) break; // If we have exceeded the VFS file size limit, don't try to load by // VFS and fall back to loading by path if (m_dataBuffer.size() > MAX_READ_SIZE) { dsyslog("File exceeds memory limit (%d MB), loading by path", MAX_READ_SIZE / (1024 * 1024)); return false; } } } if (m_dataBuffer.empty()) { dsyslog("Failed to read file (no data), loading by path"); return false; } dsyslog("Loaded file into memory (%d bytes): %s", m_dataBuffer.size(), m_path.c_str()); return true; } bool CGameInfoLoader::GetMemoryStruct(retro_game_info& info) const { if (!m_dataBuffer.empty()) { //! @todo path is null according to libretro API, but many cores expect // the frontend to set this. Do so to guard against // noncompliant cores. info.path = m_path.c_str(); info.data = m_dataBuffer.data(); info.size = m_dataBuffer.size(); info.meta = nullptr; return true; } return false; } bool CGameInfoLoader::GetPathStruct(retro_game_info& info) const { info.path = m_path.c_str(); info.data = nullptr; info.size = 0; info.meta = nullptr; return true; } game.libretro-20.2.4-Nexus/src/GameInfoLoader.h000066400000000000000000000026421445145641500212220ustar00rootroot00000000000000/* * Copyright (C) 2014-2021 Team Kodi (https://kodi.tv) * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSE.md for more information. */ #pragma once #include "libretro-common/libretro.h" #include #include #include namespace LIBRETRO { /*! * Libretro's retro_load_game() and retro_load_game_special() accept a * parameter of type retro_game_info. By setting various fields to NULL, * the libretro core can be instructed to load via memory or via path. This * class abstracts this logic by accepting a path and generating the * appropriate retro_game_info structs. */ class CGameInfoLoader { public: CGameInfoLoader(const std::string& path, bool bSupportsVFS); bool Load(void); /*! * Get the struct that instructs libretro to load via memory. Returns false * if loading via memory is not a valid strategy for this libretro core * (doesn't support VFS, file is too big / doesn't exist, etc). */ bool GetMemoryStruct(retro_game_info& info) const; /*! * As a fallback, this gets a struct that instructs libretro to load via * path. This always returns true. */ bool GetPathStruct(retro_game_info& info) const; private: const std::string m_path; const bool m_bSupportsVfs; std::vector m_dataBuffer; }; } // namespace LIBRETRO game.libretro-20.2.4-Nexus/src/audio/000077500000000000000000000000001445145641500173325ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/src/audio/AudioStream.cpp000066400000000000000000000021311445145641500222500ustar00rootroot00000000000000/* * Copyright (C) 2016-2021 Team Kodi (https://kodi.tv) * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSE.md for more information. */ #include "AudioStream.h" #include "libretro/LibretroEnvironment.h" #include "client.h" using namespace LIBRETRO; CAudioStream::CAudioStream() : m_addon(nullptr), m_singleFrameAudio(this) { } void CAudioStream::Initialize(CGameLibRetro* addon) { m_addon = addon; } void CAudioStream::Deinitialize() { m_stream.Close(); m_addon = nullptr; } void CAudioStream::AddFrames_S16NE(const uint8_t* data, unsigned int size) { if (m_addon && !m_stream.IsOpen()) { static const GAME_AUDIO_CHANNEL channelMap[] = { GAME_CH_FL, GAME_CH_FR, GAME_CH_NULL }; game_stream_properties properties{}; properties.type = GAME_STREAM_AUDIO; properties.audio.format = GAME_PCM_FORMAT_S16NE; properties.audio.channel_map = channelMap; if (m_stream.Open(properties)) return; } game_stream_packet packet{}; packet.type = GAME_STREAM_AUDIO; packet.audio.data = data; packet.audio.size = size; m_stream.AddData(packet); } game.libretro-20.2.4-Nexus/src/audio/AudioStream.h000066400000000000000000000013671445145641500217270ustar00rootroot00000000000000/* * Copyright (C) 2016-2021 Team Kodi (https://kodi.tv) * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSE.md for more information. */ #pragma once #include "SingleFrameAudio.h" #include #include class CGameLibRetro; namespace LIBRETRO { class ATTR_DLL_LOCAL CAudioStream { public: CAudioStream(); void Initialize(CGameLibRetro* addon); void Deinitialize(); void AddFrame_S16NE(int16_t left, int16_t right) { m_singleFrameAudio.AddFrame(left, right); } void AddFrames_S16NE(const uint8_t* data, unsigned int size); private: CGameLibRetro* m_addon; CSingleFrameAudio m_singleFrameAudio; kodi::addon::CInstanceGame::CStream m_stream; }; } game.libretro-20.2.4-Nexus/src/audio/SingleFrameAudio.cpp000066400000000000000000000020031445145641500232070ustar00rootroot00000000000000/* * Copyright (C) 2016-2021 Team Kodi (https://kodi.tv) * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSE.md for more information. */ #include "SingleFrameAudio.h" #include "AudioStream.h" using namespace LIBRETRO; #define FRAMES_PER_PACKET 100 // This can be calculated from CLibretroEnvironment::GetSystemInfo().timing.sample_rate #define SAMPLES_PER_FRAME 2 // L + R #define SAMPLE_SIZE sizeof(int16_t) CSingleFrameAudio::CSingleFrameAudio(CAudioStream* audioStream) : m_audioStream(audioStream) { m_data.reserve(FRAMES_PER_PACKET * SAMPLES_PER_FRAME); } void CSingleFrameAudio::AddFrame(int16_t left, int16_t right) { m_data.push_back(left); m_data.push_back(right); const unsigned int frameCount = static_cast(m_data.size() / SAMPLES_PER_FRAME); if (frameCount >= FRAMES_PER_PACKET) { m_audioStream->AddFrames_S16NE(reinterpret_cast(m_data.data()), static_cast(m_data.size() * SAMPLE_SIZE)); m_data.clear(); } } game.libretro-20.2.4-Nexus/src/audio/SingleFrameAudio.h000066400000000000000000000007421445145641500226640ustar00rootroot00000000000000/* * Copyright (C) 2016-2021 Team Kodi (https://kodi.tv) * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSE.md for more information. */ #pragma once #include #include namespace LIBRETRO { class CAudioStream; class CSingleFrameAudio { public: CSingleFrameAudio(CAudioStream* audioStream); void AddFrame(int16_t left, int16_t right); private: CAudioStream* const m_audioStream; std::vector m_data; }; } game.libretro-20.2.4-Nexus/src/cheevos/000077500000000000000000000000001445145641500176655ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/src/cheevos/Cheevos.cpp000066400000000000000000000153351445145641500217740ustar00rootroot00000000000000/* * This file is based on https://github.com/libretro/RetroArch/blob/96c5f5dfb07454c972c50838815330382d6b1911/cheevos/fixup.c * * Copyright (C) 2014-2020 Team Kodi (https://kodi.tv) * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSE.md for more information. */ #include "Cheevos.h" #include "libretro/LibretroEnvironment.h" #include "libretro/MemoryMap.h" #include "rcheevos/rconsoles.h" #include "rcheevos/rhash.h" #include "rcheevos/rurl.h" using namespace LIBRETRO; namespace { constexpr unsigned int HASH_SIZE = 33; constexpr unsigned int URL_SIZE = 512; constexpr unsigned int RICH_PRESENCE_EVAL_SIZE = 512; constexpr unsigned int POST_DATA_SIZE = 1024; } // namespace CCheevos::CCheevos() { rc_runtime_init(&m_runtime); } void CCheevos::Initialize() { rc_runtime_init(&m_runtime); } void CCheevos::Deinitialize() { rc_runtime_destroy(&m_runtime); } void CCheevos::ResetRuntime() { rc_runtime_reset(&m_runtime); m_richPresence = rc_parse_richpresence(m_richPresenceBuffer.data(), m_richPresenceScript.c_str(), NULL, 0); } CCheevos& CCheevos::Get(void) { static CCheevos _instance; return _instance; } bool CCheevos::GenerateHashFromFile(std::string& hash, unsigned int consoleID, const std::string& filePath) { char _hash[HASH_SIZE] = {}; int res = rc_hash_generate_from_file(_hash, consoleID, filePath.c_str()); hash = _hash; return res != RC_OK; } bool CCheevos::GetGameIDUrl(std::string& url, const std::string& hash) { char _url[URL_SIZE] = {}; int res = rc_url_get_gameid(_url, URL_SIZE, hash.c_str()); url = _url; return res == 0; } bool CCheevos::GetPatchFileUrl(std::string& url, const std::string& username, const std::string& token, unsigned int gameID) { char _url[URL_SIZE] = {}; int res = rc_url_get_patch(_url, URL_SIZE, username.c_str(), token.c_str(), gameID); url = _url; return res == 0; } bool CCheevos::PostRichPresenceUrl(std::string& url, std::string& postData, const std::string& username, const std::string& token, unsigned int gameID, const std::string& richPresence) { char _url[URL_SIZE] = {}; char _postData[POST_DATA_SIZE] = {}; int res = rc_url_ping(_url, URL_SIZE, _postData, POST_DATA_SIZE, username.c_str(), token.c_str(), gameID, richPresence.c_str()); url = _url; postData = _postData; return res >= 0; } void CCheevos::EnableRichPresence(const std::string& script) { const char* _script = script.c_str(); rc_runtime_activate_richpresence(&m_runtime, _script, NULL, 0); m_richPresenceBuffer.resize(rc_richpresence_size(_script)); m_richPresence = rc_parse_richpresence(m_richPresenceBuffer.data(), _script, NULL, 0); m_richPresenceScript = script; } void CCheevos::EvaluateRichPresence(std::string& evaluation, unsigned int consoleID) { char _evaluation[RICH_PRESENCE_EVAL_SIZE] = {}; m_consoleID = consoleID; rc_evaluate_richpresence(m_richPresence, _evaluation, RICH_PRESENCE_EVAL_SIZE, PeekInternal, this, NULL); evaluation = _evaluation; } unsigned int CCheevos::PeekInternal(unsigned address, unsigned num_bytes, void* ud) { CCheevos* cheevos = static_cast(ud); if (cheevos != nullptr) return cheevos->Peek(address, num_bytes); return 0; } unsigned int CCheevos::Peek(unsigned int address, unsigned int numBytes) { CMemoryMap mmap = CLibretroEnvironment::Get().GetMemoryMap(); const uint8_t* data = FixupFind(address, mmap, m_consoleID); unsigned value = 0; if (data) { switch (numBytes) { case 4: value |= data[2] << 16 | data[3] << 24; //no break case 2: value |= data[1] << 8; //no break case 1: value |= data[0]; //no break default: break; } } return value; } const uint8_t* CCheevos::FixupFind(unsigned address, CMemoryMap& mmap, int console) { auto location = m_addressFixups.find(address); if (location != m_addressFixups.end()) return location->second; const uint8_t* dataAddress = PatchAddress(address, mmap, console); m_addressFixups[address] = dataAddress; return dataAddress; } const uint8_t* CCheevos::PatchAddress(size_t address, CMemoryMap& mmap, int console) { const void* pointer = NULL; size_t original_address = address; switch (console) { case RC_CONSOLE_NINTENDO: if (address >= 0x0800 && address < 0x2000) address &= 0x07ff; break; case RC_CONSOLE_GAMEBOY_COLOR: if (address >= 0xe000 && address <= 0xfdff) address -= 0x2000; break; default: break; } if (mmap.Size() != 0) { switch (console) { case RC_CONSOLE_GAMEBOY_ADVANCE: if (address < 0x8000) address += 0x3000000; else address += 0x2000000 - 0x8000; break; case RC_CONSOLE_PC_ENGINE: if (address < 0x002000) address += 0x1f0000; else if (address < 0x012000) address += 0x100000 - 0x002000; else if (address < 0x042000) address += 0x0d0000 - 0x012000; else address += 0x1ee000 - 0x042000; break; case RC_CONSOLE_SUPER_NINTENDO: if (address < 0x020000) address += 0x7e0000; else address += 0x006000 - 0x020000; break; case RC_CONSOLE_SEGA_CD: if (address < 0x010000) address += 0xFF0000; else address += 0x80020000 - 0x010000; break; default: break; } for (size_t i = 0; i < mmap.Size(); i++) { const retro_memory_descriptor_kodi& desc = mmap[i]; if (((desc.descriptor.start ^ address) & desc.descriptor.select) == 0) { pointer = desc.descriptor.ptr; address -= desc.descriptor.start; if (desc.disconnectMask) address = Reduce(address & desc.disconnectMask, desc.descriptor.disconnect); if (address >= desc.descriptor.len) address -= HighestBit(address); address += desc.descriptor.offset; break; } } } if (!pointer) return NULL; return (const uint8_t*)pointer + address; } size_t CCheevos::HighestBit(size_t n) { n |= n >> 1; n |= n >> 2; n |= n >> 4; n |= n >> 8; n |= n >> 16; return n ^ (n >> 1); } size_t CCheevos::Reduce(size_t addr, size_t mask) { while (mask) { size_t tmp = (mask - 1) & ~mask; addr = (addr & tmp) | ((addr >> 1) & ~tmp); mask = (mask & (mask - 1)) >> 1; } return addr; } game.libretro-20.2.4-Nexus/src/cheevos/Cheevos.h000066400000000000000000000037351445145641500214420ustar00rootroot00000000000000/* * Copyright (C) 2014-2020 Team Kodi (https://kodi.tv) * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSE.md for more information. */ #pragma once #include "rcheevos/rcheevos.h" #include #include #include #include #include namespace LIBRETRO { class CMemoryMap; class CCheevos { public: CCheevos(); static CCheevos& Get(); void Initialize(); void Deinitialize(); // When the game is reset, the runtime should also be reset void ResetRuntime(); bool GenerateHashFromFile(std::string& hash, unsigned int consoleID, const std::string& filePath); bool GetGameIDUrl(std::string& url, const std::string& hash); bool GetPatchFileUrl(std::string& url, const std::string& username, const std::string& token, unsigned int gameID); bool PostRichPresenceUrl(std::string& url, std::string& postData, const std::string& username, const std::string& token, unsigned int gameID, const std::string& richPresence); void EnableRichPresence(const std::string& script); void EvaluateRichPresence(std::string& evaluation, unsigned int consoleID); unsigned int Peek(unsigned int address, unsigned int numBytes); private: const uint8_t* FixupFind(unsigned address, CMemoryMap& mmap, int consolecheevos); const uint8_t* PatchAddress(size_t address, CMemoryMap& mmap, int consoleID); size_t HighestBit(size_t n); size_t Reduce(size_t addr, size_t mask); static unsigned int PeekInternal(unsigned address, unsigned num_bytes, void* ud); int m_consoleID; rc_runtime_t m_runtime; std::unordered_map m_addressFixups; // Rich Presence rc_richpresence_t* m_richPresence = nullptr; std::string m_richPresenceScript; std::vector m_richPresenceBuffer; }; } // namespace LIBRETRO game.libretro-20.2.4-Nexus/src/cheevos/CheevosEnvironment.cpp000066400000000000000000000013751445145641500242200ustar00rootroot00000000000000/* * Copyright (C) 2020 Team Kodi (https://kodi.tv) * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSE.md for more information. */ #include "CheevosEnvironment.h" #include "CheevosFrontendBridge.h" #include using namespace LIBRETRO; CCheevosEnvironment& CCheevosEnvironment::Get(void) { static CCheevosEnvironment _instance; return _instance; } void CCheevosEnvironment::Initialize() { static rc_hash_filereader fileReader = { CCheevosFrontendBridge::OpenFile, CCheevosFrontendBridge::Seek, CCheevosFrontendBridge::GetPosition, CCheevosFrontendBridge::ReadFile, CCheevosFrontendBridge::CloseFile, }; rc_hash_init_custom_filereader(&fileReader); } void CCheevosEnvironment::Deinitialize() { } game.libretro-20.2.4-Nexus/src/cheevos/CheevosEnvironment.h000066400000000000000000000006151445145641500236610ustar00rootroot00000000000000/* * Copyright (C) 2020 Team Kodi (https://kodi.tv) * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSE.md for more information. */ #pragma once namespace LIBRETRO { class CCheevosEnvironment { public: static CCheevosEnvironment& Get(void); void Initialize(); void Deinitialize(); private: CCheevosEnvironment() = default; }; } // namespace LIBRETRO game.libretro-20.2.4-Nexus/src/cheevos/CheevosFrontendBridge.cpp000066400000000000000000000045541445145641500246120ustar00rootroot00000000000000/* * Copyright (C) 2020 Team Kodi (https://kodi.tv) * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSE.md for more information. */ #include "CheevosFrontendBridge.h" #include #include using namespace LIBRETRO; void *CCheevosFrontendBridge::OpenFile(const char* path_utf8) { // Return NULL for error if (path_utf8 == nullptr) return nullptr; // TODO: Handle UTF-8? std::unique_ptr fileHandle(new FileHandle{ path_utf8 }); fileHandle->file.reset(new kodi::vfs::CFile); if (!fileHandle->file->OpenFile(fileHandle->path, 0)) return nullptr; // Return the opaque file handle on success return static_cast(fileHandle.release()); } void CCheevosFrontendBridge::CloseFile(void* file_handle) { if (file_handle == nullptr) return; FileHandle *fileHandle = static_cast(file_handle); fileHandle->file->Close(); delete fileHandle; } size_t CCheevosFrontendBridge::GetPosition(void* file_handle) { // Return 0 for error if (file_handle == nullptr) return 0; FileHandle *fileHandle = static_cast(file_handle); const int64_t currentPosition = fileHandle->file->GetPosition(); if (currentPosition < 0) return 0; // Return the current read / write position for the file return static_cast(currentPosition); } void CCheevosFrontendBridge::Seek(void* file_handle, size_t offset, int origin) { if (file_handle == nullptr) return; FileHandle *fileHandle = static_cast(file_handle); int whence = -1; switch (origin) { case 0: whence = SEEK_SET; break; case 1: whence = SEEK_CUR; break; case 2: whence = SEEK_END; break; default: break; } if (whence == -1) return; fileHandle->file->Seek(offset, whence); } size_t CCheevosFrontendBridge::ReadFile(void* file_handle, void* buffer, size_t requested_bytes) { // Return 0 for error if (file_handle == nullptr) return 0; FileHandle *fileHandle = static_cast(file_handle); const ssize_t bytesRead = fileHandle->file->Read(buffer, requested_bytes); if (bytesRead < 0) return 0; // Return 0 if no bytes are available to read (end of file was reached) or // undetectable error occurred if (bytesRead == 0) return 0; // Return the number of bytes read return static_cast(bytesRead); } game.libretro-20.2.4-Nexus/src/cheevos/CheevosFrontendBridge.h000066400000000000000000000017651445145641500242600ustar00rootroot00000000000000/* * Copyright (C) 2020 Team Kodi (https://kodi.tv) * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSE.md for more information. */ #pragma once #include #include #include namespace kodi { namespace vfs { class CFile; } } namespace LIBRETRO { /*! * Provide a bridge for frontend callbacks given to the rcheevos library. * * These functions are given to the rcheevos library in * CheevosEnvironment::Initialize(). */ class CCheevosFrontendBridge { public: // Forward to Kodi VFS API static void *OpenFile(const char* path_utf8); static void CloseFile(void* file_handle); static size_t GetPosition(void* file_handle); static void Seek(void* file_handle, size_t offset, int origin); static size_t ReadFile(void* file_handle, void* buffer, size_t requested_bytes); private: struct FileHandle { std::string path; std::unique_ptr file; }; }; } // namespace LIBRETRO game.libretro-20.2.4-Nexus/src/client.cpp000066400000000000000000000344721445145641500202250ustar00rootroot00000000000000/* * Copyright (C) 2014-2021 Team Kodi (https://kodi.tv) * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSE.md for more information. */ #include "cheevos/Cheevos.h" #include "cheevos/CheevosEnvironment.h" #include "input/ButtonMapper.h" #include "input/ControllerTopology.h" #include "input/InputManager.h" #include "libretro-common/libretro.h" #include "libretro/LibretroEnvironment.h" #include "log/Log.h" #include "log/LogAddon.h" #include "settings/Settings.h" #include "GameInfoLoader.h" #include "client.h" #include #include #include using namespace LIBRETRO; #define GAME_CLIENT_NAME_UNKNOWN "Unknown libretro core" #define GAME_CLIENT_VERSION_UNKNOWN "0.0.0" void SAFE_DELETE_GAME_INFO(std::vector& vec) { for (std::vector::iterator it = vec.begin(); it != vec.end(); ++it) delete *it; vec.clear(); } CGameLibRetro::CGameLibRetro() { } CGameLibRetro::~CGameLibRetro() { /* TODO m_clientBridge.AudioEnable(false); */ CInputManager::Get().ClosePorts(); m_client.retro_deinit(); CControllerTopology::GetInstance().Clear(); CLibretroEnvironment::Get().Deinitialize(); CCheevosEnvironment::Get().Deinitialize(); CCheevos::Get().Deinitialize(); CLog::Get().SetType(SYS_LOG_TYPE_CONSOLE); SAFE_DELETE_GAME_INFO(m_gameInfo); } ADDON_STATUS CGameLibRetro::Create() { try { std::string dllPath = GameClientDllPath(); if (dllPath.empty()) throw ADDON_STATUS_UNKNOWN; CLog::Get().SetType(SYS_LOG_TYPE_ADDON); if (!m_client.Load(dllPath)) { esyslog("Failed to load %s", dllPath.c_str()); throw ADDON_STATUS_PERMANENT_FAILURE; } unsigned int version = m_client.retro_api_version(); if (version != 1) { esyslog("Expected libretro api v1, found version %u", version); throw ADDON_STATUS_PERMANENT_FAILURE; } // Environment must be initialized before calling retro_init() CLibretroEnvironment::Get().Initialize(this, &m_client, &m_clientBridge); CCheevosEnvironment::Get().Initialize(); CButtonMapper::Get().LoadButtonMap(); CControllerTopology::GetInstance().LoadTopology(); CCheevos::Get().Initialize(); m_client.retro_init(); // Log core info retro_system_info systemInfo = { }; m_client.retro_get_system_info(&systemInfo); // VFS support is derived from need_fullpath. This property means that the // libretro cores requires a valid pathname. Conversely, if need_fullpath // is false, the core can load from memory. m_supportsVFS = !systemInfo.need_fullpath; std::string libraryName = systemInfo.library_name ? systemInfo.library_name : ""; std::string libraryVersion = systemInfo.library_version ? systemInfo.library_version : ""; std::string extensions = systemInfo.valid_extensions ? systemInfo.valid_extensions : ""; dsyslog("CORE: ----------------------------------"); dsyslog("CORE: Library name: %s", libraryName.c_str()); dsyslog("CORE: Library version: %s", libraryVersion.c_str()); dsyslog("CORE: Extensions: %s", extensions.c_str()); dsyslog("CORE: Supports VFS: %s", m_supportsVFS ? "true" : "false"); dsyslog("CORE: ----------------------------------"); // Reject invalid properties std::set coreExtensions; // TODO: Parse string from libretro API std::set addonExtensions; // TODO: Convert char** to set if (coreExtensions != addonExtensions) { std::string strAddonExtensions;// = StringUtils::Join(addonExtensions, "|"); // TODO esyslog("CORE: Extensions don't match addon.xml: %s", strAddonExtensions.c_str()); throw ADDON_STATUS_PERMANENT_FAILURE; } if (SupportsVFS() != m_supportsVFS) { esyslog("CORE: VFS support doesn't match addon.xml: %s", SupportsVFS() ? "true" : "false"); throw ADDON_STATUS_PERMANENT_FAILURE; } /* TODO // Initialize libretro's extended audio interface m_clientBridge.AudioEnable(true); */ } catch (const ADDON_STATUS& status) { return status; } if (!CSettings::Get().IsInitialized()) return ADDON_STATUS_NEED_SETTINGS; return ADDON_STATUS_OK; } ADDON_STATUS CGameLibRetro::SetSetting(const std::string& settingName, const kodi::addon::CSettingValue& settingValue) { if (settingName == "" || settingValue.empty()) return ADDON_STATUS_UNKNOWN; CSettings::Get().SetSetting(settingName, settingValue); CLibretroEnvironment::Get().SetSetting(settingName, settingValue.GetString()); return ADDON_STATUS_OK; } GAME_ERROR CGameLibRetro::LoadGame(const std::string& url) { // Build info loader vector SAFE_DELETE_GAME_INFO(m_gameInfo); m_gameInfo.push_back(new CGameInfoLoader(url, m_supportsVFS)); bool bResult = false; // Try to load via memory retro_game_info gameInfo; if (m_gameInfo[0]->Load()) { m_gameInfo[0]->GetMemoryStruct(gameInfo); bResult = m_client.retro_load_game(&gameInfo); } if (!bResult) { // Fall back to loading via path m_gameInfo[0]->GetPathStruct(gameInfo); bResult = m_client.retro_load_game(&gameInfo); } return bResult ? GAME_ERROR_NO_ERROR : GAME_ERROR_FAILED; } GAME_ERROR CGameLibRetro::LoadGameSpecial(SPECIAL_GAME_TYPE type, const std::vector& urls) { // TODO return GAME_ERROR_FAILED; /* retro_system_info info = { }; m_client.retro_get_system_info(&info); const bool bSupportsVFS = !info.need_fullpath; // Build info loader vector SAFE_DELETE_GAME_INFO(m_gameInfo); for (const auto& url : urls) m_gameInfo.push_back(new CGameInfoLoader(url, bSupportsVFS)); // Try to load via memory std::vector infoVec; infoVec.resize(urls.size()); bool bLoadFromMemory = true; for (unsigned int i = 0; bLoadFromMemory && i < urls.size(); i++) bLoadFromMemory &= m_gameInfo[i]->GetMemoryStruct(infoVec[i]); if (bLoadFromMemory) { if (m_client.retro_load_game_special(type, infoVec.data(), urls.size())) return GAME_ERROR_NO_ERROR; } // Fall back to loading by path for (unsigned int i = 0; i < urls.size(); i++) m_gameInfo[i]->GetPathStruct(infoVec[i]); bool result = m_client.retro_load_game_special(type, infoVec.data(), urls.size()); return result ? GAME_ERROR_NO_ERROR : GAME_ERROR_FAILED; */ } GAME_ERROR CGameLibRetro::LoadStandalone() { if (!m_client.retro_load_game(nullptr)) return GAME_ERROR_FAILED; return GAME_ERROR_NO_ERROR; } GAME_ERROR CGameLibRetro::UnloadGame() { GAME_ERROR error = GAME_ERROR_FAILED; m_client.retro_unload_game(); CLibretroEnvironment::Get().CloseStreams(); error = GAME_ERROR_NO_ERROR; SAFE_DELETE_GAME_INFO(m_gameInfo); return error; } GAME_ERROR CGameLibRetro::GetGameTiming(game_system_timing& timing_info) { retro_system_av_info retro_info = { }; m_client.retro_get_system_av_info(&retro_info); timing_info.fps = retro_info.timing.fps; timing_info.sample_rate = retro_info.timing.sample_rate; // Report info to CLibretroEnvironment CLibretroEnvironment::Get().UpdateVideoGeometry(retro_info.geometry); return GAME_ERROR_NO_ERROR; } GAME_REGION CGameLibRetro::GetRegion() { return m_client.retro_get_region() == RETRO_REGION_NTSC ? GAME_REGION_NTSC : GAME_REGION_PAL; } GAME_ERROR CGameLibRetro::RunFrame() { // Trigger the frame time callback before running the core. uint64_t current = m_timer.microseconds(); int64_t delta = 0; if (m_frameTimeLast > 0) delta = current - m_frameTimeLast; m_frameTimeLast = current; m_clientBridge.FrameTime(delta); m_client.retro_run(); CLibretroEnvironment::Get().OnFrameEnd(); return GAME_ERROR_NO_ERROR; } GAME_ERROR CGameLibRetro::Reset() { m_client.retro_reset(); return GAME_ERROR_NO_ERROR; } /*! * \Brief Notify a core about audio being available for writing * * This enables finer-grained audio control by allowing the frontend to * control when audio data is sent to the frontend. * * When this function is called, audio data should be written to the * frontend via the AddStreamData() Game API callback in the same thread * that invoked AudioAvailable(). * * This extended interface is not recommended for use with emulators which * have highly synchronous audio. * * This function is not part of the Game API yet. It has been implemented * here in case a libretro core requires the extended audio interface. */ GAME_ERROR CGameLibRetro::AudioAvailable() { return m_clientBridge.AudioAvailable(); } GAME_ERROR CGameLibRetro::HwContextReset() { return m_clientBridge.HwContextReset(); } GAME_ERROR CGameLibRetro::HwContextDestroy() { return m_clientBridge.HwContextDestroy(); } bool CGameLibRetro::HasFeature(const std::string& controller_id, const std::string& feature_name) { return CButtonMapper::Get().GetLibretroIndex(controller_id, feature_name) >= 0; } game_input_topology* CGameLibRetro::GetTopology() { return CControllerTopology::GetInstance().GetTopology(); } void CGameLibRetro::FreeTopology(game_input_topology* topology) { CControllerTopology::FreeTopology(topology); } void CGameLibRetro::SetControllerLayouts(const std::vector& controllers) { CInputManager::Get().SetControllerLayouts(controllers); } bool CGameLibRetro::EnableKeyboard(bool enable, const std::string& controller_id) { bool bSuccess = false; if (enable) { bSuccess = CInputManager::Get().EnableKeyboard(controller_id); } else { CInputManager::Get().DisableKeyboard(); bSuccess = true; } return bSuccess; } bool CGameLibRetro::EnableMouse(bool enable, const std::string& controller_id) { bool bSuccess = false; if (enable) { bSuccess = CInputManager::Get().EnableMouse(controller_id); } else { CInputManager::Get().DisableMouse(); bSuccess = true; } return bSuccess; } bool CGameLibRetro::ConnectController(bool connect, const std::string& port_address, const std::string& controller_id) { std::string strPortAddress(port_address); std::string strController; if (connect) strController = controller_id; int port = CInputManager::Get().GetPortIndex(strPortAddress); if (port < 0) { esyslog("Failed to connect controller, invalid port address: %s", strPortAddress.c_str()); } else { libretro_device_t device = RETRO_DEVICE_NONE; if (connect) { device = CInputManager::Get().ConnectController(strPortAddress, controller_id); } else { CInputManager::Get().DisconnectController(strPortAddress); } // Get connection port override if specified int connectionPort = -1; if (CInputManager::Get().GetConnectionPortIndex(strPortAddress, connectionPort)) port = connectionPort; if (port >= 0) { dsyslog("Setting port \"%s\" (libretro port %d) to controller \"%s\" (libretro device ID %u)", strPortAddress.c_str(), port, strController.c_str(), device); m_client.retro_set_controller_port_device(port, device); } else { dsyslog("Ignoring port \"%s\" with controller \"%s\" (libretro device ID %u)", strPortAddress.c_str(), strController.c_str(), device); } return true; } return false; } bool CGameLibRetro::InputEvent(const game_input_event& event) { return CInputManager::Get().InputEvent(event); } size_t CGameLibRetro::SerializeSize() { return m_client.retro_serialize_size(); } GAME_ERROR CGameLibRetro::Serialize(uint8_t* data, size_t size) { if (data == nullptr) return GAME_ERROR_INVALID_PARAMETERS; bool result = m_client.retro_serialize(data, size); return result ? GAME_ERROR_NO_ERROR : GAME_ERROR_FAILED; } GAME_ERROR CGameLibRetro::Deserialize(const uint8_t* data, size_t size) { if (data == nullptr) return GAME_ERROR_INVALID_PARAMETERS; bool result = m_client.retro_unserialize(data, size); return result ? GAME_ERROR_NO_ERROR : GAME_ERROR_FAILED; } GAME_ERROR CGameLibRetro::CheatReset() { m_client.retro_cheat_reset(); return GAME_ERROR_NO_ERROR; } GAME_ERROR CGameLibRetro::GetMemory(GAME_MEMORY type, uint8_t*& data, size_t& size) { data = static_cast(m_client.retro_get_memory_data(type)); size = m_client.retro_get_memory_size(type); return GAME_ERROR_NO_ERROR; } GAME_ERROR CGameLibRetro::SetCheat(unsigned int index, bool enabled, const std::string& code) { m_client.retro_cheat_set(index, enabled, code.c_str()); return GAME_ERROR_NO_ERROR; } GAME_ERROR CGameLibRetro::RCGenerateHashFromFile(std::string& hash, unsigned int consoleID, const std::string& filePath) { if (!CCheevos::Get().GenerateHashFromFile(hash, consoleID, filePath)) return GAME_ERROR_FAILED; return GAME_ERROR_NO_ERROR; } GAME_ERROR CGameLibRetro::RCGetGameIDUrl(std::string& url, const std::string& hash) { if (!CCheevos::Get().GetGameIDUrl(url, hash)) return GAME_ERROR_FAILED; return GAME_ERROR_NO_ERROR; } GAME_ERROR CGameLibRetro::RCGetPatchFileUrl(std::string& url, const std::string& username, const std::string& token, unsigned int gameID) { if (!CCheevos::Get().GetPatchFileUrl(url, username, token, gameID)) return GAME_ERROR_FAILED; return GAME_ERROR_NO_ERROR; } GAME_ERROR CGameLibRetro::RCPostRichPresenceUrl(std::string& url, std::string& postData, const std::string& username, const std::string& token, unsigned int gameID, const std::string& richPresence) { if (!CCheevos::Get().PostRichPresenceUrl(url, postData, username, token, gameID, richPresence)) return GAME_ERROR_FAILED; return GAME_ERROR_NO_ERROR; } GAME_ERROR CGameLibRetro::RCEnableRichPresence(const std::string& script) { CCheevos::Get().EnableRichPresence(script); return GAME_ERROR_NO_ERROR; } GAME_ERROR CGameLibRetro::RCGetRichPresenceEvaluation(std::string& evaluation, unsigned int consoleID) { CCheevos::Get().EvaluateRichPresence(evaluation, consoleID); return GAME_ERROR_NO_ERROR; } GAME_ERROR CGameLibRetro::RCResetRuntime() { CCheevos::Get().ResetRuntime(); return GAME_ERROR_NO_ERROR; } ADDONCREATOR(CGameLibRetro) game.libretro-20.2.4-Nexus/src/client.h000066400000000000000000000101531445145641500176600ustar00rootroot00000000000000/* * Copyright (C) 2014-2021 Team Kodi (https://kodi.tv) * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSE.md for more information. */ #pragma once #include "libretro/ClientBridge.h" #include "libretro/LibretroDLL.h" #include "utils/Timer.h" #include namespace LIBRETRO { class CGameInfoLoader; } class ATTR_DLL_LOCAL CGameLibRetro : public kodi::addon::CAddonBase, public kodi::addon::CInstanceGame { public: CGameLibRetro(); ~CGameLibRetro() override; ADDON_STATUS Create() override; ADDON_STATUS SetSetting(const std::string& settingName, const kodi::addon::CSettingValue& settingValue) override; // --- Game operations --------------------------------------------------------- GAME_ERROR LoadGame(const std::string& url) override; GAME_ERROR LoadGameSpecial(SPECIAL_GAME_TYPE type, const std::vector& urls) override; GAME_ERROR LoadStandalone() override; GAME_ERROR UnloadGame() override; GAME_ERROR GetGameTiming(game_system_timing& timing_info) override; GAME_REGION GetRegion() override; bool RequiresGameLoop() override { return true; } GAME_ERROR RunFrame() override; GAME_ERROR Reset() override; // --- Hardware rendering operations ------------------------------------------- GAME_ERROR HwContextReset() override; GAME_ERROR HwContextDestroy() override; // --- Input operations -------------------------------------------------------- bool HasFeature(const std::string& controller_id, const std::string& feature_name) override; game_input_topology* GetTopology() override; void FreeTopology(game_input_topology* topology) override; void SetControllerLayouts(const std::vector& controllers) override; bool EnableKeyboard(bool enable, const std::string& controller_id) override; bool EnableMouse(bool enable, const std::string& controller_id) override; bool ConnectController(bool connect, const std::string& port_address, const std::string& controller_id) override; bool InputEvent(const game_input_event& event) override; // --- Serialization operations ------------------------------------------------ size_t SerializeSize() override; GAME_ERROR Serialize(uint8_t* data, size_t size) override; GAME_ERROR Deserialize(const uint8_t* data, size_t size) override; // --- Cheat operations -------------------------------------------------------- GAME_ERROR CheatReset() override; GAME_ERROR GetMemory(GAME_MEMORY type, uint8_t*& data, size_t& size) override; GAME_ERROR SetCheat(unsigned int index, bool enabled, const std::string& code) override; // --- RCheevos ---------------------------------------------------------------- GAME_ERROR RCGenerateHashFromFile(std::string& hash, unsigned int consoleID, const std::string& filePath) override; GAME_ERROR RCGetGameIDUrl(std::string& url, const std::string& hash) override; GAME_ERROR RCGetPatchFileUrl(std::string& url, const std::string& username, const std::string& token, unsigned int gameID) override; GAME_ERROR RCPostRichPresenceUrl(std::string& url, std::string& postData, const std::string& username, const std::string& token, unsigned int gameID, const std::string& richPresence) override; GAME_ERROR RCEnableRichPresence(const std::string& script) override; GAME_ERROR RCGetRichPresenceEvaluation(std::string& evaluation, unsigned int consoleID) override; GAME_ERROR RCResetRuntime() override; private: GAME_ERROR AudioAvailable(); LIBRETRO::Timer m_timer; LIBRETRO::CLibretroDLL m_client; LIBRETRO::CClientBridge m_clientBridge; std::vector m_gameInfo; bool m_supportsVFS = false; // TODO int64_t m_frameTimeLast = 0; }; game.libretro-20.2.4-Nexus/src/input/000077500000000000000000000000001445145641500173705ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/src/input/ButtonMapper.cpp000066400000000000000000000217541445145641500225250ustar00rootroot00000000000000/* * Copyright (C) 2015-2021 Team Kodi (https://kodi.tv) * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSE.md for more information. */ #include "ButtonMapper.h" #include "DefaultControllerTranslator.h" #include "DefaultKeyboardTranslator.h" #include "InputDefinitions.h" #include "LibretroDevice.h" #include "libretro/LibretroDLL.h" #include "libretro/LibretroEnvironment.h" #include "libretro/LibretroTranslator.h" #include "libretro-common/libretro.h" #include "log/Log.h" #include #include #include #define BUTTONMAP_XML "buttonmap.xml" #define BUTTONMAP_XML_VERSION 2 #define BUTTONMAP_XML_MIN_VERSION 2 using namespace LIBRETRO; CButtonMapper::CButtonMapper(void) : m_bLoadAttempted(false) { } CButtonMapper& CButtonMapper::Get(void) { static CButtonMapper _instance; return _instance; } bool CButtonMapper::LoadButtonMap(void) { bool bSuccess = false; m_devices.clear(); std::string strFilename = CLibretroEnvironment::Get().GetResourcePath(BUTTONMAP_XML); if (strFilename.empty()) { esyslog("Could not locate buttonmap \"%s\"", BUTTONMAP_XML); } else { dsyslog("Loading libretro buttonmap %s", strFilename.c_str()); TiXmlDocument buttonMapXml; if (!buttonMapXml.LoadFile(strFilename)) { esyslog("Failed to open file: %s (line %d)", buttonMapXml.ErrorDesc(), buttonMapXml.ErrorRow()); } else { TiXmlElement* pRootElement = buttonMapXml.RootElement(); bSuccess = Deserialize(pRootElement); } } return bSuccess; } libretro_device_t CButtonMapper::GetLibretroType(const std::string& strControllerId) { // Handle default controller unless it appears in buttonmap.xml if (strControllerId == DEFAULT_CONTROLLER_ID && !HasController(DEFAULT_CONTROLLER_ID)) return RETRO_DEVICE_ANALOG; // Handle default keyboard unless it appears in buttonmap.xml if (strControllerId == DEFAULT_KEYBOARD_ID && !HasController(DEFAULT_KEYBOARD_ID)) return RETRO_DEVICE_KEYBOARD; libretro_device_t deviceType = RETRO_DEVICE_NONE; // Check buttonmap for other controllers DeviceIt it = GetDevice(m_devices, strControllerId); if (it != m_devices.end()) deviceType = (*it)->Type(); return deviceType; } libretro_subclass_t CButtonMapper::GetSubclass(const std::string& strControllerId) { // Handle default controller unless it appears in buttonmap.xml if (strControllerId == DEFAULT_CONTROLLER_ID && !HasController(DEFAULT_CONTROLLER_ID)) return RETRO_SUBCLASS_NONE; // Handle default keyboard unless it appears in buttonmap.xml if (strControllerId == DEFAULT_KEYBOARD_ID && !HasController(DEFAULT_KEYBOARD_ID)) return RETRO_SUBCLASS_NONE; libretro_subclass_t subclass = RETRO_SUBCLASS_NONE; // Check buttonmap for other controllers DeviceIt it = GetDevice(m_devices, strControllerId); if (it != m_devices.end()) subclass = (*it)->Subclass(); return subclass; } int CButtonMapper::GetLibretroIndex(const std::string& strControllerId, const std::string& strFeatureName) { if (!strControllerId.empty() && !strFeatureName.empty()) { // Handle default controller unless it appears in buttonmap.xml if (strControllerId == DEFAULT_CONTROLLER_ID && !HasController(DEFAULT_CONTROLLER_ID)) return CDefaultControllerTranslator::GetLibretroIndex(strFeatureName); // Handle default keyboard unless it appears in buttonmap.xml if (strControllerId == DEFAULT_KEYBOARD_ID && !HasController(DEFAULT_KEYBOARD_ID)) return CDefaultKeyboardTranslator::GetLibretroIndex(strFeatureName); // Check buttonmap for other controllers std::string mapto = GetFeature(strControllerId, strFeatureName); if (!mapto.empty()) return LibretroTranslator::GetFeatureIndex(mapto); } return -1; } libretro_device_t CButtonMapper::GetLibretroDevice(const std::string& strControllerId, const std::string& strFeatureName) const { if (!strControllerId.empty() && !strFeatureName.empty()) { std::string mapto = GetFeature(strControllerId, strFeatureName); if (!mapto.empty()) return LibretroTranslator::GetLibretroDevice(mapto); } return RETRO_DEVICE_NONE; } int CButtonMapper::GetAxisID(const std::string& strControllerId, const std::string& strFeatureName) const { if (!strControllerId.empty() && !strFeatureName.empty()) { std::string axis = GetAxis(strControllerId, strFeatureName); if (!axis.empty()) return LibretroTranslator::GetAxisID(axis); } return -1; } std::string CButtonMapper::GetControllerFeature(const std::string& strControllerId, const std::string& strLibretroFeature) { std::string feature; if (!strControllerId.empty() && !strLibretroFeature.empty()) { // Handle default controller unless it appears in buttonmap.xml if (strControllerId == DEFAULT_CONTROLLER_ID && !HasController(DEFAULT_CONTROLLER_ID)) return CDefaultControllerTranslator::GetControllerFeature(strLibretroFeature); // No need to handle keyboard, keyboard input doesn't go from libretro to frontend DeviceIt it = GetDevice(m_devices, strControllerId); if (it != m_devices.end()) { const DevicePtr &device = *it; const FeatureMap& features = device->Features(); for (auto& featurePair : features) { const std::string& controllerFeature = featurePair.first; const FeatureMapItem& libretroFeature = featurePair.second; if (libretroFeature.feature == strLibretroFeature) { feature = controllerFeature; break; } } } } return feature; } bool CButtonMapper::HasController(const std::string& strControllerId) const { bool bFound = false; DeviceIt it = GetDevice(m_devices, strControllerId); if (it != m_devices.end()) bFound = true; return bFound; } std::string CButtonMapper::GetFeature(const std::string& strControllerId, const std::string& strFeatureName) const { std::string mapto; DeviceIt it = GetDevice(m_devices, strControllerId); if (it != m_devices.end()) { const DevicePtr &device = *it; const FeatureMap& features = device->Features(); for (auto& featurePair : features) { const std::string& controllerFeature = featurePair.first; const std::string& libretroFeature = featurePair.second.feature; if (controllerFeature == strFeatureName) { mapto = libretroFeature; break; } } } return mapto; } std::string CButtonMapper::GetAxis(const std::string& strControllerId, const std::string& strFeatureName) const { std::string axis; for (auto& device : m_devices) { if (device->ControllerID() == strControllerId) { const FeatureMap& features = device->Features(); for (auto& featurePair : features) { const std::string& controllerFeature = featurePair.first; const std::string& libretroAxis = featurePair.second.axis; if (controllerFeature == strFeatureName) { axis = libretroAxis; break; } } break; } } return axis; } bool CButtonMapper::Deserialize(TiXmlElement* pElement) { bool bSuccess = false; if (pElement == nullptr || pElement->ValueStr() != BUTTONMAP_XML_ROOT) { esyslog("Can't find root <%s> tag", BUTTONMAP_XML_ROOT); } else { // Assume v1 if unspecified unsigned int version = 1; const char* strVersion = pElement->Attribute(BUTTONMAP_XML_ATTR_VERSION); if (strVersion == nullptr) { esyslog("Buttonmap version required, expected version %u (min=%u)", BUTTONMAP_XML_VERSION, BUTTONMAP_XML_MIN_VERSION); } else { std::istringstream ss(strVersion); ss >> version; if (version < BUTTONMAP_XML_MIN_VERSION) { esyslog("Buttonmap with version %u too old, expected version %u (min=%u)", version, BUTTONMAP_XML_VERSION, BUTTONMAP_XML_MIN_VERSION); } else { dsyslog("Detected buttonmap version %u", version); } } if (version >= BUTTONMAP_XML_MIN_VERSION) { const TiXmlElement* pChild = pElement->FirstChildElement(BUTTONMAP_XML_ELM_CONTROLLER); if (!pChild) { esyslog("Can't find <%s> tag", BUTTONMAP_XML_ELM_CONTROLLER); } else { bSuccess = true; for ( ; pChild != nullptr; pChild = pChild->NextSiblingElement(BUTTONMAP_XML_ELM_CONTROLLER)) { DevicePtr device(std::make_shared()); if (!device->Deserialize(pChild, version)) { bSuccess = false; break; } m_devices.emplace_back(std::move(device)); } if (bSuccess) dsyslog("Loaded buttonmap at version %u", version); } } } return bSuccess; } CButtonMapper::DeviceIt CButtonMapper::GetDevice(const DeviceVector &devices, const std::string &controllerId) { return std::find_if(devices.begin(), devices.end(), [&controllerId](const DevicePtr &device) { return device->ControllerID() == controllerId; }); } game.libretro-20.2.4-Nexus/src/input/ButtonMapper.h000066400000000000000000000032511445145641500221620ustar00rootroot00000000000000/* * Copyright (C) 2015-2021 Team Kodi (https://kodi.tv) * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSE.md for more information. */ #pragma once #include "InputTypes.h" #include #include // TODO: Make this class generic and move XML-specific stuff to xml subfolder class TiXmlElement; namespace LIBRETRO { class CButtonMapper { private: CButtonMapper(void); public: static CButtonMapper& Get(void); bool LoadButtonMap(void); libretro_device_t GetLibretroType(const std::string& strControllerId); libretro_subclass_t GetSubclass(const std::string& strControllerId); int GetLibretroIndex(const std::string& strControllerId, const std::string& strFeatureName); libretro_device_t GetLibretroDevice(const std::string& strControllerId, const std::string& strFeatureName) const; int GetAxisID(const std::string& strControllerId, const std::string& strFeatureName) const; std::string GetControllerFeature(const std::string& strControllerId, const std::string& strLibretroFeature); private: bool HasController(const std::string& strControllerId) const; std::string GetFeature(const std::string& strControllerId, const std::string& strFeatureName) const; std::string GetAxis(const std::string& strControllerId, const std::string& strFeatureName) const; bool Deserialize(TiXmlElement* pElement); using DeviceVector = std::vector; using DeviceIt = DeviceVector::const_iterator; static DeviceIt GetDevice(const DeviceVector &devices, const std::string &controllerId); bool m_bLoadAttempted; DeviceVector m_devices; }; } game.libretro-20.2.4-Nexus/src/input/ControllerLayout.cpp000066400000000000000000000005171445145641500234200ustar00rootroot00000000000000/* * Copyright (C) 2018-2021 Team Kodi (https://kodi.tv) * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSE.md for more information. */ #include "ControllerLayout.h" using namespace LIBRETRO; CControllerLayout::CControllerLayout(const kodi::addon::GameControllerLayout& controller) : m_controller(controller) { } game.libretro-20.2.4-Nexus/src/input/ControllerLayout.h000066400000000000000000000011771445145641500230700ustar00rootroot00000000000000/* * Copyright (C) 2018-2021 Team Kodi (https://kodi.tv) * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSE.md for more information. */ #pragma once #include #include #include struct game_controller_layout; namespace LIBRETRO { class CControllerLayout { public: CControllerLayout(const kodi::addon::GameControllerLayout& controller); const std::string &ControllerID() const { return m_controller.controller_id; } bool ProvidesInput() const { return m_controller.provides_input; } private: kodi::addon::GameControllerLayout m_controller; }; } game.libretro-20.2.4-Nexus/src/input/ControllerTopology.cpp000066400000000000000000000454021445145641500237610ustar00rootroot00000000000000/* * Copyright (C) 2017-2021 Team Kodi (https://kodi.tv) * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSE.md for more information. */ #include "ControllerTopology.h" #include "InputDefinitions.h" #include "InputTranslator.h" #include "libretro/LibretroEnvironment.h" #include "log/Log.h" #include #include #include using namespace LIBRETRO; #define TOPOLOGY_XML "topology.xml" #define ADDRESS_SEPARATOR '/' //! @todo Remove me when these are added to the Game API #if !defined(KEYBOARD_PORT_ID) #define KEYBOARD_PORT_ID "keyboard" #endif #if !defined(MOUSE_PORT_ID) #define MOUSE_PORT_ID "mouse" #endif CControllerTopology& CControllerTopology::GetInstance() { static CControllerTopology instance; return instance; } bool CControllerTopology::LoadTopology() { bool bSuccess = false; Clear(); std::string strFilename = CLibretroEnvironment::Get().GetResourcePath(TOPOLOGY_XML); if (strFilename.empty()) { dsyslog("Could not locate controller topology \"%s\"", TOPOLOGY_XML); } else { dsyslog("Loading controller topology \"%s\"", strFilename.c_str()); TiXmlDocument topologyXml; if (topologyXml.LoadFile(strFilename)) { TiXmlElement* pRootElement = topologyXml.RootElement(); bSuccess = Deserialize(pRootElement); } else { esyslog("Failed to load controller topology: %s (line %d)", topologyXml.ErrorDesc(), topologyXml.ErrorRow()); } } return bSuccess; } void CControllerTopology::Clear() { m_ports.clear(); } game_input_topology *CControllerTopology::GetTopology() { if (!m_ports.empty()) { game_input_topology *topology = new game_input_topology; int unsigned portCount = 0; topology->ports = GetPorts(m_ports, portCount); topology->port_count = portCount; topology->player_limit = m_playerLimit; return topology; } return nullptr; } void CControllerTopology::FreeTopology(game_input_topology *topology) { if (topology != nullptr) FreePorts(topology->ports, topology->port_count); delete topology; } void CControllerTopology::FreePorts(game_input_port *ports, unsigned int portCount) { if (ports != nullptr) { for (unsigned int i = 0; i < portCount; i++) FreeControllers(ports[i].accepted_devices, ports[i].device_count); } delete[] ports; } unsigned int CControllerTopology::GetPlayerCount(const PortPtr& port) { unsigned int playerCount = 0; const ControllerPtr& controller = GetActiveController(port); if (controller) playerCount += GetPlayerCount(controller); return playerCount; } unsigned int CControllerTopology::GetPlayerCount(const ControllerPtr& controller) { unsigned int playerCount = 0; if (controller->bProvidesInput) playerCount++; for (const PortPtr &port : controller->ports) playerCount += GetPlayerCount(port); return playerCount; } int CControllerTopology::GetPortIndex(const std::string &address) const { int portIndex = -1; unsigned int playerCount = 0; if (m_ports.empty()) { // If topology is unknown, use the first port portIndex = 0; } else { for (const auto &port : m_ports) { if (port->type == GAME_PORT_CONTROLLER) { portIndex = GetPortIndex(port, address, playerCount); if (portIndex >= 0) break; } } } // Reset port index if it exceeds the player limit if (m_playerLimit >= 0 && portIndex >= m_playerLimit) portIndex = -1; return portIndex; } int CControllerTopology::GetPortIndex(const PortPtr &port, const std::string &portAddress, unsigned int &playerCount) { int portIndex = -1; std::string portId; std::string remainingAddress; SplitAddress(portAddress, portId, remainingAddress); if (port->portId == portId) { if (remainingAddress.empty()) { // Base case portIndex = playerCount; } else { const ControllerPtr& controller = GetActiveController(port); if (controller) { // Player count is incremented as we visit controllers recursively portIndex = GetPortIndex(controller, remainingAddress, playerCount); } } } else { // Player count wasn't incremented by visiting controllers for this port, // so calculate and increment it now playerCount += GetPlayerCount(port); } return portIndex; } int CControllerTopology::GetPortIndex(const ControllerPtr &controller, const std::string &portAddress, unsigned int &playerCount) { int portIndex = -1; std::string portControllerId; std::string remainingAddress; SplitAddress(portAddress, portControllerId, remainingAddress); if (controller->controllerId == portControllerId) { const auto &ports = controller->ports; for (const auto &port : ports) { portIndex = GetPortIndex(port, remainingAddress, playerCount); if (portIndex >= 0) break; } } if (controller->bProvidesInput) playerCount++; return portIndex; } bool CControllerTopology::GetConnectionPortIndex(const std::string &address, int &connectionPort) const { for (const auto &port : m_ports) { if (GetConnectionPortIndex(port, address, connectionPort)) return true; } return false; } bool CControllerTopology::GetConnectionPortIndex(const PortPtr &port, const std::string &portAddress, int &connectionPort) { std::string portId; std::string remainingAddress; SplitAddress(portAddress, portId, remainingAddress); if (port->portId == portId) { if (remainingAddress.empty()) { // Base case if (!port->connectionPort.empty()) { std::istringstream(port->connectionPort) >> connectionPort; return true; } else { return false; } } else { const ControllerPtr& controller = GetActiveController(port); if (controller) { if (GetConnectionPortIndex(controller, remainingAddress, connectionPort)) return true; } } } return false; } bool CControllerTopology::GetConnectionPortIndex(const ControllerPtr &controller, const std::string &portAddress, int &connectionPort) { std::string portControllerId; std::string remainingAddress; SplitAddress(portAddress, portControllerId, remainingAddress); if (controller->controllerId == portControllerId) { const auto &ports = controller->ports; for (const auto &childPort : ports) { if (GetConnectionPortIndex(childPort, remainingAddress, connectionPort)) return true; } } return false; } std::string CControllerTopology::GetAddress(unsigned int portIndex) const { std::string address; unsigned int playerCount = 0; if (m_ports.empty()) { return DEFAULT_PORT_ID; } else { for (const auto &port : m_ports) { if (port->type == GAME_PORT_CONTROLLER) { address = GetAddress(port, portIndex, playerCount); if (!address.empty()) break; } } } return address; } std::string CControllerTopology::GetAddress(const PortPtr &port, unsigned int portIndex, unsigned int &playerCount) { std::string address; if (portIndex == playerCount) { // Base case address = ADDRESS_SEPARATOR + port->portId; } else { const ControllerPtr& controller = GetActiveController(port); if (controller) { std::string controllerAddress = GetAddress(controller, portIndex, playerCount); if (!controllerAddress.empty()) address = ADDRESS_SEPARATOR + port->portId + controllerAddress; } } playerCount++; return address; } std::string CControllerTopology::GetAddress(const ControllerPtr &controller, unsigned int portIndex, unsigned int &playerCount) { std::string address; const auto &ports = controller->ports; for (const auto &port : ports) { std::string portAddress = GetAddress(port, portIndex, playerCount); if (!portAddress.empty()) { address = ADDRESS_SEPARATOR + controller->controllerId + portAddress; break; } } if (controller->bProvidesInput) playerCount++; return address; } bool CControllerTopology::SetDevice(GAME_PORT_TYPE portType, const std::string &controllerId) { for (const auto &port : m_ports) { if (port->type == portType) { const auto &accepts = port->accepts; auto it = std::find_if(accepts.begin(), accepts.end(), [&controllerId](const ControllerPtr &controller) { return controllerId == controller->controllerId; }); if (it != accepts.end()) { port->activeId = controllerId; return true; } } } return false; } void CControllerTopology::RemoveDevice(GAME_PORT_TYPE portType) { for (const auto &port : m_ports) { if (port->type == portType) port->activeId.clear(); } } bool CControllerTopology::SetController(const std::string &portAddress, const std::string &controllerId, bool bProvidesInput) { if (m_ports.empty()) { // No topology was specified, create one now m_ports.emplace_back(CreateDefaultPort(controllerId)); } for (const auto &port : m_ports) { if (port->type == GAME_PORT_CONTROLLER) { if (SetController(port, portAddress, controllerId, bProvidesInput)) return true; } } return false; } bool CControllerTopology::SetController(const PortPtr &port, const std::string &portAddress, const std::string &controllerId, bool bProvidesInput) { bool bSuccess = false; std::string portId; std::string remainingAddress; SplitAddress(portAddress, portId, remainingAddress); if (port->portId == portId) { const auto &accepts = port->accepts; if (remainingAddress.empty()) { // Base case auto it = std::find_if(accepts.begin(), accepts.end(), [&controllerId](const ControllerPtr &controller) { return controllerId == controller->controllerId; }); if (it != accepts.end()) { port->activeId = controllerId; (*it)->bProvidesInput = bProvidesInput; bSuccess = true; } } else { const ControllerPtr& controller = GetActiveController(port); if (controller) { if (SetController(controller, remainingAddress, controllerId, bProvidesInput)) bSuccess = true; } } } return bSuccess; } bool CControllerTopology::SetController(const ControllerPtr &controller, const std::string &portAddress, const std::string &controllerId, bool bProvidesInput) { std::string portControllerId; std::string remainingAddress; SplitAddress(portAddress, portControllerId, remainingAddress); if (controller->controllerId == portControllerId) { const auto &ports = controller->ports; for (const auto &port : ports) { if (SetController(port, remainingAddress, controllerId, bProvidesInput)) return true; } } return false; } void CControllerTopology::RemoveController(const std::string &portAddress) { for (const auto &port : m_ports) { if (port->type == GAME_PORT_CONTROLLER) RemoveController(port, portAddress); } } void CControllerTopology::RemoveController(const PortPtr &port, const std::string &portAddress) { std::string portId; std::string remainingAddress; SplitAddress(portAddress, portId, remainingAddress); if (port->portId == portId) { if (remainingAddress.empty()) { // Base case port->activeId.clear(); } else { const ControllerPtr& controller = GetActiveController(port); if (controller) RemoveController(controller, remainingAddress); } } } void CControllerTopology::RemoveController(const ControllerPtr &controller, const std::string &portAddress) { std::string portControllerId; std::string remainingAddress; SplitAddress(portAddress, portControllerId, remainingAddress); if (controller->controllerId == portControllerId) { const auto &ports = controller->ports; for (const auto &port : ports) RemoveController(port, remainingAddress); } } bool CControllerTopology::Deserialize(const TiXmlElement* pElement) { bool bSuccess = false; if (pElement == nullptr || pElement->ValueStr() != TOPOLOGY_XML_ROOT) { esyslog("Can't find root <%s> tag", TOPOLOGY_XML_ROOT); } else { const char* strPlayerLimit = pElement->Attribute(TOPOLOGY_XML_ATTR_PLAYER_LIMIT); if (strPlayerLimit != nullptr) { std::istringstream ssPlayerLimit(strPlayerLimit); ssPlayerLimit >> m_playerLimit; } const TiXmlElement* pChild = pElement->FirstChildElement(TOPOLOGY_XML_ELEM_PORT); if (pChild == nullptr) { esyslog("Can't find <%s> tag", TOPOLOGY_XML_ELEM_PORT); } else { bSuccess = true; for ( ; pChild != nullptr; pChild = pChild->NextSiblingElement(TOPOLOGY_XML_ELEM_PORT)) { PortPtr port = DeserializePort(pChild); if (!port) { bSuccess = false; break; } m_ports.emplace_back(std::move(port)); } if (bSuccess) dsyslog("Loaded controller topology with %u ports", m_ports.size()); } } return bSuccess; } CControllerTopology::PortPtr CControllerTopology::DeserializePort(const TiXmlElement* pElement) { PortPtr port; const char* strPortType = pElement->Attribute(TOPOLOGY_XML_ATTR_PORT_TYPE); GAME_PORT_TYPE portType = CInputTranslator::GetPortType(strPortType != nullptr ? strPortType : ""); //! @todo Remove this hack if (portType == GAME_PORT_UNKNOWN) portType = GAME_PORT_CONTROLLER; std::string portId; switch (portType) { case GAME_PORT_CONTROLLER: { const char* strPortId = pElement->Attribute(TOPOLOGY_XML_ATTR_PORT_ID); if (strPortId != nullptr) portId = strPortId; else esyslog("<%s> tag is missing attribute \"%s\", can't proceed without port ID", TOPOLOGY_XML_ELEM_PORT, TOPOLOGY_XML_ATTR_PORT_ID); break; } case GAME_PORT_KEYBOARD: { portId = KEYBOARD_PORT_ID; break; } case GAME_PORT_MOUSE: { portId = MOUSE_PORT_ID; break; } default: { esyslog("<%s> tag attribute \"%s\" has unknown value: \"%s\"", TOPOLOGY_XML_ELEM_PORT, TOPOLOGY_XML_ATTR_PORT_TYPE, strPortType != nullptr ? strPortType : ""); break; } } if (!portId.empty()) { const char* strConnectionPort = pElement->Attribute(TOPOLOGY_XML_ATTR_CONNECTION_PORT); std::string connectionPort = strConnectionPort != nullptr ? strConnectionPort : ""; const char* strForceConnected = pElement->Attribute(TOPOLOGY_XML_ATTR_FORCE_CONNECTED); bool forceConnected = (strForceConnected != nullptr && std::string(strForceConnected) == "true"); port.reset(new Port{ portType, portId, std::move(connectionPort), forceConnected }); const TiXmlElement* pChild = pElement->FirstChildElement(TOPOLOGY_XML_ELEM_ACCEPTS); if (pChild == nullptr) { dsyslog("<%s> tag with ID \"%s\" is missing <%s> node, port won't accept any controllers", TOPOLOGY_XML_ELEM_PORT, portId.c_str(), TOPOLOGY_XML_ELEM_ACCEPTS); } else { for ( ; pChild != nullptr; pChild = pChild->NextSiblingElement(TOPOLOGY_XML_ELEM_ACCEPTS)) { ControllerPtr controller = DeserializeController(pChild); if (!controller) { port.reset(); break; } port->accepts.emplace_back(std::move(controller)); } } } return port; } CControllerTopology::ControllerPtr CControllerTopology::DeserializeController(const TiXmlElement* pElement) { ControllerPtr controller; const char* strControllerId = pElement->Attribute(TOPOLOGY_XML_ATTR_CONTROLLER_ID); if (strControllerId == nullptr) { esyslog("<%s> tag is missing attribute \"%s\", can't proceed without controller ID", TOPOLOGY_XML_ELEM_ACCEPTS, TOPOLOGY_XML_ATTR_CONTROLLER_ID); } else { controller.reset(new Controller{ strControllerId }); const TiXmlElement* pChild = pElement->FirstChildElement(TOPOLOGY_XML_ELEM_PORT); for ( ; pChild != nullptr; pChild = pChild->NextSiblingElement(TOPOLOGY_XML_ELEM_PORT)) { PortPtr port = DeserializePort(pChild); if (!port) { controller.reset(); break; } controller->ports.emplace_back(std::move(port)); } } return controller; } game_input_port *CControllerTopology::GetPorts(const std::vector &portVec, unsigned int &portCount) { game_input_port *ports = nullptr; portCount = static_cast(portVec.size()); if (portCount > 0) { ports = new game_input_port[portCount]; for (unsigned int i = 0; i < portCount; i++) { ports[i].type = portVec[i]->type; ports[i].port_id = portVec[i]->portId.c_str(); ports[i].force_connected = portVec[i]->forceConnected; unsigned int deviceCount = 0; ports[i].accepted_devices = GetControllers(portVec[i]->accepts, deviceCount); ports[i].device_count = deviceCount; } } return ports; } game_input_device *CControllerTopology::GetControllers(const std::vector &controllerVec, unsigned int &deviceCount) { game_input_device *devices = nullptr; deviceCount = static_cast(controllerVec.size()); if (deviceCount > 0) { devices = new game_input_device[deviceCount]; for (unsigned int i = 0; i < deviceCount; i++) { devices[i].controller_id = controllerVec[i]->controllerId.c_str(); unsigned int portCount = 0; devices[i].available_ports = GetPorts(controllerVec[i]->ports, portCount); devices[i].port_count = portCount; } } return devices; } void CControllerTopology::FreeControllers(game_input_device *devices, unsigned int deviceCount) { for (unsigned int i = 0; i < deviceCount; i++) FreePorts(devices[i].available_ports, devices[i].port_count); delete[] devices; } CControllerTopology::PortPtr CControllerTopology::CreateDefaultPort(const std::string &acceptedController) { PortPtr port(new Port{GAME_PORT_CONTROLLER, DEFAULT_PORT_ID, {}, {}}); port->accepts.emplace_back(new Controller{ acceptedController }); return port; } const CControllerTopology::ControllerPtr& CControllerTopology::GetActiveController(const PortPtr& port) { if (!port->activeId.empty()) { const auto &accepts = port->accepts; auto it = std::find_if(accepts.begin(), accepts.end(), [&port](const ControllerPtr &controller) { return port->activeId == controller->controllerId; }); if (it != accepts.end()) return *it; } static const ControllerPtr empty; return empty; } void CControllerTopology::SplitAddress(const std::string &address, std::string &nodeId, std::string &remainingAddress) { // Start searching after leading / size_t pos = address.find(ADDRESS_SEPARATOR, 1); if (pos == std::string::npos) { // Skip leading / to extract node ID nodeId = address.substr(1); remainingAddress.clear(); } else { // Skip leading / to extract node ID nodeId = address.substr(1, pos - 1); remainingAddress = address.substr(pos); } } game.libretro-20.2.4-Nexus/src/input/ControllerTopology.h000066400000000000000000000075421445145641500234310ustar00rootroot00000000000000/* * Copyright (C) 2017-2021 Team Kodi (https://kodi.tv) * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSE.md for more information. */ #pragma once #include #include #include #include class TiXmlElement; namespace LIBRETRO { class CControllerTopology { public: CControllerTopology() = default; static CControllerTopology& GetInstance(); bool LoadTopology(); void Clear(); game_input_topology* GetTopology(); static void FreeTopology(game_input_topology *topology); static void FreePorts(game_input_port *ports, unsigned int portCount); int GetPortIndex(const std::string &address) const; bool GetConnectionPortIndex(const std::string &address, int &connectionPortId) const; std::string GetAddress(unsigned int portIndex) const; bool SetDevice(GAME_PORT_TYPE portType, const std::string &controllerId); void RemoveDevice(GAME_PORT_TYPE portType); bool SetController(const std::string &portAddress, const std::string &controllerId, bool bProvidesInput); void RemoveController(const std::string &portAddress); int PlayerLimit() const { return m_playerLimit; } private: struct Port; using PortPtr = std::unique_ptr; struct Controller; using ControllerPtr = std::unique_ptr; bool Deserialize(const TiXmlElement* pElement); PortPtr DeserializePort(const TiXmlElement* pElement); ControllerPtr DeserializeController(const TiXmlElement* pElement); static game_input_port *GetPorts(const std::vector &portVec, unsigned int &portCount); static game_input_device *GetControllers(const std::vector &controllerVec, unsigned int &deviceCount); static void FreeControllers(game_input_device *devices, unsigned int deviceCount); struct Port { GAME_PORT_TYPE type; std::string portId; std::string connectionPort; // Empty if no connection port is specified in topology.xml bool forceConnected = false; std::vector accepts; std::string activeId; // Empty if disconnected }; struct Controller { std::string controllerId; std::vector ports; bool bProvidesInput; }; static unsigned int GetPlayerCount(const PortPtr& port); static unsigned int GetPlayerCount(const ControllerPtr& controller); static int GetPortIndex(const PortPtr &port, const std::string &portAddress, unsigned int &playerCount); static int GetPortIndex(const ControllerPtr &controller, const std::string &portAddress, unsigned int &playerCount); static bool GetConnectionPortIndex(const PortPtr &port, const std::string &portAddress, int &connectionPort); static bool GetConnectionPortIndex(const ControllerPtr &controller, const std::string &portAddress, int &connectionPort); static std::string GetAddress(const PortPtr &port, unsigned int portIndex, unsigned int &playerCount); static std::string GetAddress(const ControllerPtr &controller, unsigned int portIndex, unsigned int &playerCount); static bool SetController(const PortPtr &port, const std::string &portAddress, const std::string &controllerId, bool bProvidesInput); static void RemoveController(const PortPtr &port, const std::string &portAddress); static bool SetController(const ControllerPtr &controller, const std::string &portAddress, const std::string &controllerId, bool bProvidesInput); static void RemoveController(const ControllerPtr &controller, const std::string &portAddress); static PortPtr CreateDefaultPort(const std::string &acceptedController); static const ControllerPtr& GetActiveController(const PortPtr& port); static void SplitAddress(const std::string &address, std::string &nodeId, std::string &remainingAddress); std::vector m_ports; int m_playerLimit = -1; }; } game.libretro-20.2.4-Nexus/src/input/DefaultControllerDefines.h000066400000000000000000000025461445145641500244760ustar00rootroot00000000000000/* * Copyright (C) 2017-2021 Team Kodi (https://kodi.tv) * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSE.md for more information. */ #pragma once #define DEFAULT_CONTROLLER_FEATURE_A "a" #define DEFAULT_CONTROLLER_FEATURE_B "b" #define DEFAULT_CONTROLLER_FEATURE_X "x" #define DEFAULT_CONTROLLER_FEATURE_Y "y" #define DEFAULT_CONTROLLER_FEATURE_START "start" #define DEFAULT_CONTROLLER_FEATURE_BACK "back" #define DEFAULT_CONTROLLER_FEATURE_UP "up" #define DEFAULT_CONTROLLER_FEATURE_DOWN "down" #define DEFAULT_CONTROLLER_FEATURE_RIGHT "right" #define DEFAULT_CONTROLLER_FEATURE_LEFT "left" #define DEFAULT_CONTROLLER_FEATURE_LEFT_BUMPER "leftbumber" #define DEFAULT_CONTROLLER_FEATURE_RIGHT_BUMPER "rightbumper" #define DEFAULT_CONTROLLER_FEATURE_LEFT_TRIGGER "lefttrigger" #define DEFAULT_CONTROLLER_FEATURE_RIGHT_TRIGGER "righttrigger" #define DEFAULT_CONTROLLER_FEATURE_LEFT_THUMB "leftthumb" #define DEFAULT_CONTROLLER_FEATURE_RIGHT_THUMB "rightthumb" #define DEFAULT_CONTROLLER_FEATURE_LEFT_STICK "leftstick" #define DEFAULT_CONTROLLER_FEATURE_RIGHT_STICK "rightstick" #define DEFAULT_CONTROLLER_FEATURE_LEFT_MOTOR "leftmotor" #define DEFAULT_CONTROLLER_FEATURE_RIGHT_MOTOR "rightmotor" // Guide button not used game.libretro-20.2.4-Nexus/src/input/DefaultControllerTranslator.cpp000066400000000000000000000110501445145641500255730ustar00rootroot00000000000000/* * Copyright (C) 2017-2021 Team Kodi (https://kodi.tv) * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSE.md for more information. */ #include "DefaultControllerTranslator.h" #include "DefaultControllerDefines.h" #include "libretro-common/libretro.h" using namespace LIBRETRO; int CDefaultControllerTranslator::GetLibretroIndex(const std::string &strFeatureName) { if (strFeatureName == DEFAULT_CONTROLLER_FEATURE_A) return RETRO_DEVICE_ID_JOYPAD_B; if (strFeatureName == DEFAULT_CONTROLLER_FEATURE_B) return RETRO_DEVICE_ID_JOYPAD_A; if (strFeatureName == DEFAULT_CONTROLLER_FEATURE_X) return RETRO_DEVICE_ID_JOYPAD_Y; if (strFeatureName == DEFAULT_CONTROLLER_FEATURE_Y) return RETRO_DEVICE_ID_JOYPAD_X; if (strFeatureName == DEFAULT_CONTROLLER_FEATURE_START) return RETRO_DEVICE_ID_JOYPAD_START; if (strFeatureName == DEFAULT_CONTROLLER_FEATURE_BACK) return RETRO_DEVICE_ID_JOYPAD_SELECT; if (strFeatureName == DEFAULT_CONTROLLER_FEATURE_LEFT_BUMPER) return RETRO_DEVICE_ID_JOYPAD_L; if (strFeatureName == DEFAULT_CONTROLLER_FEATURE_RIGHT_BUMPER) return RETRO_DEVICE_ID_JOYPAD_R; if (strFeatureName == DEFAULT_CONTROLLER_FEATURE_LEFT_THUMB) return RETRO_DEVICE_ID_JOYPAD_L3; if (strFeatureName == DEFAULT_CONTROLLER_FEATURE_RIGHT_THUMB) return RETRO_DEVICE_ID_JOYPAD_R3; if (strFeatureName == DEFAULT_CONTROLLER_FEATURE_UP) return RETRO_DEVICE_ID_JOYPAD_UP; if (strFeatureName == DEFAULT_CONTROLLER_FEATURE_DOWN) return RETRO_DEVICE_ID_JOYPAD_DOWN; if (strFeatureName == DEFAULT_CONTROLLER_FEATURE_RIGHT) return RETRO_DEVICE_ID_JOYPAD_RIGHT; if (strFeatureName == DEFAULT_CONTROLLER_FEATURE_LEFT) return RETRO_DEVICE_ID_JOYPAD_LEFT; if (strFeatureName == DEFAULT_CONTROLLER_FEATURE_LEFT_TRIGGER) return RETRO_DEVICE_ID_JOYPAD_L2; if (strFeatureName == DEFAULT_CONTROLLER_FEATURE_RIGHT_TRIGGER) return RETRO_DEVICE_ID_JOYPAD_R2; if (strFeatureName == DEFAULT_CONTROLLER_FEATURE_LEFT_STICK) return RETRO_DEVICE_INDEX_ANALOG_LEFT; if (strFeatureName == DEFAULT_CONTROLLER_FEATURE_RIGHT_STICK) return RETRO_DEVICE_INDEX_ANALOG_RIGHT; if (strFeatureName == DEFAULT_CONTROLLER_FEATURE_LEFT_MOTOR) return RETRO_RUMBLE_STRONG; if (strFeatureName == DEFAULT_CONTROLLER_FEATURE_RIGHT_MOTOR) return RETRO_RUMBLE_WEAK; return -1; } std::string CDefaultControllerTranslator::GetControllerFeature(const std::string &strLibretroFeature) { if (strLibretroFeature == "RETRO_DEVICE_ID_JOYPAD_A") return DEFAULT_CONTROLLER_FEATURE_B; if (strLibretroFeature == "RETRO_DEVICE_ID_JOYPAD_B") return DEFAULT_CONTROLLER_FEATURE_A; if (strLibretroFeature == "RETRO_DEVICE_ID_JOYPAD_X") return DEFAULT_CONTROLLER_FEATURE_Y; if (strLibretroFeature == "RETRO_DEVICE_ID_JOYPAD_Y") return DEFAULT_CONTROLLER_FEATURE_X; if (strLibretroFeature == "RETRO_DEVICE_ID_JOYPAD_START") return DEFAULT_CONTROLLER_FEATURE_START; if (strLibretroFeature == "RETRO_DEVICE_ID_JOYPAD_SELECT") return DEFAULT_CONTROLLER_FEATURE_BACK; if (strLibretroFeature == "RETRO_DEVICE_ID_JOYPAD_UP") return DEFAULT_CONTROLLER_FEATURE_UP; if (strLibretroFeature == "RETRO_DEVICE_ID_JOYPAD_DOWN") return DEFAULT_CONTROLLER_FEATURE_DOWN; if (strLibretroFeature == "RETRO_DEVICE_ID_JOYPAD_RIGHT") return DEFAULT_CONTROLLER_FEATURE_RIGHT; if (strLibretroFeature == "RETRO_DEVICE_ID_JOYPAD_LEFT") return DEFAULT_CONTROLLER_FEATURE_LEFT; if (strLibretroFeature == "RETRO_DEVICE_ID_JOYPAD_L") return DEFAULT_CONTROLLER_FEATURE_LEFT_BUMPER; if (strLibretroFeature == "RETRO_DEVICE_ID_JOYPAD_R") return DEFAULT_CONTROLLER_FEATURE_RIGHT_BUMPER; if (strLibretroFeature == "RETRO_DEVICE_ID_JOYPAD_L2") return DEFAULT_CONTROLLER_FEATURE_LEFT_TRIGGER; if (strLibretroFeature == "RETRO_DEVICE_ID_JOYPAD_R2") return DEFAULT_CONTROLLER_FEATURE_RIGHT_TRIGGER; if (strLibretroFeature == "RETRO_DEVICE_ID_JOYPAD_L3") return DEFAULT_CONTROLLER_FEATURE_LEFT_THUMB; if (strLibretroFeature == "RETRO_DEVICE_ID_JOYPAD_R3") return DEFAULT_CONTROLLER_FEATURE_RIGHT_THUMB; if (strLibretroFeature == "RETRO_DEVICE_INDEX_ANALOG_LEFT") return DEFAULT_CONTROLLER_FEATURE_LEFT_STICK; if (strLibretroFeature == "RETRO_DEVICE_INDEX_ANALOG_RIGHT") return DEFAULT_CONTROLLER_FEATURE_RIGHT_STICK; if (strLibretroFeature == "RETRO_RUMBLE_STRONG") return DEFAULT_CONTROLLER_FEATURE_LEFT_MOTOR; if (strLibretroFeature == "RETRO_RUMBLE_WEAK") return DEFAULT_CONTROLLER_FEATURE_RIGHT_MOTOR; return ""; } game.libretro-20.2.4-Nexus/src/input/DefaultControllerTranslator.h000066400000000000000000000015041445145641500252430ustar00rootroot00000000000000/* * Copyright (C) 2017-2021 Team Kodi (https://kodi.tv) * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSE.md for more information. */ #pragma once #include #define DEFAULT_CONTROLLER_ID "game.controller.default" namespace LIBRETRO { class CDefaultControllerTranslator { public: /*! * \brief Translate from Kodi feature name to libretro index */ static int GetLibretroIndex(const std::string &strFeatureName); /*! * \brief Translate from libretro feature (from libretro.h) to Kodi feature * * This is necessary because input doesn't just flow from Kodi to the * add-on. Rumble feedback going from the add-on to Kodi makes use of this * functionality. */ static std::string GetControllerFeature(const std::string &strLibretroFeature); }; } game.libretro-20.2.4-Nexus/src/input/DefaultKeyboardDefines.h000066400000000000000000000175221445145641500241130ustar00rootroot00000000000000/* * Copyright (C) 2018-2021 Team Kodi (https://kodi.tv) * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSE.md for more information. */ #pragma once #define DEFAULT_KEYBOARD_FEATURE_BACKSPACE "backspace" #define DEFAULT_KEYBOARD_FEATURE_TAB "tab" #define DEFAULT_KEYBOARD_FEATURE_CLEAR "clear" #define DEFAULT_KEYBOARD_FEATURE_ENTER "enter" #define DEFAULT_KEYBOARD_FEATURE_PAUSE "pause" #define DEFAULT_KEYBOARD_FEATURE_ESCAPE "escape" #define DEFAULT_KEYBOARD_FEATURE_SPACE "space" #define DEFAULT_KEYBOARD_FEATURE_EXCLAIM "exclaim" #define DEFAULT_KEYBOARD_FEATURE_DOUBLEQUOTE "doublequote" #define DEFAULT_KEYBOARD_FEATURE_HASH "hash" #define DEFAULT_KEYBOARD_FEATURE_DOLLAR "dollar" #define DEFAULT_KEYBOARD_FEATURE_AMPERSAND "ampersand" #define DEFAULT_KEYBOARD_FEATURE_QUOTE "quote" #define DEFAULT_KEYBOARD_FEATURE_LEFTPAREN "leftparen" #define DEFAULT_KEYBOARD_FEATURE_RIGHTPAREN "rightparen" #define DEFAULT_KEYBOARD_FEATURE_ASTERISK "asterisk" #define DEFAULT_KEYBOARD_FEATURE_PLUS "plus" #define DEFAULT_KEYBOARD_FEATURE_COMMA "comma" #define DEFAULT_KEYBOARD_FEATURE_MINUS "minus" #define DEFAULT_KEYBOARD_FEATURE_PERIOD "period" #define DEFAULT_KEYBOARD_FEATURE_SLASH "slash" #define DEFAULT_KEYBOARD_FEATURE_0 "0" #define DEFAULT_KEYBOARD_FEATURE_1 "1" #define DEFAULT_KEYBOARD_FEATURE_2 "2" #define DEFAULT_KEYBOARD_FEATURE_3 "3" #define DEFAULT_KEYBOARD_FEATURE_4 "4" #define DEFAULT_KEYBOARD_FEATURE_5 "5" #define DEFAULT_KEYBOARD_FEATURE_6 "6" #define DEFAULT_KEYBOARD_FEATURE_7 "7" #define DEFAULT_KEYBOARD_FEATURE_8 "8" #define DEFAULT_KEYBOARD_FEATURE_9 "9" #define DEFAULT_KEYBOARD_FEATURE_COLON "colon" #define DEFAULT_KEYBOARD_FEATURE_SEMICOLON "semicolon" #define DEFAULT_KEYBOARD_FEATURE_LESS "less" #define DEFAULT_KEYBOARD_FEATURE_EQUALS "equals" #define DEFAULT_KEYBOARD_FEATURE_GREATER "greater" #define DEFAULT_KEYBOARD_FEATURE_QUESTION "question" #define DEFAULT_KEYBOARD_FEATURE_AT "at" #define DEFAULT_KEYBOARD_FEATURE_LEFTBRACKET "leftbracket" #define DEFAULT_KEYBOARD_FEATURE_BACKSLASH "backslash" #define DEFAULT_KEYBOARD_FEATURE_RIGHTBRACKET "rightbracket" #define DEFAULT_KEYBOARD_FEATURE_CARET "caret" #define DEFAULT_KEYBOARD_FEATURE_UNDERSCORE "underscore" #define DEFAULT_KEYBOARD_FEATURE_GRAVE "grave" #define DEFAULT_KEYBOARD_FEATURE_A "a" #define DEFAULT_KEYBOARD_FEATURE_B "b" #define DEFAULT_KEYBOARD_FEATURE_C "c" #define DEFAULT_KEYBOARD_FEATURE_D "d" #define DEFAULT_KEYBOARD_FEATURE_E "e" #define DEFAULT_KEYBOARD_FEATURE_F "f" #define DEFAULT_KEYBOARD_FEATURE_G "g" #define DEFAULT_KEYBOARD_FEATURE_H "h" #define DEFAULT_KEYBOARD_FEATURE_I "i" #define DEFAULT_KEYBOARD_FEATURE_J "j" #define DEFAULT_KEYBOARD_FEATURE_K "k" #define DEFAULT_KEYBOARD_FEATURE_L "l" #define DEFAULT_KEYBOARD_FEATURE_M "m" #define DEFAULT_KEYBOARD_FEATURE_N "n" #define DEFAULT_KEYBOARD_FEATURE_O "o" #define DEFAULT_KEYBOARD_FEATURE_P "p" #define DEFAULT_KEYBOARD_FEATURE_Q "q" #define DEFAULT_KEYBOARD_FEATURE_R "r" #define DEFAULT_KEYBOARD_FEATURE_S "s" #define DEFAULT_KEYBOARD_FEATURE_T "t" #define DEFAULT_KEYBOARD_FEATURE_U "u" #define DEFAULT_KEYBOARD_FEATURE_V "v" #define DEFAULT_KEYBOARD_FEATURE_W "w" #define DEFAULT_KEYBOARD_FEATURE_X "x" #define DEFAULT_KEYBOARD_FEATURE_Y "y" #define DEFAULT_KEYBOARD_FEATURE_Z "z" #define DEFAULT_KEYBOARD_FEATURE_LEFTBRACE "leftbrace" #define DEFAULT_KEYBOARD_FEATURE_BAR "bar" #define DEFAULT_KEYBOARD_FEATURE_RIGHTBRACE "rightbrace" #define DEFAULT_KEYBOARD_FEATURE_TILDE "tilde" #define DEFAULT_KEYBOARD_FEATURE_DELETE "delete" #define DEFAULT_KEYBOARD_FEATURE_KP0 "kp0" #define DEFAULT_KEYBOARD_FEATURE_KP1 "kp1" #define DEFAULT_KEYBOARD_FEATURE_KP2 "kp2" #define DEFAULT_KEYBOARD_FEATURE_KP3 "kp3" #define DEFAULT_KEYBOARD_FEATURE_KP4 "kp4" #define DEFAULT_KEYBOARD_FEATURE_KP5 "kp5" #define DEFAULT_KEYBOARD_FEATURE_KP6 "kp6" #define DEFAULT_KEYBOARD_FEATURE_KP7 "kp7" #define DEFAULT_KEYBOARD_FEATURE_KP8 "kp8" #define DEFAULT_KEYBOARD_FEATURE_KP9 "kp9" #define DEFAULT_KEYBOARD_FEATURE_KPPERIOD "kpperiod" #define DEFAULT_KEYBOARD_FEATURE_KPDIVIDE "kpdivide" #define DEFAULT_KEYBOARD_FEATURE_KPMULTIPLY "kpmultiply" #define DEFAULT_KEYBOARD_FEATURE_KPMINUS "kpminus" #define DEFAULT_KEYBOARD_FEATURE_KPPLUS "kpplus" #define DEFAULT_KEYBOARD_FEATURE_KPENTER "kpenter" #define DEFAULT_KEYBOARD_FEATURE_KPEQUALS "kpequals" #define DEFAULT_KEYBOARD_FEATURE_UP "up" #define DEFAULT_KEYBOARD_FEATURE_DOWN "down" #define DEFAULT_KEYBOARD_FEATURE_RIGHT "right" #define DEFAULT_KEYBOARD_FEATURE_LEFT "left" #define DEFAULT_KEYBOARD_FEATURE_INSERT "insert" #define DEFAULT_KEYBOARD_FEATURE_HOME "home" #define DEFAULT_KEYBOARD_FEATURE_END "end" #define DEFAULT_KEYBOARD_FEATURE_PAGEUP "pageup" #define DEFAULT_KEYBOARD_FEATURE_PAGEDOWN "pagedown" #define DEFAULT_KEYBOARD_FEATURE_F1 "f1" #define DEFAULT_KEYBOARD_FEATURE_F2 "f2" #define DEFAULT_KEYBOARD_FEATURE_F3 "f3" #define DEFAULT_KEYBOARD_FEATURE_F4 "f4" #define DEFAULT_KEYBOARD_FEATURE_F5 "f5" #define DEFAULT_KEYBOARD_FEATURE_F6 "f6" #define DEFAULT_KEYBOARD_FEATURE_F7 "f7" #define DEFAULT_KEYBOARD_FEATURE_F8 "f8" #define DEFAULT_KEYBOARD_FEATURE_F9 "f9" #define DEFAULT_KEYBOARD_FEATURE_F10 "f10" #define DEFAULT_KEYBOARD_FEATURE_F11 "f11" #define DEFAULT_KEYBOARD_FEATURE_F12 "f12" #define DEFAULT_KEYBOARD_FEATURE_F13 "f13" #define DEFAULT_KEYBOARD_FEATURE_F14 "f14" #define DEFAULT_KEYBOARD_FEATURE_F15 "f15" #define DEFAULT_KEYBOARD_FEATURE_NUMLOCK "numlock" #define DEFAULT_KEYBOARD_FEATURE_CAPSLOCK "capslock" #define DEFAULT_KEYBOARD_FEATURE_SCROLLLOCK "scrolllock" #define DEFAULT_KEYBOARD_FEATURE_RIGHTSHIFT "rightshift" #define DEFAULT_KEYBOARD_FEATURE_LEFTSHIFT "leftshift" #define DEFAULT_KEYBOARD_FEATURE_RIGHTCTRL "rightctrl" #define DEFAULT_KEYBOARD_FEATURE_LEFTCTRL "leftctrl" #define DEFAULT_KEYBOARD_FEATURE_RIGHTALT "rightalt" #define DEFAULT_KEYBOARD_FEATURE_LEFTALT "leftalt" #define DEFAULT_KEYBOARD_FEATURE_RIGHTMETA "rightmeta" #define DEFAULT_KEYBOARD_FEATURE_LEFTMETA "leftmeta" #define DEFAULT_KEYBOARD_FEATURE_RIGHTSUPER "rightsuper" #define DEFAULT_KEYBOARD_FEATURE_LEFTSUPER "leftsuper" #define DEFAULT_KEYBOARD_FEATURE_MODE "mode" #define DEFAULT_KEYBOARD_FEATURE_COMPOSE "compose" #define DEFAULT_KEYBOARD_FEATURE_HELP "help" #define DEFAULT_KEYBOARD_FEATURE_PRINTSCREEN "printscreen" #define DEFAULT_KEYBOARD_FEATURE_SYSREQ "sysreq" #define DEFAULT_KEYBOARD_FEATURE_BREAK "break" #define DEFAULT_KEYBOARD_FEATURE_MENU "menu" #define DEFAULT_KEYBOARD_FEATURE_POWER "power" #define DEFAULT_KEYBOARD_FEATURE_EURO "euro" #define DEFAULT_KEYBOARD_FEATURE_UNDO "undo" game.libretro-20.2.4-Nexus/src/input/DefaultKeyboardTranslator.cpp000066400000000000000000000275121445145641500252220ustar00rootroot00000000000000/* * Copyright (C) 2018-2021 Team Kodi (https://kodi.tv) * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSE.md for more information. */ #include "DefaultKeyboardTranslator.h" #include "DefaultKeyboardDefines.h" #include "libretro-common/libretro.h" using namespace LIBRETRO; int CDefaultKeyboardTranslator::GetLibretroIndex(const std::string &strFeatureName) { if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_BACKSPACE) return RETROK_BACKSPACE; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_TAB) return RETROK_TAB; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_CLEAR) return RETROK_CLEAR; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_ENTER) return RETROK_RETURN; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_PAUSE) return RETROK_PAUSE; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_ESCAPE) return RETROK_ESCAPE; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_SPACE) return RETROK_SPACE; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_EXCLAIM) return RETROK_EXCLAIM; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_DOUBLEQUOTE) return RETROK_QUOTEDBL; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_HASH) return RETROK_HASH; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_DOLLAR) return RETROK_DOLLAR; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_AMPERSAND) return RETROK_AMPERSAND; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_QUOTE) return RETROK_QUOTE; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_LEFTPAREN) return RETROK_LEFTPAREN; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_RIGHTPAREN) return RETROK_RIGHTPAREN; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_ASTERISK) return RETROK_ASTERISK; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_PLUS) return RETROK_PLUS; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_COMMA) return RETROK_COMMA; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_MINUS) return RETROK_MINUS; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_PERIOD) return RETROK_PERIOD; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_SLASH) return RETROK_SLASH; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_0) return RETROK_0; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_1) return RETROK_1; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_2) return RETROK_2; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_3) return RETROK_3; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_4) return RETROK_4; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_5) return RETROK_5; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_6) return RETROK_6; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_7) return RETROK_7; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_8) return RETROK_8; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_9) return RETROK_9; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_COLON) return RETROK_COLON; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_SEMICOLON) return RETROK_SEMICOLON; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_LESS) return RETROK_LESS; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_EQUALS) return RETROK_EQUALS; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_GREATER) return RETROK_GREATER; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_QUESTION) return RETROK_QUESTION; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_AT) return RETROK_AT; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_LEFTBRACKET) return RETROK_LEFTBRACKET; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_BACKSLASH) return RETROK_BACKSLASH; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_RIGHTBRACKET) return RETROK_RIGHTBRACKET; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_CARET) return RETROK_CARET; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_UNDERSCORE) return RETROK_UNDERSCORE; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_GRAVE) return RETROK_BACKQUOTE; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_A) return RETROK_a; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_B) return RETROK_b; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_C) return RETROK_c; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_D) return RETROK_d; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_E) return RETROK_e; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_F) return RETROK_f; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_G) return RETROK_g; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_H) return RETROK_h; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_I) return RETROK_i; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_J) return RETROK_j; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_K) return RETROK_k; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_L) return RETROK_l; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_M) return RETROK_m; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_N) return RETROK_n; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_O) return RETROK_o; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_P) return RETROK_p; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_Q) return RETROK_q; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_R) return RETROK_r; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_S) return RETROK_s; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_T) return RETROK_t; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_U) return RETROK_u; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_V) return RETROK_v; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_W) return RETROK_w; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_X) return RETROK_x; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_Y) return RETROK_y; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_Z) return RETROK_z; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_LEFTBRACE) return RETROK_LEFTBRACE; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_BAR) return RETROK_BAR; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_RIGHTBRACE) return RETROK_RIGHTBRACE; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_TILDE) return RETROK_TILDE; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_DELETE) return RETROK_DELETE; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_KP0) return RETROK_KP0; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_KP1) return RETROK_KP1; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_KP2) return RETROK_KP2; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_KP3) return RETROK_KP3; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_KP4) return RETROK_KP4; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_KP5) return RETROK_KP5; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_KP6) return RETROK_KP6; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_KP7) return RETROK_KP7; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_KP8) return RETROK_KP8; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_KP9) return RETROK_KP9; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_KPPERIOD) return RETROK_KP_PERIOD; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_KPDIVIDE) return RETROK_KP_DIVIDE; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_KPMULTIPLY) return RETROK_KP_MULTIPLY; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_KPMINUS) return RETROK_KP_MINUS; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_KPPLUS) return RETROK_KP_PLUS; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_KPENTER) return RETROK_KP_ENTER; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_KPEQUALS) return RETROK_KP_EQUALS; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_UP) return RETROK_UP; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_DOWN) return RETROK_DOWN; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_RIGHT) return RETROK_RIGHT; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_LEFT) return RETROK_LEFT; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_INSERT) return RETROK_INSERT; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_HOME) return RETROK_HOME; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_END) return RETROK_END; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_PAGEUP) return RETROK_PAGEUP; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_PAGEDOWN) return RETROK_PAGEDOWN; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_F1) return RETROK_F1; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_F2) return RETROK_F2; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_F3) return RETROK_F3; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_F4) return RETROK_F4; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_F5) return RETROK_F5; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_F6) return RETROK_F6; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_F7) return RETROK_F7; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_F8) return RETROK_F8; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_F9) return RETROK_F9; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_F10) return RETROK_F10; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_F11) return RETROK_F11; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_F12) return RETROK_F12; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_F13) return RETROK_F13; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_F14) return RETROK_F14; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_F15) return RETROK_F15; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_NUMLOCK) return RETROK_NUMLOCK; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_CAPSLOCK) return RETROK_CAPSLOCK; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_SCROLLLOCK) return RETROK_SCROLLOCK; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_RIGHTSHIFT) return RETROK_RSHIFT; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_LEFTSHIFT) return RETROK_LSHIFT; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_RIGHTCTRL) return RETROK_RCTRL; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_LEFTCTRL) return RETROK_LCTRL; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_RIGHTALT) return RETROK_RALT; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_LEFTALT) return RETROK_LALT; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_RIGHTMETA) return RETROK_RMETA; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_LEFTMETA) return RETROK_LMETA; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_RIGHTSUPER) return RETROK_RSUPER; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_LEFTSUPER) return RETROK_LSUPER; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_MODE) return RETROK_MODE; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_COMPOSE) return RETROK_COMPOSE; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_HELP) return RETROK_HELP; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_PRINTSCREEN) return RETROK_PRINT; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_SYSREQ) return RETROK_SYSREQ; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_BREAK) return RETROK_BREAK; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_MENU) return RETROK_MENU; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_POWER) return RETROK_POWER; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_EURO) return RETROK_EURO; if (strFeatureName == DEFAULT_KEYBOARD_FEATURE_UNDO) return RETROK_UNDO; return -1; } game.libretro-20.2.4-Nexus/src/input/DefaultKeyboardTranslator.h000066400000000000000000000007301445145641500246600ustar00rootroot00000000000000/* * Copyright (C) 2018-2021 Team Kodi (https://kodi.tv) * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSE.md for more information. */ #pragma once #include #define DEFAULT_KEYBOARD_ID "game.controller.keyboard" namespace LIBRETRO { class CDefaultKeyboardTranslator { public: /*! * \brief Translate from Kodi feature name to libretro index */ static int GetLibretroIndex(const std::string &strFeatureName); }; } game.libretro-20.2.4-Nexus/src/input/InputDefinitions.h000066400000000000000000000025431445145641500230400ustar00rootroot00000000000000/* * Copyright (C) 2015-2021 Team Kodi (https://kodi.tv) * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSE.md for more information. */ #pragma once // Buttonmap XML #define BUTTONMAP_XML_ROOT "buttonmap" #define BUTTONMAP_XML_ELM_CONTROLLER "controller" #define BUTTONMAP_XML_ELM_FEATURE "feature" #define BUTTONMAP_XML_ATTR_VERSION "version" #define BUTTONMAP_XML_ATTR_CONTROLLER_ID "id" #define BUTTONMAP_XML_ATTR_DEVICE_TYPE "type" #define BUTTONMAP_XML_ATTR_DEVICE_SUBCLASS "subclass" #define BUTTONMAP_XML_ATTR_FEATURE_NAME "name" #define BUTTONMAP_XML_ATTR_FEATURE_MAPTO "mapto" #define BUTTONMAP_XML_ATTR_FEATURE_AXIS "axis" // Topology XML #define TOPOLOGY_XML_ROOT "logicaltopology" #define TOPOLOGY_XML_ELEM_PORT "port" #define TOPOLOGY_XML_ELEM_ACCEPTS "accepts" #define TOPOLOGY_XML_ATTR_PLAYER_LIMIT "playerlimit" #define TOPOLOGY_XML_ATTR_PORT_TYPE "type" #define TOPOLOGY_XML_ATTR_PORT_ID "id" #define TOPOLOGY_XML_ATTR_CONNECTION_PORT "connectionPort" #define TOPOLOGY_XML_ATTR_FORCE_CONNECTED "forceConnected" #define TOPOLOGY_XML_ATTR_CONTROLLER_ID "controller" // Game API strings #define PORT_TYPE_KEYBOARD "keyboard" #define PORT_TYPE_MOUSE "mouse" #define PORT_TYPE_CONTROLLER "controller" game.libretro-20.2.4-Nexus/src/input/InputManager.cpp000066400000000000000000000273511445145641500224760ustar00rootroot00000000000000/* * Copyright (C) 2015-2021 Team Kodi (https://kodi.tv) * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSE.md for more information. */ #include "InputManager.h" #include "ControllerTopology.h" #include "LibretroDevice.h" #include "LibretroDeviceInput.h" #include "libretro/ClientBridge.h" #include "libretro-common/libretro.h" #include "libretro/LibretroEnvironment.h" #include "libretro/LibretroTranslator.h" #include "log/Log.h" #include #include using namespace LIBRETRO; #define PORT_MAX_COUNT 32 // Large enough CInputManager& CInputManager::Get(void) { static CInputManager _instance; return _instance; } libretro_device_caps_t CInputManager::GetDeviceCaps(void) const { return 1 << RETRO_DEVICE_JOYPAD | 1 << RETRO_DEVICE_MOUSE | 1 << RETRO_DEVICE_KEYBOARD | 1 << RETRO_DEVICE_LIGHTGUN | 1 << RETRO_DEVICE_ANALOG | 1 << RETRO_DEVICE_POINTER; } void CInputManager::SetControllerLayouts(const std::vector& controllers) { m_controllerLayouts.clear(); for (const auto &controller : controllers) { m_controllerLayouts[controller.controller_id].reset(new CControllerLayout(controller)); } } bool CInputManager::EnableKeyboard(const std::string &controllerId) { bool bSuccess = false; if (!CControllerTopology::GetInstance().SetDevice(GAME_PORT_KEYBOARD, controllerId)) { esyslog("Error: Keyboard \"%s\" not supported", controllerId.c_str()); } else { DevicePtr device(new CLibretroDevice(controllerId)); m_keyboard = std::move(device); bSuccess = true; } return bSuccess; } void CInputManager::DisableKeyboard() { CControllerTopology::GetInstance().RemoveDevice(GAME_PORT_KEYBOARD); m_keyboard.reset(); } bool CInputManager::EnableMouse(const std::string &controllerId) { bool bSuccess = false; if (!CControllerTopology::GetInstance().SetDevice(GAME_PORT_MOUSE, controllerId)) { esyslog("Error: Mouse \"%s\" not supported", controllerId.c_str()); } else { DevicePtr device(new CLibretroDevice(controllerId)); m_mouse = std::move(device); bSuccess = true; } return bSuccess; } void CInputManager::DisableMouse() { CControllerTopology::GetInstance().RemoveDevice(GAME_PORT_MOUSE); m_mouse.reset(); } libretro_device_t CInputManager::ConnectController(const std::string &address, const std::string &controllerId) { unsigned int deviceType = RETRO_DEVICE_NONE; // Unmasked device type const int port = GetPortIndex(address); if (port < 0) { esyslog("Failed to connect controller, invalid port address: %s", address.c_str()); } else if (!controllerId.empty()) { auto it = m_controllerLayouts.find(controllerId); if (it != m_controllerLayouts.end()) { const CControllerLayout &controller = *it->second; const bool bProvidesInput = controller.ProvidesInput(); if (!CControllerTopology::GetInstance().SetController(address, controllerId, bProvidesInput)) { esyslog("Error: Controller port \"%s\" (libretro port %d) does not accept %s", address.c_str(), port, controllerId.c_str()); } else { DevicePtr device(new CLibretroDevice(controllerId)); if (device->Subclass() != RETRO_SUBCLASS_NONE) deviceType = RETRO_DEVICE_SUBCLASS(device->Type(), device->Subclass()); else deviceType = device->Type(); if (port >= static_cast(m_controllers.size())) m_controllers.resize(port + 1); m_controllers[port] = std::move(device); } } } return deviceType; } bool CInputManager::DisconnectController(const std::string &address) { bool bSuccess = false; const int port = GetPortIndex(address); if (port < 0) { esyslog("Failed to disconnect controller, invalid port address: %s", address.c_str()); } else { CControllerTopology::GetInstance().RemoveController(address); if (port < static_cast(m_controllers.size())) m_controllers[port].reset(); bSuccess = true; } return bSuccess; } int CInputManager::GetPortIndex(const std::string &address) const { return CControllerTopology::GetInstance().GetPortIndex(address); } bool CInputManager::GetConnectionPortIndex(const std::string &address, int& connectionPort) const { return CControllerTopology::GetInstance().GetConnectionPortIndex(address, connectionPort); } std::string CInputManager::GetAddress(unsigned int port) const { return CControllerTopology::GetInstance().GetAddress(port); } libretro_device_t CInputManager::GetDeviceType(const std::string &address) const { libretro_device_t deviceType = RETRO_DEVICE_NONE; int port = GetPortIndex(address); if (0 <= port && port < static_cast(m_controllers.size())) { const DevicePtr &device = m_controllers[port]; if (device) { libretro_subclass_t subclass = device->Subclass(); if (subclass == RETRO_SUBCLASS_NONE) deviceType = device->Type(); else deviceType = RETRO_DEVICE_SUBCLASS(device->Type(), subclass); } } return deviceType; } void CInputManager::ClosePorts(void) { m_controllers.clear(); } void CInputManager::EnableAnalogSensors(unsigned int port, bool bEnabled) { // TODO } bool CInputManager::InputEvent(const game_input_event& event) { std::string controllerId = event.controller_id != nullptr ? event.controller_id : ""; std::string feature = event.feature_name != nullptr ? event.feature_name : ""; if (controllerId.empty() || feature.empty()) return false; bool bHandled = false; switch (event.port_type) { case GAME_PORT_KEYBOARD: { if (m_keyboard) bHandled |= m_keyboard->Input().InputEvent(event); break; } case GAME_PORT_MOUSE: { if (m_mouse) bHandled = m_mouse->Input().InputEvent(event); break; } case GAME_PORT_CONTROLLER: { std::string portAddress = event.port_address != nullptr ? event.port_address : ""; int port = GetPortIndex(portAddress); if (0 <= port && port < PORT_MAX_COUNT) { // Resize devices if necessary if (port >= static_cast(m_controllers.size())) m_controllers.resize(port + 1); if (m_controllers[port]) bHandled = m_controllers[port]->Input().InputEvent(event); else esyslog("Event from controller %s sent to port with no device!", event.controller_id != nullptr ? event.controller_id : ""); } break; } default: break; } return bHandled; } void CInputManager::LogInputDescriptors(const retro_input_descriptor* descriptors) const { dsyslog("Libretro input bindings:"); dsyslog("------------------------------------------------------------"); for (const retro_input_descriptor* descriptor = descriptors; descriptor != nullptr && descriptor->description != nullptr && !std::string(descriptor->description).empty(); descriptor++) { std::string component = LibretroTranslator::GetComponentName(descriptor->device, descriptor->index, descriptor->id); if (component.empty()) { dsyslog("Port: %u, Device: %s, Feature: %s, Description: %s", descriptor->port, LibretroTranslator::GetDeviceName(descriptor->device), LibretroTranslator::GetFeatureName(descriptor->device, descriptor->index, descriptor->id), descriptor->description ? descriptor->description : ""); } else { dsyslog("Port: %u, Device: %s, Feature: %s, Component: %s, Description: %s", descriptor->port, LibretroTranslator::GetDeviceName(descriptor->device), LibretroTranslator::GetFeatureName(descriptor->device, descriptor->index, descriptor->id), component.c_str(), descriptor->description ? descriptor->description : ""); } } dsyslog("------------------------------------------------------------"); } std::string CInputManager::ControllerID(unsigned int port) const { std::string controllerId; if (port < m_controllers.size()) { const DevicePtr &device = m_controllers[port]; if (device) controllerId = device->ControllerID(); } return controllerId; } bool CInputManager::ButtonState(libretro_device_t device, unsigned int port, unsigned int buttonIndex) const { bool bState = false; switch (device) { case RETRO_DEVICE_KEYBOARD: { if (m_keyboard) bState = m_keyboard->Input().ButtonState(buttonIndex); break; } case RETRO_DEVICE_MOUSE: { if (m_mouse) { bState = m_mouse->Input().ButtonState(buttonIndex); break; } // Fall through to controller ports } default: { if (port < m_controllers.size()) { const DevicePtr &controller = m_controllers[port]; if (controller) bState = controller->Input().ButtonState(buttonIndex); } break; } } return bState; } float CInputManager::AnalogButtonState(unsigned int port, unsigned int buttonIndex) const { float state = 0.0f; if (port < m_controllers.size()) { const DevicePtr &device = m_controllers[port]; if (device) state = device->Input().AnalogButtonState(buttonIndex); } return state; } int CInputManager::DeltaX(libretro_device_t device, unsigned int port) { int deltaX = 0; if (device == RETRO_DEVICE_MOUSE && m_mouse) { deltaX = m_mouse->Input().RelativePointerDeltaX(); } else if (port < m_controllers.size()) { const DevicePtr &device = m_controllers[port]; if (device) deltaX = device->Input().RelativePointerDeltaX(); } return deltaX; } int CInputManager::DeltaY(libretro_device_t device, unsigned int port) { int deltaY = 0; if (device == RETRO_DEVICE_MOUSE && m_mouse) { deltaY = m_mouse->Input().RelativePointerDeltaY(); } else if (port < m_controllers.size()) { const DevicePtr &device = m_controllers[port]; if (device) deltaY = device->Input().RelativePointerDeltaY(); } return deltaY; } bool CInputManager::AnalogStickState(unsigned int port, unsigned int analogStickIndex, float& x, float& y) const { bool bSuccess = false; if (port < m_controllers.size()) { const DevicePtr &device = m_controllers[port]; if (device) bSuccess = device->Input().AnalogStickState(analogStickIndex, x, y); } return bSuccess; } bool CInputManager::AbsolutePointerState(unsigned int port, unsigned int pointerIndex, float& x, float& y) const { bool bSuccess = false; if (port < m_controllers.size()) { const DevicePtr &device = m_controllers[port]; if (device) bSuccess = device->Input().AbsolutePointerState(pointerIndex, x, y); } return bSuccess; } bool CInputManager::AccelerometerState(unsigned int port, float& x, float& y, float& z) const { bool bSuccess = false; if (port < m_controllers.size()) { const DevicePtr &device = m_controllers[port]; if (device) bSuccess = device->Input().AccelerometerState(x, y, z); } return bSuccess; } void CInputManager::SetControllerInfo(const retro_controller_info* info) { dsyslog("Libretro controller info:"); dsyslog("------------------------------------------------------------"); for (unsigned int i = 0; i < info->num_types; i++) { const retro_controller_description& type = info->types[i]; libretro_device_t baseType = type.id & RETRO_DEVICE_MASK; std::string description = type.desc ? type.desc : ""; if (type.id & ~RETRO_DEVICE_MASK) { libretro_subclass_t subclass = (type.id >> RETRO_DEVICE_TYPE_SHIFT) - 1; dsyslog("Device: %s, Subclass: %u, Description: \"%s\"", LibretroTranslator::GetDeviceName(baseType), subclass, description.c_str()); } else { dsyslog("Device: %s, Description: \"%s\"", LibretroTranslator::GetDeviceName(baseType), description.c_str()); } } dsyslog("------------------------------------------------------------"); } game.libretro-20.2.4-Nexus/src/input/InputManager.h000066400000000000000000000110161445145641500221320ustar00rootroot00000000000000/* * Copyright (C) 2015-2021 Team Kodi (https://kodi.tv) * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSE.md for more information. */ #pragma once #include "InputTypes.h" #include "ControllerLayout.h" #include "LibretroDevice.h" #include #include #include #include #include #include #include struct retro_controller_info; struct retro_input_descriptor; namespace LIBRETRO { typedef uint64_t libretro_device_caps_t; class CInputManager { private: CInputManager(void) { } public: static CInputManager& Get(void); /*! * \brief Get the devices supported by the libretro wrapper * * \return A bitmask of libretro devices that this class supports */ libretro_device_caps_t GetDeviceCaps(void) const; /*! * \brief */ void SetControllerLayouts(const std::vector& controllers); /*! * \brief Enable the keyboard * * \param controllerId The keyboard's controller ID * * \return True if keyboard was enabled, false otherwise */ bool EnableKeyboard(const std::string &controller); /*! * \brief Disable the keyboard and free any resources it held */ void DisableKeyboard(); /*! * \brief Enable mouse input * * \param controllerId The mouse's controller ID * * \return True if mouse input was enabled, false otherwise */ bool EnableMouse(const std::string &controllerId); /*! * \brief Disable the mouse and free any resources it held */ void DisableMouse(); /*! * \brief Called when a device has been connected to a port */ libretro_device_t ConnectController(const std::string &address, const std::string &controllerId); /*! * \brief Called when a device has been disconnected from a port */ bool DisconnectController(const std::string &address); /*! * \brief Get the port number associated with the specified address * * \return The port number, or -1 if the address has no port number */ int GetPortIndex(const std::string &address) const; /*! * \brief Get the port number that we should use when setting the * controller port * * \param address The port address * \param[out] connectionPort The port used to change connections, or * untouched if this function returns false * * \return True if a connection port was specified, false otherwise */ bool GetConnectionPortIndex(const std::string &address, int& connectionPort) const; std::string GetAddress(unsigned int port) const; /*! * \brief Get the libretro device abstraction for the device connected to * the specified address */ libretro_device_t GetDeviceType(const std::string &address) const; /*! * \brief Close all ports */ void ClosePorts(void); /*! * \brief Enable or disable the port's analog sensors (enabled by default) * * \param port The port * \param bEnabled True to enable port's analog sensors, false to disable */ void EnableAnalogSensors(unsigned int port, bool bEnabled); /*! * \brief Called when an input event has occurred */ bool InputEvent(const game_input_event& event); /*! * \brief Parse libretro input descriptors and output to the log */ void LogInputDescriptors(const retro_input_descriptor* descriptors) const; /*! * \brief Return the controller ID that the specified port is connected to */ std::string ControllerID(unsigned int port) const; bool ButtonState(libretro_device_t device, unsigned int port, unsigned int buttonIndex) const; float AnalogButtonState(unsigned int port, unsigned int buttonIndex) const; int DeltaX(libretro_device_t device, unsigned int port); int DeltaY(libretro_device_t device, unsigned int port); bool AnalogStickState(unsigned int port, unsigned int analogStickIndex, float& x, float& y) const; bool AbsolutePointerState(unsigned int port, unsigned int pointerIndex, float& x, float& y) const; bool AccelerometerState(unsigned int port, float& x, float& y, float& z) const; /*! * \brief Inform the frontend of controller info */ void SetControllerInfo(const retro_controller_info* info); private: DevicePtr m_keyboard; DevicePtr m_mouse; DeviceVector m_controllers; std::map> m_controllerLayouts; }; } game.libretro-20.2.4-Nexus/src/input/InputTranslator.cpp000066400000000000000000000010471445145641500232470ustar00rootroot00000000000000/* * Copyright (C) 2017-2021 Team Kodi (https://kodi.tv) * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSE.md for more information. */ #include "InputTranslator.h" #include "InputDefinitions.h" using namespace LIBRETRO; GAME_PORT_TYPE CInputTranslator::GetPortType(const std::string &portType) { if (portType == PORT_TYPE_KEYBOARD) return GAME_PORT_KEYBOARD; if (portType == PORT_TYPE_MOUSE) return GAME_PORT_MOUSE; if (portType == PORT_TYPE_CONTROLLER) return GAME_PORT_CONTROLLER; return GAME_PORT_UNKNOWN; } game.libretro-20.2.4-Nexus/src/input/InputTranslator.h000066400000000000000000000006331445145641500227140ustar00rootroot00000000000000/* * Copyright (C) 2017-2021 Team Kodi (https://kodi.tv) * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSE.md for more information. */ #pragma once #include namespace LIBRETRO { class CInputTranslator { public: /*! * \brief Translate from string to Game API enum */ static GAME_PORT_TYPE GetPortType(const std::string &portType); }; } game.libretro-20.2.4-Nexus/src/input/InputTypes.h000066400000000000000000000012201445145641500216600ustar00rootroot00000000000000/* * Copyright (C) 2017-2021 Team Kodi (https://kodi.tv) * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSE.md for more information. */ #pragma once #include #include #include #include // No subclass #define RETRO_SUBCLASS_NONE (-1) namespace LIBRETRO { class CLibretroDevice; using DevicePtr = std::shared_ptr; using DeviceVector = std::vector; using libretro_device_t = unsigned int; using libretro_subclass_t = int; struct FeatureMapItem { std::string feature; std::string axis; }; using FeatureMap = std::map; } game.libretro-20.2.4-Nexus/src/input/LibretroDevice.cpp000066400000000000000000000065321445145641500230040ustar00rootroot00000000000000/* * Copyright (C) 2015-2021 Team Kodi (https://kodi.tv) * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSE.md for more information. */ #include "LibretroDevice.h" #include "ButtonMapper.h" #include "InputDefinitions.h" #include "LibretroDeviceInput.h" #include "libretro/LibretroTranslator.h" #include "libretro-common/libretro.h" #include "log/Log.h" #include #include using namespace LIBRETRO; CLibretroDevice::CLibretroDevice() : m_type(RETRO_DEVICE_NONE) { } CLibretroDevice::CLibretroDevice(const std::string &controllerId) : m_controllerId(controllerId), m_type(CButtonMapper::Get().GetLibretroType(controllerId)), m_subclass(CButtonMapper::Get().GetSubclass(controllerId)), m_input(new CLibretroDeviceInput(controllerId)) { } CLibretroDevice::~CLibretroDevice() { } bool CLibretroDevice::Deserialize(const TiXmlElement* pElement, unsigned int buttonMapVersion) { if (!pElement) return false; // Controller ID const char* controllerId = pElement->Attribute(BUTTONMAP_XML_ATTR_CONTROLLER_ID); if (!controllerId) { esyslog("<%s> tag has no \"%s\" attribute", BUTTONMAP_XML_ELM_CONTROLLER, BUTTONMAP_XML_ATTR_CONTROLLER_ID); return false; } // Device type const char* type = pElement->Attribute(BUTTONMAP_XML_ATTR_DEVICE_TYPE); if (!type) { esyslog("<%s> tag has no \"%s\" attribute", BUTTONMAP_XML_ELM_CONTROLLER, BUTTONMAP_XML_ATTR_DEVICE_TYPE); return false; } m_controllerId = controllerId; m_type = LibretroTranslator::GetDeviceType(type); if (m_type == RETRO_DEVICE_NONE) { esyslog("<%s> tag has invalid device type: \"%s\"", BUTTONMAP_XML_ELM_CONTROLLER, type); return false; } // Device subclass const char* subclass = pElement->Attribute(BUTTONMAP_XML_ATTR_DEVICE_SUBCLASS); if (subclass) std::istringstream(subclass) >> m_subclass; else m_subclass = RETRO_SUBCLASS_NONE; // Features const TiXmlElement* pFeature = pElement->FirstChildElement(BUTTONMAP_XML_ELM_FEATURE); while (pFeature) { const char* name = pFeature->Attribute(BUTTONMAP_XML_ATTR_FEATURE_NAME); if (!name) { esyslog("<%s> tag has no \"%s\" attribute", BUTTONMAP_XML_ELM_FEATURE, BUTTONMAP_XML_ATTR_FEATURE_NAME); return false; } const char* mapto = pFeature->Attribute(BUTTONMAP_XML_ATTR_FEATURE_MAPTO); if (!mapto) { esyslog("<%s> tag has no \"%s\" attribute", BUTTONMAP_XML_ELM_FEATURE, BUTTONMAP_XML_ATTR_FEATURE_MAPTO); return false; } const char* axis = pFeature->Attribute(BUTTONMAP_XML_ATTR_FEATURE_AXIS); FeatureMapItem libretroFeature = { mapto }; // Ensure feature is valid if (LibretroTranslator::GetFeatureIndex(libretroFeature.feature) < 0) { esyslog("<%s> tag has invalid \"%s\" attribute: \"%s\"", BUTTONMAP_XML_ELM_FEATURE, BUTTONMAP_XML_ATTR_FEATURE_MAPTO, mapto); return false; } if (axis != nullptr) { libretroFeature.axis = axis; // Ensure axis is valid if (LibretroTranslator::GetAxisID(libretroFeature.axis) < 0) { esyslog("<%s> tag has invalid \"%s\" attribute: \"%s\"", BUTTONMAP_XML_ELM_FEATURE, BUTTONMAP_XML_ATTR_FEATURE_AXIS, axis); return false; } } m_featureMap[name] = std::move(libretroFeature); pFeature = pFeature->NextSiblingElement(BUTTONMAP_XML_ELM_FEATURE); } return true; } game.libretro-20.2.4-Nexus/src/input/LibretroDevice.h000066400000000000000000000023201445145641500224400ustar00rootroot00000000000000/* * Copyright (C) 2015-2021 Team Kodi (https://kodi.tv) * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSE.md for more information. */ #pragma once #include "InputTypes.h" #include #include #include #include #include class TiXmlElement; namespace LIBRETRO { class CLibretroDeviceInput; class CLibretroDevice { public: CLibretroDevice(); CLibretroDevice(const std::string &controller); ~CLibretroDevice(); const std::string& ControllerID(void) const { return m_controllerId; } libretro_device_t Type(void) const { return m_type; } libretro_subclass_t Subclass() const { return m_subclass; } const FeatureMap& Features(void) const { return m_featureMap; } CLibretroDeviceInput& Input() { return *m_input; } bool Deserialize(const TiXmlElement* pElement, unsigned int buttonMapVersion); private: std::string m_controllerId; libretro_device_t m_type; libretro_subclass_t m_subclass = RETRO_SUBCLASS_NONE; FeatureMap m_featureMap; std::unique_ptr m_input; }; } game.libretro-20.2.4-Nexus/src/input/LibretroDeviceInput.cpp000066400000000000000000000211041445145641500240140ustar00rootroot00000000000000/* * Copyright (C) 2015-2021 Team Kodi (https://kodi.tv) * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSE.md for more information. */ #include "LibretroDeviceInput.h" #include "LibretroDevice.h" #include "ButtonMapper.h" #include "libretro/ClientBridge.h" #include "libretro/LibretroEnvironment.h" #include "libretro/LibretroTranslator.h" #include "libretro-common/libretro.h" #include "log/Log.h" using namespace LIBRETRO; #define LIBRETRO_JOYPAD_BUTTON_COUNT 16 #define LIBRETRO_ANALOG_STICK_COUNT 2 #define LIBRETRO_ACCELEROMETER_COUNT 1 #define LIBRETRO_MOUSE_BUTTON_COUNT 11 #define LIBRETRO_LIGHTGUN_BUTTON_COUNT 17 #define LIBRETRO_RELATIVE_POINTER_COUNT 1 #define LIBRETRO_ABSOLUTE_POINTER_COUNT 10 #define ANALOG_DIGITAL_THRESHHOLD 0.5f CLibretroDeviceInput::CLibretroDeviceInput(const std::string &controllerId) { unsigned int type = CButtonMapper::Get().GetLibretroType(controllerId); switch (type) { case RETRO_DEVICE_JOYPAD: m_buttons.resize(LIBRETRO_JOYPAD_BUTTON_COUNT); break; case RETRO_DEVICE_MOUSE: m_buttons.resize(LIBRETRO_MOUSE_BUTTON_COUNT); m_relativePointers.resize(LIBRETRO_RELATIVE_POINTER_COUNT); break; case RETRO_DEVICE_LIGHTGUN: m_buttons.resize(LIBRETRO_LIGHTGUN_BUTTON_COUNT); m_relativePointers.resize(LIBRETRO_RELATIVE_POINTER_COUNT); break; case RETRO_DEVICE_ANALOG: m_buttons.resize(LIBRETRO_JOYPAD_BUTTON_COUNT); m_analogButtons.resize(LIBRETRO_JOYPAD_BUTTON_COUNT); m_analogSticks.resize(LIBRETRO_ANALOG_STICK_COUNT); break; case RETRO_DEVICE_POINTER: m_absolutePointers.resize(LIBRETRO_ABSOLUTE_POINTER_COUNT); break; case RETRO_DEVICE_KEYBOARD: m_buttons.resize(RETROK_LAST - 1); break; default: break; } m_accelerometers.resize(LIBRETRO_ACCELEROMETER_COUNT); } bool CLibretroDeviceInput::ButtonState(unsigned int buttonIndex) const { bool buttonState = false; if (buttonIndex < m_buttons.size()) buttonState = m_buttons[buttonIndex].pressed; return buttonState; } float CLibretroDeviceInput::AnalogButtonState(unsigned int buttonIndex) const { float axisState = 0.0f; if (buttonIndex < m_analogButtons.size()) axisState = m_analogButtons[buttonIndex].magnitude; return axisState; } bool CLibretroDeviceInput::AnalogStickState(unsigned int analogStickIndex, float& x, float& y) const { bool bSuccess = false; if (analogStickIndex < m_analogSticks.size()) { x = m_analogSticks[analogStickIndex].x; y = m_analogSticks[analogStickIndex].y; bSuccess = true; } return bSuccess; } bool CLibretroDeviceInput::AccelerometerState(float& x, float& y, float& z) const { bool bSuccess = false; if (!m_accelerometers.empty()) { x = m_accelerometers[0].x; y = m_accelerometers[0].y; z = m_accelerometers[0].z; bSuccess = true; } return bSuccess; } int CLibretroDeviceInput::RelativePointerDeltaX(void) { int deltaX = 0; if (!m_relativePointers.empty()) { std::unique_lock lock(m_relativePtrMutex); deltaX = m_relativePointers[0].x; m_relativePointers[0].x = 0; } return deltaX; } int CLibretroDeviceInput::RelativePointerDeltaY(void) { int deltaY = 0; if (!m_relativePointers.empty()) { std::unique_lock lock(m_relativePtrMutex); deltaY = m_relativePointers[0].y; m_relativePointers[0].y = 0; } return deltaY; } bool CLibretroDeviceInput::AbsolutePointerState(unsigned int pointerIndex, float& x, float& y) const { bool bSuccess = false; if (pointerIndex < m_absolutePointers.size() && m_absolutePointers[pointerIndex].pressed) { x = m_absolutePointers[pointerIndex].x; y = m_absolutePointers[pointerIndex].y; bSuccess = true; } return bSuccess; } bool CLibretroDeviceInput::InputEvent(const game_input_event& event) { const std::string strControllerId = event.controller_id ? event.controller_id : ""; const std::string strFeatureName = event.feature_name ? event.feature_name : ""; int index = CButtonMapper::Get().GetLibretroIndex(strControllerId, strFeatureName); if (index >= 0) { switch (event.type) { case GAME_INPUT_EVENT_DIGITAL_BUTTON: { if (index < (int)m_buttons.size()) m_buttons[index] = event.digital_button; if (index < static_cast(m_analogButtons.size())) m_analogButtons[index].magnitude = event.digital_button.pressed ? 1.0f : 0.0f; break; } case GAME_INPUT_EVENT_ANALOG_BUTTON: { if (index < static_cast(m_buttons.size())) m_buttons[index].pressed = (event.analog_button.magnitude >= ANALOG_DIGITAL_THRESHHOLD); if (index < static_cast(m_analogButtons.size())) m_analogButtons[index].magnitude = event.analog_button.magnitude; break; } case GAME_INPUT_EVENT_AXIS: { const int axisId = CButtonMapper::Get().GetAxisID(strControllerId, strFeatureName); if (axisId >= 0) { const libretro_device_t deviceType = CButtonMapper::Get().GetLibretroDevice(strControllerId, strFeatureName); switch (deviceType) { case RETRO_DEVICE_ANALOG: { if (index < static_cast(m_analogSticks.size())) { auto& analogStick = m_analogSticks[index]; switch (axisId) { case RETRO_DEVICE_ID_ANALOG_X: analogStick.x = event.axis.position; break; case RETRO_DEVICE_ID_ANALOG_Y: analogStick.y = event.axis.position; break; default: break; } } break; } case RETRO_DEVICE_POINTER: { if (index < static_cast(m_absolutePointers.size())) { auto& absPointer = m_absolutePointers[index]; switch (axisId) { case RETRO_DEVICE_ID_POINTER_X: absPointer.x = event.axis.position; break; case RETRO_DEVICE_ID_POINTER_Y: absPointer.y = event.axis.position; break; default: break; } } break; } default: break; } } break; } case GAME_INPUT_EVENT_ANALOG_STICK: if (index < (int)m_analogSticks.size()) m_analogSticks[index] = event.analog_stick; break; case GAME_INPUT_EVENT_ACCELEROMETER: if (index < (int)m_accelerometers.size()) m_accelerometers[index] = event.accelerometer; break; case GAME_INPUT_EVENT_KEY: { // Send keypress to libertro SendKeyEvent(strControllerId, strFeatureName, index, event.key); // Save keypress for polling if (static_cast(index) < m_buttons.size()) m_buttons[index] = event.digital_button; break; } case GAME_INPUT_EVENT_RELATIVE_POINTER: if (index < (int)m_relativePointers.size()) { std::unique_lock lock(m_relativePtrMutex); m_relativePointers[index].x += event.rel_pointer.x; m_relativePointers[index].y += event.rel_pointer.y; } break; case GAME_INPUT_EVENT_ABSOLUTE_POINTER: if (index < (int)m_absolutePointers.size()) m_absolutePointers[index] = event.abs_pointer; break; default: break; } return true; } return false; } void CLibretroDeviceInput::SendKeyEvent(const std::string &controllerId, const std::string &feature, unsigned int keyIndex, const game_key_event &keyEvent) { // Report key to client CClientBridge* clientBridge = CLibretroEnvironment::Get().GetClientBridge(); if (clientBridge) { const bool down = keyEvent.pressed; const retro_key keycode = static_cast(keyIndex); const uint32_t character = keyEvent.unicode; const retro_mod key_modifiers = LibretroTranslator::GetKeyModifiers(keyEvent.modifiers); std::string retroKey = LibretroTranslator::GetFeatureName(RETRO_DEVICE_KEYBOARD, 0, keycode); dsyslog("Controller \"%s\" key \"%s\" (%s) modifier 0x%08x: %s", controllerId.c_str(), feature.c_str(), retroKey.c_str(), keyEvent.modifiers, down ? "down" : "up"); clientBridge->KeyboardEvent(down, keycode, character, key_modifiers); } } game.libretro-20.2.4-Nexus/src/input/LibretroDeviceInput.h000066400000000000000000000031121445145641500234600ustar00rootroot00000000000000/* * Copyright (C) 2015-2021 Team Kodi (https://kodi.tv) * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSE.md for more information. */ #pragma once #include #include #include #include namespace LIBRETRO { typedef unsigned int libretro_device_t; class CLibretroDeviceInput { public: CLibretroDeviceInput(const std::string &controllerId); bool ButtonState(unsigned int buttonIndex) const; float AnalogButtonState(unsigned int buttonIndex) const; bool AnalogStickState(unsigned int analogStickIndex, float& x, float& y) const; bool AccelerometerState(float& x, float& y, float& z) const; int RelativePointerDeltaX(void); int RelativePointerDeltaY(void); bool AbsolutePointerState(unsigned int pointerIndex, float& x, float& y) const; bool InputEvent(const game_input_event& event); private: /*! * \brief Report key to client */ void SendKeyEvent(const std::string &controllerId, const std::string &feature, unsigned int keyIndex, const game_key_event &keyEvent); std::vector m_buttons; std::vector m_analogButtons; std::vector m_analogSticks; std::vector m_accelerometers; std::vector m_relativePointers; std::vector m_absolutePointers; std::mutex m_relativePtrMutex; }; } game.libretro-20.2.4-Nexus/src/libretro/000077500000000000000000000000001445145641500200535ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/src/libretro/ClientBridge.cpp000066400000000000000000000034521445145641500231160ustar00rootroot00000000000000/* * Copyright (C) 2014-2021 Team Kodi (https://kodi.tv) * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSE.md for more information. */ #include "ClientBridge.h" #include "libretro-common/libretro.h" // Causing errors with std::numeric_limits::max() #ifdef max #undef max #endif #include using namespace LIBRETRO; CClientBridge::CClientBridge() : m_retro_keyboard_event(nullptr), m_retro_hw_context_reset(nullptr), m_retro_hw_context_destroy(nullptr), m_retro_audio_set_state_callback(nullptr), m_retro_audio_callback(nullptr), m_retro_frame_time_callback(nullptr) { } GAME_ERROR CClientBridge::KeyboardEvent(bool down, unsigned keycode, uint32_t character, uint16_t key_modifiers) { if (!m_retro_keyboard_event) return GAME_ERROR_FAILED; m_retro_keyboard_event(down, keycode, character, key_modifiers); return GAME_ERROR_NO_ERROR; } GAME_ERROR CClientBridge::HwContextReset(void) { if (!m_retro_hw_context_reset) return GAME_ERROR_FAILED; m_retro_hw_context_reset(); return GAME_ERROR_NO_ERROR; } GAME_ERROR CClientBridge::HwContextDestroy(void) { if (!m_retro_hw_context_destroy) return GAME_ERROR_FAILED; m_retro_hw_context_destroy(); return GAME_ERROR_NO_ERROR; } GAME_ERROR CClientBridge::AudioEnable(bool enabled) { if (!m_retro_audio_set_state_callback) return GAME_ERROR_FAILED; m_retro_audio_set_state_callback(enabled); return GAME_ERROR_NO_ERROR; } GAME_ERROR CClientBridge::AudioAvailable(void) { if (!m_retro_audio_callback) return GAME_ERROR_FAILED; m_retro_audio_callback(); return GAME_ERROR_NO_ERROR; } GAME_ERROR CClientBridge::FrameTime(int64_t usec) { if (!m_retro_frame_time_callback) return GAME_ERROR_FAILED; m_retro_frame_time_callback(usec); return GAME_ERROR_NO_ERROR; } game.libretro-20.2.4-Nexus/src/libretro/ClientBridge.h000066400000000000000000000052701445145641500225630ustar00rootroot00000000000000/* * Copyright (C) 2014-2021 Team Kodi (https://kodi.tv) * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSE.md for more information. */ #pragma once #include struct retro_game_info; // from libretro.h typedef int64_t retro_usec_t; namespace LIBRETRO { /*! * Provide a bridge for client callbacks that we want to expose to the * frontend as part of the API. Colloquially, it fixes the callbacks of * callbacks shit. */ class CClientBridge { public: CClientBridge(); // These functions are invoked when the frontend calls the Kodi game API. // They do not have public methods exposed for them in the libretro API. // To maintain ABI, they were exposed through the generic EnvironmentCallback() // function in a tangled mess of callbacks for callbacks. GAME_ERROR KeyboardEvent(bool down, unsigned keycode, uint32_t character, uint16_t key_modifiers); GAME_ERROR HwContextReset(void); GAME_ERROR HwContextDestroy(void); GAME_ERROR AudioEnable(bool enabled); GAME_ERROR AudioAvailable(void); GAME_ERROR FrameTime(int64_t); typedef void (*KeyboardEventCallback)(bool down, unsigned keycode, uint32_t character, uint16_t key_modifiers); typedef void (*HwContextResetCallback)(void); typedef void (*HwContextDestroyCallback)(void); typedef void (*AudioEnableCallback)(bool enabled); typedef void (*AudioAvailableCallback)(void); typedef void (*FrameTimeCallback)(int64_t); void SetKeyboardEvent(KeyboardEventCallback callback) { m_retro_keyboard_event = callback; } void SetHwContextReset(HwContextResetCallback callback) { m_retro_hw_context_reset = callback; } void SetHwContextDestroy(HwContextDestroyCallback callback) { m_retro_hw_context_destroy = callback; } void SetAudioEnable(AudioEnableCallback callback) { m_retro_audio_set_state_callback = callback; } void SetAudioAvailable(AudioAvailableCallback callback) { m_retro_audio_callback = callback; } void SetFrameTime(FrameTimeCallback callback) { m_retro_frame_time_callback = callback; } private: // The bridge is accomplished by invoking the callback provided by libretro's // enironment callback. The frontend can only invoke the commands above // if the client provides these callbacks at run-time. KeyboardEventCallback m_retro_keyboard_event; HwContextResetCallback m_retro_hw_context_reset; HwContextDestroyCallback m_retro_hw_context_destroy; AudioEnableCallback m_retro_audio_set_state_callback; AudioAvailableCallback m_retro_audio_callback; FrameTimeCallback m_retro_frame_time_callback; }; } // namespace LIBRETRO game.libretro-20.2.4-Nexus/src/libretro/FrontendBridge.cpp000066400000000000000000000430201445145641500234520ustar00rootroot00000000000000/* * Copyright (C) 2014-2021 Team Kodi (https://kodi.tv) * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSE.md for more information. */ #include "FrontendBridge.h" #include "LibretroEnvironment.h" #include "LibretroTranslator.h" #include "input/ButtonMapper.h" #include "input/InputManager.h" #include "client.h" #include #include #include #include #include #include using namespace LIBRETRO; #define S16NE_FRAMESIZE 4 // int16 L + int16 R #define MAX_RUMBLE_STRENGTH 0xffff #ifndef CONSTRAIN // Credit: https://stackoverflow.com/questions/8941262/constrain-function-port-from-arduino #define CONSTRAIN(amt, low, high) ((amt) < (low) ? (low) : ((amt) > (high) ? (high) : (amt))) #endif void CFrontendBridge::LogFrontend(retro_log_level level, const char *fmt, ...) { ADDON_LOG xbmcLevel; switch (level) { case RETRO_LOG_DEBUG: xbmcLevel = ADDON_LOG_DEBUG; break; case RETRO_LOG_INFO: xbmcLevel = ADDON_LOG_INFO; break; case RETRO_LOG_WARN: xbmcLevel = ADDON_LOG_ERROR; break; case RETRO_LOG_ERROR: xbmcLevel = ADDON_LOG_ERROR; break; default: xbmcLevel = ADDON_LOG_ERROR; break; } char buffer[16384]; va_list args; va_start(args, fmt); vsprintf(buffer, fmt, args); va_end(args); kodi::Log(xbmcLevel, buffer); } void CFrontendBridge::VideoRefresh(const void* data, unsigned int width, unsigned int height, size_t pitch) { if (data == RETRO_HW_FRAME_BUFFER_VALID) { CLibretroEnvironment::Get().Video().RenderHwFrame(); } else if (data == nullptr) { // Libretro is sending a frame dupe command CLibretroEnvironment::Get().Video().DupeFrame(); } else { CLibretroEnvironment::Get().Video().AddFrame(static_cast(data), static_cast(pitch * height), width, height, CLibretroEnvironment::Get().GetVideoFormat(), CLibretroEnvironment::Get().GetVideoRotation()); } } void CFrontendBridge::AudioFrame(int16_t left, int16_t right) { CLibretroEnvironment::Get().Audio().AddFrame_S16NE(left, right); } size_t CFrontendBridge::AudioFrames(const int16_t* data, size_t frames) { CLibretroEnvironment::Get().Audio().AddFrames_S16NE(reinterpret_cast(data), static_cast(frames * S16NE_FRAMESIZE)); return frames; } void CFrontendBridge::InputPoll(void) { // Not needed } int16_t CFrontendBridge::InputState(unsigned int port, unsigned int device, unsigned int index, unsigned int id) { int16_t inputState = 0; // According to libretro.h, device should already be masked, but just in case device &= RETRO_DEVICE_MASK; switch (device) { case RETRO_DEVICE_JOYPAD: case RETRO_DEVICE_KEYBOARD: inputState = CInputManager::Get().ButtonState(device, port, id) ? 1 : 0; break; case RETRO_DEVICE_MOUSE: case RETRO_DEVICE_LIGHTGUN: static_assert(RETRO_DEVICE_ID_MOUSE_X == RETRO_DEVICE_ID_LIGHTGUN_X, "RETRO_DEVICE_ID_MOUSE_X != RETRO_DEVICE_ID_LIGHTGUN_X"); static_assert(RETRO_DEVICE_ID_MOUSE_Y == RETRO_DEVICE_ID_LIGHTGUN_Y, "RETRO_DEVICE_ID_MOUSE_Y != RETRO_DEVICE_ID_LIGHTGUN_Y"); switch (id) { case RETRO_DEVICE_ID_MOUSE_X: inputState = CInputManager::Get().DeltaX(device, port); break; case RETRO_DEVICE_ID_MOUSE_Y: inputState = CInputManager::Get().DeltaY(device, port); break; default: { inputState = CInputManager::Get().ButtonState(device, port, id) ? 1 : 0; break; } } break; case RETRO_DEVICE_ANALOG: { float value = 0.0f; // Axis value between -1 and 1 if (index == RETRO_DEVICE_INDEX_ANALOG_BUTTON) { value = CInputManager::Get().AnalogButtonState(port, id); } else { float x, y; if (CInputManager::Get().AnalogStickState(port, index, x, y)) { if (id == RETRO_DEVICE_ID_ANALOG_X) { value = x; } else if (id == RETRO_DEVICE_ID_ANALOG_Y) { value = -y; // y axis is inverted } } } const float normalized = (value + 1.0f) / 2.0f; const int clamped = std::max(0, std::min(0xffff, static_cast(normalized * 0xffff))); inputState = clamped - 0x8000; break; } case RETRO_DEVICE_POINTER: { float x, y; if (CInputManager::Get().AbsolutePointerState(port, index, x, y)) { if (id == RETRO_DEVICE_ID_POINTER_X) { inputState = (int)(x * 0x7fff); } else if (id == RETRO_DEVICE_ID_POINTER_Y) { inputState = (int)(y * 0x7fff); } else if (id == RETRO_DEVICE_ID_POINTER_PRESSED) { inputState = 1; } } break; } default: break; } return inputState; } uintptr_t CFrontendBridge::HwGetCurrentFramebuffer(void) { if (!CLibretroEnvironment::Get().GetAddon()) return 0; return CLibretroEnvironment::Get().Video().GetHwFramebuffer(); } retro_proc_address_t CFrontendBridge::HwGetProcAddress(const char *sym) { if (!CLibretroEnvironment::Get().GetAddon()) return nullptr; return CLibretroEnvironment::Get().GetAddon()->HwGetProcAddress(sym); } bool CFrontendBridge::RumbleSetState(unsigned int port, retro_rumble_effect effect, uint16_t strength) { if (!CLibretroEnvironment::Get().GetAddon()) return false; std::string controllerId = CInputManager::Get().ControllerID(port); std::string address = CInputManager::Get().GetAddress(port); std::string libretroMotor = LibretroTranslator::GetMotorName(effect); std::string featureName = CButtonMapper::Get().GetControllerFeature(controllerId, libretroMotor); float magnitude = static_cast(strength) / MAX_RUMBLE_STRENGTH; if (controllerId.empty() || address.empty() || featureName.empty()) return false; game_input_event eventStruct; eventStruct.type = GAME_INPUT_EVENT_MOTOR; eventStruct.controller_id = controllerId.c_str(); eventStruct.port_address = address.c_str(); eventStruct.port_type = GAME_PORT_CONTROLLER; eventStruct.feature_name = featureName.c_str(); eventStruct.motor.magnitude = CONSTRAIN(magnitude, 0.0f, 1.0f); CLibretroEnvironment::Get().GetAddon()->KodiInputEvent(eventStruct); return true; } void CFrontendBridge::LedSetState(int led, int state) { if (!CLibretroEnvironment::Get().GetAddon()) return; // TODO kodi::Log(ADDON_LOG_DEBUG, "LED: %d, state: %d", led, state); } bool CFrontendBridge::SensorSetState(unsigned port, retro_sensor_action action, unsigned rate) { const bool bEnabled = (action == RETRO_SENSOR_ACCELEROMETER_ENABLE); CInputManager::Get().EnableAnalogSensors(port, bEnabled); return true; } float CFrontendBridge::SensorGetInput(unsigned port, unsigned id) { float axisState = 0.0f; float x, y, z; if (CInputManager::Get().AccelerometerState(port, x, y, z)) { switch (id) { case RETRO_SENSOR_ACCELEROMETER_X: axisState = x; break; case RETRO_SENSOR_ACCELEROMETER_Y: axisState = y; break; case RETRO_SENSOR_ACCELEROMETER_Z: axisState = z; break; default: break; } } return axisState; } bool CFrontendBridge::StartCamera(void) { return false; // Not implemented } void CFrontendBridge::StopCamera(void) { // Not implemented } retro_time_t CFrontendBridge::PerfGetTimeUsec(void) { return 0; // Not implemented } retro_perf_tick_t CFrontendBridge::PerfGetCounter(void) { return 0; // Not implemented } uint64_t CFrontendBridge::PerfGetCpuFeatures(void) { return 0; // Not implemented } void CFrontendBridge::PerfLog(void) { // Not implemented } void CFrontendBridge::PerfRegister(retro_perf_counter *counter) { // Not implemented } void CFrontendBridge::PerfStart(retro_perf_counter *counter) { // Not implemented } void CFrontendBridge::PerfStop(retro_perf_counter *counter) { // Not implemented } bool CFrontendBridge::StartLocation(void) { return false; // Not implemented } void CFrontendBridge::StopLocation(void) { // Not implemented } bool CFrontendBridge::GetLocation(double *lat, double *lon, double *horiz_accuracy, double *vert_accuracy) { return false; // Not implemented } void CFrontendBridge::SetLocationInterval(unsigned interval_ms, unsigned interval_distance) { // Not implemented } void CFrontendBridge::LocationInitialized(void) { // Not implemented } void CFrontendBridge::LocationDeinitialized(void) { // Not implemented } const char *CFrontendBridge::GetPath(retro_vfs_file_handle *stream) { if (stream == nullptr) return ""; FileHandle *fileHandle = reinterpret_cast(stream); return fileHandle->path.c_str(); } retro_vfs_file_handle *CFrontendBridge::OpenFile(const char *path, unsigned mode, unsigned hints) { // Return NULL for error if (path == nullptr) return nullptr; std::unique_ptr fileHandle(new FileHandle{ path }); fileHandle->file.reset(new kodi::vfs::CFile); const bool bReadOnly = (mode == RETRO_VFS_FILE_ACCESS_READ); if (bReadOnly) { unsigned int flags = 0; // TODO //flags &= ADDDON_READ_TRUNCATED; if (hints & RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS) flags &= ADDON_READ_CACHED; if (!fileHandle->file->OpenFile(fileHandle->path, flags)) return nullptr; } else { // Discard contents and overwrite existing file unless "update existing" is // specified const bool bOverwrite = !(mode & RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING); if (!fileHandle->file->OpenFileForWrite(fileHandle->path, bOverwrite)) return nullptr; } // Return the opaque file handle on success return reinterpret_cast(fileHandle.release()); } int CFrontendBridge::CloseFile(retro_vfs_file_handle *stream) { // Return -1 on failure if (stream == nullptr) return -1; FileHandle *fileHandle = reinterpret_cast(stream); fileHandle->file->Close(); delete fileHandle; // Return 0 on success return 0; } int64_t CFrontendBridge::FileSize(retro_vfs_file_handle *stream) { // Return -1 for error if (stream == nullptr) return -1; FileHandle *fileHandle = reinterpret_cast(stream); const int64_t fileSize = fileHandle->file->GetLength(); if (fileSize < 0) return -1; // Return the file size on success return fileSize; } int64_t CFrontendBridge::GetPosition(retro_vfs_file_handle *stream) { // Return -1 for error if (stream == nullptr) return -1; FileHandle *fileHandle = reinterpret_cast(stream); const int64_t currentPosition = fileHandle->file->GetPosition(); if (currentPosition < 0) return -1; // Return the current read / write position for the file return currentPosition; } int64_t CFrontendBridge::Seek(retro_vfs_file_handle *stream, int64_t offset, int seek_position) { // Return -1 for error if (stream == nullptr) return -1; FileHandle *fileHandle = reinterpret_cast(stream); int whence = -1; switch (seek_position) { case RETRO_VFS_SEEK_POSITION_START: whence = SEEK_SET; break; case RETRO_VFS_SEEK_POSITION_CURRENT: whence = SEEK_CUR; break; case RETRO_VFS_SEEK_POSITION_END: whence = SEEK_END; break; default: break; } if (whence == -1) return -1; const int64_t newOffset = fileHandle->file->Seek(offset, whence); if (newOffset < 0) return -1; // Return the resulting offset location as measured in bytes from the // beginning of the file return newOffset; } int64_t CFrontendBridge::ReadFile(retro_vfs_file_handle *stream, void *s, uint64_t len) { // Return -1 for error if (stream == nullptr) return -1; FileHandle *fileHandle = reinterpret_cast(stream); const ssize_t bytesRead = fileHandle->file->Read(s, static_cast(len)); if (bytesRead < 0) return -1; // Return 0 if no bytes are available to read (end of file was reached) or // undetectable error occurred if (bytesRead == 0) return 0; // Return the number of bytes read return static_cast(bytesRead); } int64_t CFrontendBridge::WriteFile(retro_vfs_file_handle *stream, const void *s, uint64_t len) { // Return -1 for error if (stream == nullptr) return -1; FileHandle *fileHandle = reinterpret_cast(stream); const ssize_t bytesWritten = fileHandle->file->Write(s, static_cast(len)); if (bytesWritten < 0) return -1; // Return 0 if no bytes were written and no detectable error occurred if (bytesWritten == 0) return 0; // Return the number of bytes written return static_cast(bytesWritten); } int CFrontendBridge::FlushFile(retro_vfs_file_handle *stream) { // Return -1 on failure if (stream == nullptr) return -1; FileHandle *fileHandle = reinterpret_cast(stream); fileHandle->file->Flush(); // Return 0 on success return 0; } int CFrontendBridge::RemoveFile(const char *path) { // Return -1 on failure if (path == nullptr) return -1; if (!kodi::vfs::DeleteFile(path)) return -1; // Return 0 on success return 0; } int CFrontendBridge::RenameFile(const char *old_path, const char *new_path) { // Return -1 on failure if (old_path == nullptr || new_path == nullptr) return -1; if (!kodi::vfs::RenameFile(old_path, new_path)) return -1; // Return 0 on success return 0; } int64_t CFrontendBridge::Truncate(retro_vfs_file_handle *stream, int64_t length) { // Return -1 on error if (stream == nullptr) return -1; FileHandle *fileHandle = reinterpret_cast(stream); if (fileHandle->file->Truncate(length) < 0) return -1; // Return 0 on success return 0; } int CFrontendBridge::Stat(const char *path, int32_t *size) { int returnBitmask = 0; // Return mask with no flags set if the path was not valid if (path == nullptr) return returnBitmask; kodi::vfs::FileStatus statFile; if (!kodi::vfs::StatFile(path, statFile)) return returnBitmask; // Set bitmask flags returnBitmask &= RETRO_VFS_STAT_IS_VALID; if (statFile.GetIsDirectory()) returnBitmask &= RETRO_VFS_STAT_IS_DIRECTORY; if (statFile.GetIsCharacter()) returnBitmask &= RETRO_VFS_STAT_IS_CHARACTER_SPECIAL; // Set file size if (size != nullptr) { // What to return if size > 2 GiB? if (statFile.GetSize() <= std::numeric_limits::max()) *size = static_cast(statFile.GetSize()); } // Return bitmask on success return returnBitmask; } int CFrontendBridge::MakeDirectory(const char *dir) { // Return -1 on unknown failure if (dir == nullptr) return -1; if (!kodi::vfs::CreateDirectory(dir)) { // Return -2 if already exists if (kodi::vfs::DirectoryExists(dir)) return 2; return -1; } // Return 0 on success return 0; } retro_vfs_dir_handle *CFrontendBridge::OpenDirectory(const char *dir, bool include_hidden) { // Return NULL for error if (dir == nullptr) return nullptr; std::unique_ptr directoryHandle(new DirectoryHandle{ dir }); // Return the opaque dir handle return reinterpret_cast(directoryHandle.release()); } bool CFrontendBridge::ReadDirectory(retro_vfs_dir_handle *dirstream) { // What to return on error? if (dirstream == nullptr) return false; DirectoryHandle *directoryHandle = reinterpret_cast(dirstream); if (!directoryHandle->bOpen) { if (kodi::vfs::GetDirectory(directoryHandle->path, "", directoryHandle->items)) { directoryHandle->bOpen = true; // Simulate a read directoryHandle->currentPosition = directoryHandle->nextPosition = directoryHandle->items.begin(); // Simulate a dir entry pointer increment if (directoryHandle->nextPosition != directoryHandle->items.end()) ++directoryHandle->nextPosition; } } else { // Simulate a read directoryHandle->currentPosition = directoryHandle->nextPosition; // Simulate a dir entry pointer increment if (directoryHandle->nextPosition != directoryHandle->items.end()) ++directoryHandle->nextPosition; } // Return false if already on the last entry if (directoryHandle->currentPosition == directoryHandle->items.end()) return false; // Return true on success return true; } const char *CFrontendBridge::GetDirectoryName(retro_vfs_dir_handle *dirstream) { // Return NULL for error if (dirstream == nullptr) return nullptr; DirectoryHandle *directoryHandle = reinterpret_cast(dirstream); if (directoryHandle->currentPosition == directoryHandle->items.end()) return nullptr; // The returned string pointer must be valid until the next call to // ReadDirectory() or CloseDirectory() return directoryHandle->currentPosition->Label().c_str(); } bool CFrontendBridge::IsDirectory(retro_vfs_dir_handle *dirstream) { // Return false on error if (dirstream == nullptr) return false; DirectoryHandle *directoryHandle = reinterpret_cast(dirstream); if (directoryHandle->currentPosition == directoryHandle->items.end()) return false; return directoryHandle->currentPosition->IsFolder(); } int CFrontendBridge::CloseDirectory(retro_vfs_dir_handle *dirstream) { // Return -1 on failure if (dirstream == nullptr) return -1; DirectoryHandle *directoryHandle = reinterpret_cast(dirstream); delete directoryHandle; // Return 0 on success return 0; } game.libretro-20.2.4-Nexus/src/libretro/FrontendBridge.h000066400000000000000000000077661445145641500231400ustar00rootroot00000000000000/* * Copyright (C) 2014-2021 Team Kodi (https://kodi.tv) * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSE.md for more information. */ #pragma once #include "libretro-common/libretro.h" #include #include #include namespace kodi { namespace vfs { class CDirEntry; class CFile; } } namespace LIBRETRO { /*! * Provide a bridge for frontend callbacks given to the client. The bridging * function is a simple wrapper that invokes the callback in the frontend. * These functions are given to the libretro client in EnvironmentCallback(). */ class CFrontendBridge { public: // Forward to Kodi add-on API static void LogFrontend(retro_log_level level, const char *fmt, ...); // Forward to Kodi game API static void VideoRefresh(const void* data, unsigned int width, unsigned int height, size_t pitch); static void AudioFrame(int16_t left, int16_t right); static size_t AudioFrames(const int16_t* data, size_t frames); static void InputPoll(void); static int16_t InputState(unsigned int port, unsigned int device, unsigned int index, unsigned int id); static uintptr_t HwGetCurrentFramebuffer(void); static retro_proc_address_t HwGetProcAddress(const char *sym); static bool RumbleSetState(unsigned port, retro_rumble_effect effect, uint16_t strength); static void LedSetState(int led, int state); static bool SensorSetState(unsigned port, retro_sensor_action action, unsigned rate); static float SensorGetInput(unsigned port, unsigned id); static bool StartCamera(void); static void StopCamera(void); static retro_time_t PerfGetTimeUsec(void); static retro_perf_tick_t PerfGetCounter(void); static uint64_t PerfGetCpuFeatures(void); static void PerfLog(void); static void PerfRegister(retro_perf_counter *counter); static void PerfStart(retro_perf_counter *counter); static void PerfStop(retro_perf_counter *counter); static bool StartLocation(void); static void StopLocation(void); static bool GetLocation(double *lat, double *lon, double *horiz_accuracy, double *vert_accuracy); static void SetLocationInterval(unsigned interval_ms, unsigned interval_distance); static void LocationInitialized(void); static void LocationDeinitialized(void); // Forward to Kodi VFS API static const char *GetPath(retro_vfs_file_handle *stream); static retro_vfs_file_handle *OpenFile(const char *path, unsigned mode, unsigned hints); static int CloseFile(retro_vfs_file_handle *stream); static int64_t FileSize(retro_vfs_file_handle *stream); static int64_t GetPosition(retro_vfs_file_handle *stream); static int64_t Seek(retro_vfs_file_handle *stream, int64_t offset, int seek_position); static int64_t ReadFile(retro_vfs_file_handle *stream, void *s, uint64_t len); static int64_t WriteFile(retro_vfs_file_handle *stream, const void *s, uint64_t len); static int FlushFile(retro_vfs_file_handle *stream); static int RemoveFile(const char *path); static int RenameFile(const char *old_path, const char *new_path); static int64_t Truncate(retro_vfs_file_handle *stream, int64_t length); static int Stat(const char *path, int32_t *size); static int MakeDirectory(const char *dir); static retro_vfs_dir_handle *OpenDirectory(const char *dir, bool include_hidden); static bool ReadDirectory(retro_vfs_dir_handle *dirstream); static const char *GetDirectoryName(retro_vfs_dir_handle *dirstream); static bool IsDirectory(retro_vfs_dir_handle *dirstream); static int CloseDirectory(retro_vfs_dir_handle *dirstream); private: struct FileHandle { std::string path; std::unique_ptr file; }; struct DirectoryHandle { std::string path; bool bOpen = false; std::vector items; std::vector::const_iterator currentPosition; std::vector::const_iterator nextPosition; }; }; } // namespace LIBRETRO game.libretro-20.2.4-Nexus/src/libretro/LibretroDLL.cpp000066400000000000000000000103171445145641500226770ustar00rootroot00000000000000/* * Copyright (C) 2014-2021 Team Kodi (https://kodi.tv) * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSE.md for more information. */ #include "LibretroDLL.h" #include "log/Log.h" #include #include #include using namespace LIBRETRO; CLibretroDLL::CLibretroDLL(void) : retro_set_environment(nullptr), retro_set_video_refresh(nullptr), retro_set_audio_sample(nullptr), retro_set_audio_sample_batch(nullptr), retro_set_input_poll(nullptr), retro_set_input_state(nullptr), retro_init(nullptr), retro_deinit(nullptr), retro_api_version(nullptr), retro_get_system_info(nullptr), retro_get_system_av_info(nullptr), retro_set_controller_port_device(nullptr), retro_reset(nullptr), retro_run(nullptr), retro_serialize_size(nullptr), retro_serialize(nullptr), retro_unserialize(nullptr), retro_cheat_reset(nullptr), retro_cheat_set(nullptr), retro_load_game(nullptr), retro_load_game_special(nullptr), retro_unload_game(nullptr), retro_get_region(nullptr), retro_get_memory_data(nullptr), retro_get_memory_size(nullptr), m_libretroClient(nullptr) { } void CLibretroDLL::Unload(void) { if (m_libretroClient) { dlclose(m_libretroClient); m_libretroClient = nullptr; } m_strPath.clear(); } // Convert functionPtr to a string literal #define LIBRETRO_REGISTER_SYMBOL(dll, functionPtr) RegisterSymbol(dll, functionPtr, #functionPtr) // Register symbols from DLL, cast to type T and store in member variable template bool RegisterSymbol(void* dll, T& functionPtr, const char* strFunctionPtr) { return (functionPtr = (T)dlsym(dll, strFunctionPtr)) != nullptr; } bool CLibretroDLL::Load(const std::string& gameClientDllPath) { Unload(); m_strPath = gameClientDllPath; m_libretroClient = dlopen(m_strPath.c_str(), RTLD_LAZY); if (m_libretroClient == nullptr) { esyslog("Unable to load: %s", dlerror()); return false; } try { if (!LIBRETRO_REGISTER_SYMBOL(m_libretroClient, retro_set_environment)) throw false; if (!LIBRETRO_REGISTER_SYMBOL(m_libretroClient, retro_set_video_refresh)) throw false; if (!LIBRETRO_REGISTER_SYMBOL(m_libretroClient, retro_set_audio_sample)) throw false; if (!LIBRETRO_REGISTER_SYMBOL(m_libretroClient, retro_set_audio_sample_batch)) throw false; if (!LIBRETRO_REGISTER_SYMBOL(m_libretroClient, retro_set_input_poll)) throw false; if (!LIBRETRO_REGISTER_SYMBOL(m_libretroClient, retro_set_input_state)) throw false; if (!LIBRETRO_REGISTER_SYMBOL(m_libretroClient, retro_init)) throw false; if (!LIBRETRO_REGISTER_SYMBOL(m_libretroClient, retro_deinit)) throw false; if (!LIBRETRO_REGISTER_SYMBOL(m_libretroClient, retro_api_version)) throw false; if (!LIBRETRO_REGISTER_SYMBOL(m_libretroClient, retro_get_system_info)) throw false; if (!LIBRETRO_REGISTER_SYMBOL(m_libretroClient, retro_get_system_av_info)) throw false; if (!LIBRETRO_REGISTER_SYMBOL(m_libretroClient, retro_set_controller_port_device)) throw false; if (!LIBRETRO_REGISTER_SYMBOL(m_libretroClient, retro_reset)) throw false; if (!LIBRETRO_REGISTER_SYMBOL(m_libretroClient, retro_run)) throw false; if (!LIBRETRO_REGISTER_SYMBOL(m_libretroClient, retro_serialize_size)) throw false; if (!LIBRETRO_REGISTER_SYMBOL(m_libretroClient, retro_serialize)) throw false; if (!LIBRETRO_REGISTER_SYMBOL(m_libretroClient, retro_unserialize)) throw false; if (!LIBRETRO_REGISTER_SYMBOL(m_libretroClient, retro_cheat_reset)) throw false; if (!LIBRETRO_REGISTER_SYMBOL(m_libretroClient, retro_cheat_set)) throw false; if (!LIBRETRO_REGISTER_SYMBOL(m_libretroClient, retro_load_game)) throw false; if (!LIBRETRO_REGISTER_SYMBOL(m_libretroClient, retro_load_game_special)) throw false; if (!LIBRETRO_REGISTER_SYMBOL(m_libretroClient, retro_unload_game)) throw false; if (!LIBRETRO_REGISTER_SYMBOL(m_libretroClient, retro_get_region)) throw false; if (!LIBRETRO_REGISTER_SYMBOL(m_libretroClient, retro_get_memory_data)) throw false; if (!LIBRETRO_REGISTER_SYMBOL(m_libretroClient, retro_get_memory_size)) throw false; } catch (const bool& bSuccess) { esyslog("Unable to assign function: %s", dlerror()); return bSuccess; } return true; } game.libretro-20.2.4-Nexus/src/libretro/LibretroDLL.h000066400000000000000000000040521445145641500223430ustar00rootroot00000000000000/* * Copyright (C) 2014-2021 Team Kodi (https://kodi.tv) * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSE.md for more information. */ #pragma once #include "libretro-common/libretro.h" #include #include #include struct AddonProps_Game; namespace LIBRETRO { class CLibretroDLL { public: CLibretroDLL(void); ~CLibretroDLL(void) { Unload(); } void Unload(void); bool Load(const std::string& gameClientDllPath); const std::string& GetPath() const { return m_strPath; } void (*retro_set_environment)(retro_environment_t); void (*retro_set_video_refresh)(retro_video_refresh_t); void (*retro_set_audio_sample)(retro_audio_sample_t); void (*retro_set_audio_sample_batch)(retro_audio_sample_batch_t); void (*retro_set_input_poll)(retro_input_poll_t); void (*retro_set_input_state)(retro_input_state_t); void (*retro_init)(void); void (*retro_deinit)(void); unsigned (*retro_api_version)(void); void (*retro_get_system_info)(struct retro_system_info *info); void (*retro_get_system_av_info)(struct retro_system_av_info *info); void (*retro_set_controller_port_device)(unsigned port, unsigned device); void (*retro_reset)(void); void (*retro_run)(void); size_t (*retro_serialize_size)(void); bool (*retro_serialize)(void *data, size_t size); bool (*retro_unserialize)(const void *data, size_t size); void (*retro_cheat_reset)(void); void (*retro_cheat_set)(unsigned index, bool enabled, const char *code); bool (*retro_load_game)(const struct retro_game_info *game); bool (*retro_load_game_special)(unsigned game_type, const struct retro_game_info *info, size_t num_info); void (*retro_unload_game)(void); unsigned (*retro_get_region)(void); void* (*retro_get_memory_data)(unsigned id); size_t (*retro_get_memory_size)(unsigned id); private: void* m_libretroClient; std::string m_strPath; }; } // namespace LIBRETRO game.libretro-20.2.4-Nexus/src/libretro/LibretroDefines.h000066400000000000000000000012211445145641500233000ustar00rootroot00000000000000/* * Copyright (C) 2016-2021 Team Kodi (https://kodi.tv) * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSE.md for more information. */ #pragma once /*! * \brief The "system" directory of the frontend * * This directory can be used to store system specific content such as BIOSes, * configuration data, etc. */ #define LIBRETRO_SYSTEM_DIRECTORY_NAME "system" /*! * \brief The "save" directory of the frontend * * This directory can be used to store SRAM, memory cards, high scores, etc, * if the libretro core cannot use the regular memory interface * retro_get_memory_data(). */ #define LIBRETRO_SAVE_DIRECTORY_NAME "save" game.libretro-20.2.4-Nexus/src/libretro/LibretroEnvironment.cpp000066400000000000000000000440071445145641500245730ustar00rootroot00000000000000/* * Copyright (C) 2014-2021 Team Kodi (https://kodi.tv) * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSE.md for more information. */ #include "LibretroEnvironment.h" #include "ClientBridge.h" #include "FrontendBridge.h" #include "libretro-common/libretro.h" #include "LibretroDLL.h" #include "LibretroTranslator.h" #include "input/InputManager.h" #include "log/Log.h" #include "settings/Settings.h" #include "video/VideoGeometry.h" #include "client.h" #include using namespace LIBRETRO; namespace LIBRETRO { bool EnvCallback(unsigned cmd, void* data) { return CLibretroEnvironment::Get().EnvironmentCallback(cmd, data); } } CLibretroEnvironment::CLibretroEnvironment(void) : m_addon(nullptr), m_client(nullptr), m_clientBridge(nullptr), m_videoFormat(GAME_PIXEL_FORMAT_0RGB1555), // Default libretro format m_videoRotation(GAME_VIDEO_ROTATION_0) { } CLibretroEnvironment& CLibretroEnvironment::Get(void) { static CLibretroEnvironment _instance; return _instance; } void CLibretroEnvironment::Initialize(CGameLibRetro* addon, CLibretroDLL* client, CClientBridge* clientBridge) { m_addon = addon; m_client = client; m_clientBridge = clientBridge; m_videoStream.Initialize(m_addon); m_audioStream.Initialize(m_addon); m_settings.Initialize(m_addon); m_resources.Initialize(m_addon); // Install environment callback m_client->retro_set_environment(EnvCallback); // Install remaining callbacks m_client->retro_set_video_refresh(CFrontendBridge::VideoRefresh); m_client->retro_set_audio_sample(CFrontendBridge::AudioFrame); m_client->retro_set_audio_sample_batch(CFrontendBridge::AudioFrames); m_client->retro_set_input_poll(CFrontendBridge::InputPoll); m_client->retro_set_input_state(CFrontendBridge::InputState); } void CLibretroEnvironment::Deinitialize() { CloseStreams(); m_resources.Deinitialize(); m_settings.Deinitialize(); } void CLibretroEnvironment::CloseStreams() { m_videoStream.Deinitialize(); m_audioStream.Deinitialize(); } void CLibretroEnvironment::UpdateVideoGeometry(const retro_game_geometry &geometry) { CVideoGeometry videoGeometry(geometry); m_videoStream.SetGeometry(videoGeometry); } void CLibretroEnvironment::SetSetting(const std::string& name, const std::string& value) { m_settings.SetCurrentValue(name, value); } std::string CLibretroEnvironment::GetResourcePath(const char* relPath) { return m_resources.GetFullPath(relPath); } void CLibretroEnvironment::OnFrameEnd() { m_videoStream.OnFrameEnd(); } bool CLibretroEnvironment::EnvironmentCallback(unsigned int cmd, void *data) { if (!m_addon || !m_clientBridge) return false; switch (cmd) { case RETRO_ENVIRONMENT_SET_ROTATION: { unsigned* typedData = reinterpret_cast(data); if (typedData) m_videoRotation = LibretroTranslator::GetVideoRotation(*typedData); break; } case RETRO_ENVIRONMENT_GET_OVERSCAN: { bool* typedData = reinterpret_cast(data); if (typedData) *typedData = !CSettings::Get().CropOverscan(); break; } case RETRO_ENVIRONMENT_GET_CAN_DUPE: { bool* typedData = reinterpret_cast(data); if (typedData) *typedData = true; break; } case RETRO_ENVIRONMENT_SET_MESSAGE: { // Sets a message to be displayed. Generally not for trivial messages. const retro_message* typedData = reinterpret_cast(data); if (typedData) { const char* msg = typedData->msg; kodi::QueueFormattedNotification(QUEUE_INFO, msg); } break; } case RETRO_ENVIRONMENT_SHUTDOWN: { m_addon->CloseGame(); break; } case RETRO_ENVIRONMENT_SET_PERFORMANCE_LEVEL: { const unsigned* typedData = reinterpret_cast(data); // Removed from Game API (void)typedData; break; } case RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY: { const char** typedData = reinterpret_cast(data); if (typedData) { *typedData = m_resources.GetSystemDir(); } break; } case RETRO_ENVIRONMENT_SET_PIXEL_FORMAT: { const retro_pixel_format* typedData = reinterpret_cast(data); if (!typedData) return false; dsyslog("Setting libretro pixel format \"%s\"", LibretroTranslator::VideoFormatToString(*typedData)); m_videoFormat = LibretroTranslator::GetVideoFormat(*typedData); break; } case RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS: { const retro_input_descriptor* typedData = reinterpret_cast(data); if (typedData) CInputManager::Get().LogInputDescriptors(typedData); break; } case RETRO_ENVIRONMENT_SET_KEYBOARD_CALLBACK: { const retro_keyboard_callback* typedData = reinterpret_cast(data); if (typedData) { // Store callback from libretro client m_clientBridge->SetKeyboardEvent(typedData->callback); } break; } case RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE: { const retro_disk_control_callback *typedData = reinterpret_cast(data); if (typedData) { // Disk control interface not implemented return false; } break; } case RETRO_ENVIRONMENT_SET_HW_RENDER: { retro_hw_render_callback* typedData = reinterpret_cast(data); if (typedData) { // Translate struct and report hw info to frontend game_stream_hw_framebuffer_properties hw_info; hw_info.context_type = LibretroTranslator::GetHWContextType(typedData->context_type); hw_info.depth = typedData->depth; hw_info.stencil = typedData->stencil; hw_info.bottom_left_origin = typedData->bottom_left_origin; hw_info.version_major = typedData->version_major; hw_info.version_minor = typedData->version_minor; hw_info.cache_context = typedData->cache_context; hw_info.debug_context = typedData->debug_context; if (!m_videoStream.EnableHardwareRendering(hw_info)) return false; // Store callbacks from libretro client m_clientBridge->SetHwContextReset(typedData->context_reset); m_clientBridge->SetHwContextDestroy(typedData->context_destroy); // Expose frontend callbacks to libretro client typedData->get_current_framebuffer = CFrontendBridge::HwGetCurrentFramebuffer; typedData->get_proc_address = CFrontendBridge::HwGetProcAddress; } break; } case RETRO_ENVIRONMENT_GET_VARIABLE: { retro_variable* typedData = reinterpret_cast(data); if (typedData) { const char* strKey = typedData->key; if (strKey == nullptr) return false; typedData->value = m_settings.GetCurrentValue(strKey); // Assume libretro core is retrieving all variables at a time m_settings.SetUnchanged(); } break; } case RETRO_ENVIRONMENT_SET_VARIABLES: { const retro_variable* typedData = reinterpret_cast(data); if (typedData) { m_settings.SetAllSettings(typedData); } break; } case RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE: { bool* typedData = reinterpret_cast(data); if (typedData) { *typedData = m_settings.Changed(); } break; } case RETRO_ENVIRONMENT_SET_SUPPORT_NO_GAME: { const bool* typedData = reinterpret_cast(data); if (typedData) { const bool bSupportsNoGame = *typedData; if (bSupportsNoGame) kodi::Log(ADDON_LOG_DEBUG, "Libretro client supports loading with no game"); } break; } case RETRO_ENVIRONMENT_GET_LIBRETRO_PATH: { const char** typedData = reinterpret_cast(data); if (typedData) { *typedData = m_resources.GetContentDirectory(); } break; } case RETRO_ENVIRONMENT_SET_AUDIO_CALLBACK: { const retro_audio_callback *typedData = reinterpret_cast(data); if (typedData) { // Store callbacks from libretro client m_clientBridge->SetAudioAvailable(typedData->callback); m_clientBridge->SetAudioEnable(typedData->set_state); } break; } case RETRO_ENVIRONMENT_SET_FRAME_TIME_CALLBACK: { const retro_frame_time_callback *typedData = reinterpret_cast(data); if (typedData) { // Store callbacks from libretro client. m_clientBridge->SetFrameTime(typedData->callback); return false; } break; } case RETRO_ENVIRONMENT_GET_RUMBLE_INTERFACE: { retro_rumble_interface* typedData = reinterpret_cast(data); if (typedData) { // Expose callback to libretro core typedData->set_rumble_state = CFrontendBridge::RumbleSetState; } break; } case RETRO_ENVIRONMENT_GET_INPUT_DEVICE_CAPABILITIES: { uint64_t* typedData = reinterpret_cast(data); if (typedData) *typedData = CInputManager::Get().GetDeviceCaps(); break; } case RETRO_ENVIRONMENT_GET_SENSOR_INTERFACE: { retro_sensor_interface* typedData = reinterpret_cast(data); if (typedData) { // Expose callbacks to libretro core typedData->set_sensor_state = CFrontendBridge::SensorSetState; typedData->get_sensor_input = CFrontendBridge::SensorGetInput; } break; } case RETRO_ENVIRONMENT_GET_CAMERA_INTERFACE: { retro_camera_callback* typedData = reinterpret_cast(data); if (typedData) { // Camera interface not implemented return false; } break; } case RETRO_ENVIRONMENT_GET_LOG_INTERFACE: { retro_log_callback* typedData = reinterpret_cast(data); if (typedData) { // Expose callback to libretro core typedData->log = CFrontendBridge::LogFrontend; // libretro logging forwards to Kodi add-on log function } break; } case RETRO_ENVIRONMENT_GET_PERF_INTERFACE: { retro_perf_callback* typedData = reinterpret_cast(data); if (typedData) { // Expose callbacks to libretro core typedData->get_time_usec = CFrontendBridge::PerfGetTimeUsec; typedData->get_cpu_features = CFrontendBridge::PerfGetCpuFeatures; typedData->get_perf_counter = CFrontendBridge::PerfGetCounter; typedData->perf_register = CFrontendBridge::PerfRegister; typedData->perf_start = CFrontendBridge::PerfStart; typedData->perf_stop = CFrontendBridge::PerfStop; typedData->perf_log = CFrontendBridge::PerfLog; } break; } case RETRO_ENVIRONMENT_GET_LOCATION_INTERFACE: { retro_location_callback* typedData = reinterpret_cast(data); if (typedData) { // Expose callbacks to libretro core typedData->start = CFrontendBridge::StartLocation; typedData->stop = CFrontendBridge::StopLocation; typedData->get_position = CFrontendBridge::GetLocation; typedData->set_interval = CFrontendBridge::SetLocationInterval; typedData->initialized = CFrontendBridge::LocationInitialized; typedData->deinitialized = CFrontendBridge::LocationDeinitialized; } break; } case RETRO_ENVIRONMENT_GET_CONTENT_DIRECTORY: { const char** typedData = reinterpret_cast(data); if (typedData) { *typedData = m_resources.GetContentDirectory(); } break; } case RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY: { const char** typedData = reinterpret_cast(data); if (typedData) { *typedData = m_resources.GetSaveDirectory(); } break; } case RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO: { const retro_system_av_info* typedData = reinterpret_cast(data); if (!typedData) return false; CVideoGeometry videoGeometry(typedData->geometry); m_videoStream.SetGeometry(videoGeometry); //! @todo Reopen streams if geometry changes //! @todo Report updating timing info to frontend const double fps = typedData->timing.fps; const double sampleRate = typedData->timing.sample_rate; break; } case RETRO_ENVIRONMENT_SET_PROC_ADDRESS_CALLBACK: { const retro_get_proc_address_interface* typedData = reinterpret_cast(data); if (typedData) { // get_proc_address() interface not implemented return false; } break; } case RETRO_ENVIRONMENT_SET_SUBSYSTEM_INFO: { const retro_subsystem_info* typedData = reinterpret_cast(data); if (typedData) { // Not implemented return false; } break; } case RETRO_ENVIRONMENT_SET_CONTROLLER_INFO: { const retro_controller_info* typedData = reinterpret_cast(data); if (typedData) { CInputManager::Get().SetControllerInfo(typedData); } break; } case RETRO_ENVIRONMENT_SET_MEMORY_MAPS: { const retro_memory_map* typedData = reinterpret_cast(data); if (typedData) m_mmap.Initialize(*typedData); break; } case RETRO_ENVIRONMENT_SET_GEOMETRY: { const retro_game_geometry* typedData = reinterpret_cast(data); if (typedData) { // Not implemented return false; } break; } case RETRO_ENVIRONMENT_GET_USERNAME: { const char** typedData = reinterpret_cast(data); if (typedData) { // Not implemented return false; } break; } case RETRO_ENVIRONMENT_GET_LANGUAGE: { unsigned int* typedData = reinterpret_cast(data); if (typedData) { // Not implemented return false; } break; } case RETRO_ENVIRONMENT_GET_CURRENT_SOFTWARE_FRAMEBUFFER: { retro_framebuffer* typedData = reinterpret_cast(data); if (typedData) { // Get framebuffer params from core const unsigned int accessFlags = typedData->access_flags; const unsigned int width = typedData->width; const unsigned int height = typedData->height; // Reading framebuffers not supported if (accessFlags & RETRO_MEMORY_ACCESS_READ) return false; game_stream_sw_framebuffer_buffer framebuffer{}; if (!m_videoStream.GetSwFramebuffer(width, height, m_videoFormat, framebuffer)) return false; // Report framebuffer info to frontend typedData->data = framebuffer.data; typedData->pitch = framebuffer.size / height; typedData->format = LibretroTranslator::GetLibretroVideoFormat(framebuffer.format); typedData->memory_flags = 0; } break; } case RETRO_ENVIRONMENT_SET_HW_SHARED_CONTEXT: { // Not implemented return false; } case RETRO_ENVIRONMENT_GET_VFS_INTERFACE: { const uint32_t supported_vfs_version = 3; retro_vfs_interface_info* typedData = reinterpret_cast(data); if (typedData) { if (typedData->required_interface_version <= supported_vfs_version) { static retro_vfs_interface vfsInterface = { CFrontendBridge::GetPath, CFrontendBridge::OpenFile, CFrontendBridge::CloseFile, CFrontendBridge::FileSize, CFrontendBridge::GetPosition, CFrontendBridge::Seek, CFrontendBridge::ReadFile, CFrontendBridge::WriteFile, CFrontendBridge::FlushFile, CFrontendBridge::RemoveFile, CFrontendBridge::RenameFile, CFrontendBridge::Truncate, CFrontendBridge::Stat, CFrontendBridge::MakeDirectory, CFrontendBridge::OpenDirectory, CFrontendBridge::ReadDirectory, CFrontendBridge::GetDirectoryName, CFrontendBridge::IsDirectory, CFrontendBridge::CloseDirectory, }; typedData->required_interface_version = supported_vfs_version; typedData->iface = &vfsInterface; } } break; } case RETRO_ENVIRONMENT_GET_LED_INTERFACE: { retro_led_interface* typedData = reinterpret_cast(data); if (typedData) { // Expose callback to libretro core typedData->set_led_state = CFrontendBridge::LedSetState; } break; } case RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE: { const retro_hw_render_interface* typedData = reinterpret_cast(data); if (typedData) { // Not implemented return false; } break; } case RETRO_ENVIRONMENT_SET_SUPPORT_ACHIEVEMENTS: { const bool* typedData = reinterpret_cast(data); if (typedData) { // Not implemented return false; } break; } case RETRO_ENVIRONMENT_SET_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE: { const retro_hw_render_context_negotiation_interface* typedData = reinterpret_cast(data); if (typedData) { // Not implemented return false; } break; } case RETRO_ENVIRONMENT_SET_SERIALIZATION_QUIRKS: { const retro_hw_render_context_negotiation_interface* typedData = reinterpret_cast(data); if (typedData) { // Not implemented return false; } break; } default: return false; } return true; } const CMemoryMap& CLibretroEnvironment::GetMemoryMap() { return m_mmap; } game.libretro-20.2.4-Nexus/src/libretro/LibretroEnvironment.h000066400000000000000000000047201445145641500242360ustar00rootroot00000000000000/* * Copyright (C) 2014-2021 Team Kodi (https://kodi.tv) * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSE.md for more information. */ #pragma once #include "LibretroResources.h" #include "audio/AudioStream.h" #include "MemoryMap.h" #include "settings/LibretroSettings.h" #include "video/VideoStream.h" #include #include #include class CGameLibRetro; struct retro_game_geometry; namespace LIBRETRO { class CClientBridge; class CLibretroDLL; class ATTR_DLL_LOCAL CLibretroEnvironment { public: static CLibretroEnvironment& Get(void); void Initialize(CGameLibRetro* addon, CLibretroDLL* client, CClientBridge* clientBridge); void Deinitialize(void); CGameLibRetro* GetAddon(void) { return m_addon; } CLibretroDLL* GetClient(void) { return m_client; } CClientBridge* GetClientBridge(void) { return m_clientBridge; } CVideoStream& Video(void) { return m_videoStream; } CAudioStream& Audio(void) { return m_audioStream; } void CloseStreams(); void UpdateVideoGeometry(const retro_game_geometry &geometry); /*! * Returns the pixel format set by the libretro core. Instead of forwarding * this to the frontend, we store the value and report it on calls to * VideoRefresh(). */ GAME_PIXEL_FORMAT GetVideoFormat(void) const { return m_videoFormat; } GAME_VIDEO_ROTATION GetVideoRotation() const { return m_videoRotation; } /*! * Invoked when the frontend transfers a setting to the add-on. */ void SetSetting(const std::string& name, const std::string& value); std::string GetResourcePath(const char* relPath); /*! * \brief Called after game has been run for a frame */ void OnFrameEnd(); bool EnvironmentCallback(unsigned cmd, void* data); const CMemoryMap& GetMemoryMap(); private: CLibretroEnvironment(void); CGameLibRetro* m_addon; CLibretroDLL* m_client; CClientBridge* m_clientBridge; CVideoStream m_videoStream; CAudioStream m_audioStream; GAME_PIXEL_FORMAT m_videoFormat; GAME_VIDEO_ROTATION m_videoRotation; CLibretroSettings m_settings; CLibretroResources m_resources; CMemoryMap m_mmap; }; } // namespace LIBRETRO game.libretro-20.2.4-Nexus/src/libretro/LibretroResources.cpp000066400000000000000000000063531445145641500242430ustar00rootroot00000000000000/* * Copyright (C) 2016-2021 Team Kodi (https://kodi.tv) * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSE.md for more information. */ #include "LibretroResources.h" #include "LibretroDefines.h" #include "log/Log.h" #include "client.h" #include #include #include using namespace LIBRETRO; CLibretroResources::CLibretroResources() : m_addon(nullptr) { } void CLibretroResources::Initialize(CGameLibRetro* addon) { m_addon = addon; assert(m_addon != nullptr); std::vector dirs; m_addon->ResourceDirectories(dirs); for (const auto& dir : dirs) { if (dir.empty()) continue; // Set system path to first resource path discovered if (m_systemDirectory.empty()) { m_systemDirectory = dir + "/" LIBRETRO_SYSTEM_DIRECTORY_NAME; // Ensure folder exists if (!kodi::vfs::DirectoryExists(m_systemDirectory)) { dsyslog("Creating system directory: %s", m_systemDirectory.c_str()); kodi::vfs::CreateDirectory(m_systemDirectory); } } m_resourceDirectories.push_back(std::move(dir)); } m_saveDirectory = m_addon->ProfileDirectory() + "/" LIBRETRO_SAVE_DIRECTORY_NAME; // Ensure folder exists if (!kodi::vfs::DirectoryExists(m_saveDirectory)) { dsyslog("Creating save directory: %s", m_saveDirectory.c_str()); kodi::vfs::CreateDirectory(m_saveDirectory); } } void CLibretroResources::Deinitialize() { m_addon = nullptr; } const char* CLibretroResources::GetBasePath(const std::string& relPath) { auto it = m_pathMap.find(relPath); if (it == m_pathMap.end()) { for (const auto& dir : m_resourceDirectories) { std::string resourcePath = dir + "/" + relPath; // Check for path existence if (kodi::vfs::FileExists(resourcePath, true)) { m_pathMap.insert(std::make_pair(relPath, std::move(dir))); it = m_pathMap.find(relPath); break; } } } if (it != m_pathMap.end()) return it->second.c_str(); return nullptr; } const char* CLibretroResources::GetBaseSystemPath(const std::string& relPath) { std::string systemPath = LIBRETRO_SYSTEM_DIRECTORY_NAME "/" + relPath; const char* basePath = GetBasePath(systemPath); if (basePath != nullptr) return ApendSystemFolder(basePath); return nullptr; } std::string CLibretroResources::CLibretroResources::GetFullPath(const std::string& relPath) { const char* basePath = GetBasePath(relPath); if (basePath != nullptr) return std::string(basePath) + "/" + relPath; return ""; } std::string CLibretroResources::GetFullSystemPath(const std::string& relPath) { const char* baseSystemPath = GetBaseSystemPath(relPath); if (baseSystemPath != nullptr) return std::string(baseSystemPath) + "/" + relPath; return ""; } const char* CLibretroResources::ApendSystemFolder(const std::string& path) { static std::map pathCache; auto it = pathCache.find(path); if (it == pathCache.end()) { const std::string systemPath = path + "/" LIBRETRO_SYSTEM_DIRECTORY_NAME; pathCache.insert(std::make_pair(path, std::move(systemPath))); it = pathCache.find(path); } if (it != pathCache.end()) return it->second.c_str(); return nullptr; } game.libretro-20.2.4-Nexus/src/libretro/LibretroResources.h000066400000000000000000000024301445145641500237000ustar00rootroot00000000000000/* * Copyright (C) 2016-2021 Team Kodi (https://kodi.tv) * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSE.md for more information. */ #pragma once #include #include #include class CGameLibRetro; namespace LIBRETRO { class CLibretroResources { public: CLibretroResources(); ~CLibretroResources() { Deinitialize(); } void Initialize(CGameLibRetro* addon); void Deinitialize(); const char* GetSystemDir() const { return m_systemDirectory.c_str(); } const char* GetContentDirectory() { return GetSystemDir(); } // Use system directory const char* GetSaveDirectory() const { return m_saveDirectory.c_str(); } const char* GetBasePath(const std::string& relPath); const char* GetBaseSystemPath(const std::string& relPath); std::string GetFullPath(const std::string& relPath); std::string GetFullSystemPath(const std::string& relPath); private: const char* ApendSystemFolder(const std::string& path); CGameLibRetro* m_addon; std::vector m_resourceDirectories; std::map m_pathMap; std::string m_systemDirectory; std::string m_saveDirectory; }; } // namespace LIBRETRO game.libretro-20.2.4-Nexus/src/libretro/LibretroTranslator.cpp000066400000000000000000000723571445145641500244310ustar00rootroot00000000000000/* * Copyright (C) 2015-2021 Team Kodi (https://kodi.tv) * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSE.md for more information. */ #include "LibretroTranslator.h" #include using namespace LIBRETRO; namespace LIBRETRO { inline retro_mod operator|(retro_mod lhs, retro_mod rhs) { return static_cast(static_cast(lhs) | static_cast(rhs)); } } // --- Audo/video translation ---------------------------------------------- GAME_PIXEL_FORMAT LibretroTranslator::GetVideoFormat(retro_pixel_format format) { switch (format) { case RETRO_PIXEL_FORMAT_0RGB1555: return GAME_PIXEL_FORMAT_0RGB1555; case RETRO_PIXEL_FORMAT_XRGB8888: return GAME_PIXEL_FORMAT_0RGB8888; case RETRO_PIXEL_FORMAT_RGB565: return GAME_PIXEL_FORMAT_RGB565; case RETRO_PIXEL_FORMAT_UNKNOWN: default: break; } return GAME_PIXEL_FORMAT_UNKNOWN; } retro_pixel_format LibretroTranslator::GetLibretroVideoFormat(GAME_PIXEL_FORMAT format) { switch (format) { case GAME_PIXEL_FORMAT_0RGB1555: return RETRO_PIXEL_FORMAT_0RGB1555; case GAME_PIXEL_FORMAT_0RGB8888: return RETRO_PIXEL_FORMAT_XRGB8888; case GAME_PIXEL_FORMAT_RGB565: return RETRO_PIXEL_FORMAT_RGB565; default: break; } return RETRO_PIXEL_FORMAT_UNKNOWN; } const char *LibretroTranslator::VideoFormatToString(retro_pixel_format format) { switch (format) { case RETRO_PIXEL_FORMAT_0RGB1555: return "0RGB1555"; case RETRO_PIXEL_FORMAT_XRGB8888: return "XRGB8888"; case RETRO_PIXEL_FORMAT_RGB565: return "RGB565"; default: break; } return ""; } GAME_VIDEO_ROTATION LibretroTranslator::GetVideoRotation(unsigned int rotation) { switch (rotation) { case 0: return GAME_VIDEO_ROTATION_0; case 1: return GAME_VIDEO_ROTATION_90_CCW; case 2: return GAME_VIDEO_ROTATION_180_CCW; case 3: return GAME_VIDEO_ROTATION_270_CCW; default: break; } return GAME_VIDEO_ROTATION_0; } // --- Hardware rendering translation -------------------------------------- GAME_HW_CONTEXT_TYPE LibretroTranslator::GetHWContextType(retro_hw_context_type type) { switch (type) { case RETRO_HW_CONTEXT_OPENGL: return GAME_HW_CONTEXT_OPENGL; case RETRO_HW_CONTEXT_OPENGLES2: return GAME_HW_CONTEXT_OPENGLES2; case RETRO_HW_CONTEXT_OPENGL_CORE: return GAME_HW_CONTEXT_OPENGL_CORE; case RETRO_HW_CONTEXT_OPENGLES3: return GAME_HW_CONTEXT_OPENGLES3; case RETRO_HW_CONTEXT_OPENGLES_VERSION: return GAME_HW_CONTEXT_OPENGLES_VERSION; case RETRO_HW_CONTEXT_VULKAN: return GAME_HW_CONTEXT_VULKAN; case RETRO_HW_CONTEXT_NONE: case RETRO_HW_CONTEXT_DUMMY: default: break; } return GAME_HW_CONTEXT_NONE; } // --- Input translation -------------------------------------------------- libretro_device_t LibretroTranslator::GetDeviceType(const std::string& strLibretroType) { if (strLibretroType == "RETRO_DEVICE_JOYPAD") return RETRO_DEVICE_JOYPAD; if (strLibretroType == "RETRO_DEVICE_MOUSE") return RETRO_DEVICE_MOUSE; if (strLibretroType == "RETRO_DEVICE_KEYBOARD") return RETRO_DEVICE_KEYBOARD; if (strLibretroType == "RETRO_DEVICE_LIGHTGUN") return RETRO_DEVICE_LIGHTGUN; if (strLibretroType == "RETRO_DEVICE_ANALOG") return RETRO_DEVICE_ANALOG; if (strLibretroType == "RETRO_DEVICE_POINTER") return RETRO_DEVICE_POINTER; return RETRO_DEVICE_NONE; } const char* LibretroTranslator::GetDeviceName(libretro_device_t type) { switch (type) { case RETRO_DEVICE_JOYPAD: return "RETRO_DEVICE_JOYPAD"; case RETRO_DEVICE_MOUSE: return "RETRO_DEVICE_MOUSE"; case RETRO_DEVICE_KEYBOARD: return "RETRO_DEVICE_KEYBOARD"; case RETRO_DEVICE_LIGHTGUN: return "RETRO_DEVICE_LIGHTGUN"; case RETRO_DEVICE_ANALOG: return "RETRO_DEVICE_ANALOG"; case RETRO_DEVICE_POINTER: return "RETRO_DEVICE_POINTER"; default: break; } return ""; } namespace LIBRETRO { struct LibretroFeature { const char *libretroId; int featureIndex; }; using LibretroFeatures = std::vector; using LibretroFeatureMap = std::map; const LibretroFeatureMap featureMap = { { RETRO_DEVICE_JOYPAD, { { "RETRO_DEVICE_ID_JOYPAD_A", RETRO_DEVICE_ID_JOYPAD_A }, { "RETRO_DEVICE_ID_JOYPAD_B", RETRO_DEVICE_ID_JOYPAD_B }, { "RETRO_DEVICE_ID_JOYPAD_X", RETRO_DEVICE_ID_JOYPAD_X }, { "RETRO_DEVICE_ID_JOYPAD_Y", RETRO_DEVICE_ID_JOYPAD_Y }, { "RETRO_DEVICE_ID_JOYPAD_START", RETRO_DEVICE_ID_JOYPAD_START }, { "RETRO_DEVICE_ID_JOYPAD_SELECT", RETRO_DEVICE_ID_JOYPAD_SELECT }, { "RETRO_DEVICE_ID_JOYPAD_UP", RETRO_DEVICE_ID_JOYPAD_UP }, { "RETRO_DEVICE_ID_JOYPAD_DOWN", RETRO_DEVICE_ID_JOYPAD_DOWN }, { "RETRO_DEVICE_ID_JOYPAD_RIGHT", RETRO_DEVICE_ID_JOYPAD_RIGHT }, { "RETRO_DEVICE_ID_JOYPAD_LEFT", RETRO_DEVICE_ID_JOYPAD_LEFT }, { "RETRO_DEVICE_ID_JOYPAD_L", RETRO_DEVICE_ID_JOYPAD_L }, { "RETRO_DEVICE_ID_JOYPAD_R", RETRO_DEVICE_ID_JOYPAD_R }, { "RETRO_DEVICE_ID_JOYPAD_L2", RETRO_DEVICE_ID_JOYPAD_L2 }, { "RETRO_DEVICE_ID_JOYPAD_R2", RETRO_DEVICE_ID_JOYPAD_R2 }, { "RETRO_DEVICE_ID_JOYPAD_L3", RETRO_DEVICE_ID_JOYPAD_L3 }, { "RETRO_DEVICE_ID_JOYPAD_R3", RETRO_DEVICE_ID_JOYPAD_R3 }, { "RETRO_RUMBLE_STRONG", RETRO_RUMBLE_STRONG }, { "RETRO_RUMBLE_WEAK", RETRO_RUMBLE_WEAK }, } }, { RETRO_DEVICE_ANALOG, { { "RETRO_DEVICE_INDEX_ANALOG_LEFT", RETRO_DEVICE_INDEX_ANALOG_LEFT }, { "RETRO_DEVICE_INDEX_ANALOG_RIGHT", RETRO_DEVICE_INDEX_ANALOG_RIGHT }, } }, { RETRO_DEVICE_MOUSE, { { "RETRO_DEVICE_MOUSE", 0 }, // Only 1 relative pointer, use ID 0 { "RETRO_DEVICE_ID_MOUSE_LEFT", RETRO_DEVICE_ID_MOUSE_LEFT }, { "RETRO_DEVICE_ID_MOUSE_RIGHT", RETRO_DEVICE_ID_MOUSE_RIGHT }, { "RETRO_DEVICE_ID_MOUSE_WHEELUP", RETRO_DEVICE_ID_MOUSE_WHEELUP }, { "RETRO_DEVICE_ID_MOUSE_WHEELDOWN", RETRO_DEVICE_ID_MOUSE_WHEELDOWN }, { "RETRO_DEVICE_ID_MOUSE_MIDDLE", RETRO_DEVICE_ID_MOUSE_MIDDLE }, { "RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELUP", RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELUP }, { "RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELDOWN", RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELDOWN }, } }, { RETRO_DEVICE_LIGHTGUN, { { "RETRO_DEVICE_LIGHTGUN", 0 }, // Only 1 relative pointer, use ID 0 { "RETRO_DEVICE_ID_LIGHTGUN_TRIGGER", RETRO_DEVICE_ID_LIGHTGUN_TRIGGER }, { "RETRO_DEVICE_ID_LIGHTGUN_CURSOR", RETRO_DEVICE_ID_LIGHTGUN_CURSOR }, { "RETRO_DEVICE_ID_LIGHTGUN_TURBO", RETRO_DEVICE_ID_LIGHTGUN_TURBO }, { "RETRO_DEVICE_ID_LIGHTGUN_PAUSE", RETRO_DEVICE_ID_LIGHTGUN_PAUSE }, { "RETRO_DEVICE_ID_LIGHTGUN_START", RETRO_DEVICE_ID_LIGHTGUN_START }, { "RETRO_DEVICE_ID_LIGHTGUN_AUX_A", RETRO_DEVICE_ID_LIGHTGUN_AUX_A }, { "RETRO_DEVICE_ID_LIGHTGUN_AUX_B", RETRO_DEVICE_ID_LIGHTGUN_AUX_B }, { "RETRO_DEVICE_ID_LIGHTGUN_SELECT", RETRO_DEVICE_ID_LIGHTGUN_SELECT }, { "RETRO_DEVICE_ID_LIGHTGUN_AUX_C", RETRO_DEVICE_ID_LIGHTGUN_AUX_C }, { "RETRO_DEVICE_ID_LIGHTGUN_DPAD_UP", RETRO_DEVICE_ID_LIGHTGUN_DPAD_UP }, { "RETRO_DEVICE_ID_LIGHTGUN_DPAD_DOWN", RETRO_DEVICE_ID_LIGHTGUN_DPAD_DOWN }, { "RETRO_DEVICE_ID_LIGHTGUN_DPAD_LEFT", RETRO_DEVICE_ID_LIGHTGUN_DPAD_LEFT }, { "RETRO_DEVICE_ID_LIGHTGUN_DPAD_RIGHT", RETRO_DEVICE_ID_LIGHTGUN_DPAD_RIGHT }, { "RETRO_DEVICE_ID_LIGHTGUN_IS_OFFSCREEN", RETRO_DEVICE_ID_LIGHTGUN_IS_OFFSCREEN }, { "RETRO_DEVICE_ID_LIGHTGUN_RELOAD", RETRO_DEVICE_ID_LIGHTGUN_RELOAD }, } }, { RETRO_DEVICE_KEYBOARD, { { "RETROK_BACKSPACE", RETROK_BACKSPACE }, { "RETROK_TAB", RETROK_TAB }, { "RETROK_CLEAR", RETROK_CLEAR }, { "RETROK_RETURN", RETROK_RETURN }, { "RETROK_PAUSE", RETROK_PAUSE }, { "RETROK_ESCAPE", RETROK_ESCAPE }, { "RETROK_SPACE", RETROK_SPACE }, { "RETROK_EXCLAIM", RETROK_EXCLAIM }, { "RETROK_QUOTEDBL", RETROK_QUOTEDBL }, { "RETROK_HASH", RETROK_HASH }, { "RETROK_DOLLAR", RETROK_DOLLAR }, { "RETROK_AMPERSAND", RETROK_AMPERSAND }, { "RETROK_QUOTE", RETROK_QUOTE }, { "RETROK_LEFTPAREN", RETROK_LEFTPAREN }, { "RETROK_RIGHTPAREN", RETROK_RIGHTPAREN }, { "RETROK_ASTERISK", RETROK_ASTERISK }, { "RETROK_PLUS", RETROK_PLUS }, { "RETROK_COMMA", RETROK_COMMA }, { "RETROK_MINUS", RETROK_MINUS }, { "RETROK_PERIOD", RETROK_PERIOD }, { "RETROK_SLASH", RETROK_SLASH }, { "RETROK_0", RETROK_0 }, { "RETROK_1", RETROK_1 }, { "RETROK_2", RETROK_2 }, { "RETROK_3", RETROK_3 }, { "RETROK_4", RETROK_4 }, { "RETROK_5", RETROK_5 }, { "RETROK_6", RETROK_6 }, { "RETROK_7", RETROK_7 }, { "RETROK_8", RETROK_8 }, { "RETROK_9", RETROK_9 }, { "RETROK_COLON", RETROK_COLON }, { "RETROK_SEMICOLON", RETROK_SEMICOLON }, { "RETROK_LESS", RETROK_LESS }, { "RETROK_EQUALS", RETROK_EQUALS }, { "RETROK_GREATER", RETROK_GREATER }, { "RETROK_QUESTION", RETROK_QUESTION }, { "RETROK_AT", RETROK_AT }, { "RETROK_LEFTBRACKET", RETROK_LEFTBRACKET }, { "RETROK_BACKSLASH", RETROK_BACKSLASH }, { "RETROK_RIGHTBRACKET", RETROK_RIGHTBRACKET }, { "RETROK_CARET", RETROK_CARET }, { "RETROK_UNDERSCORE", RETROK_UNDERSCORE }, { "RETROK_BACKQUOTE", RETROK_BACKQUOTE }, { "RETROK_a", RETROK_a }, { "RETROK_b", RETROK_b }, { "RETROK_c", RETROK_c }, { "RETROK_d", RETROK_d }, { "RETROK_e", RETROK_e }, { "RETROK_f", RETROK_f }, { "RETROK_g", RETROK_g }, { "RETROK_h", RETROK_h }, { "RETROK_i", RETROK_i }, { "RETROK_j", RETROK_j }, { "RETROK_k", RETROK_k }, { "RETROK_l", RETROK_l }, { "RETROK_m", RETROK_m }, { "RETROK_n", RETROK_n }, { "RETROK_o", RETROK_o }, { "RETROK_p", RETROK_p }, { "RETROK_q", RETROK_q }, { "RETROK_r", RETROK_r }, { "RETROK_s", RETROK_s }, { "RETROK_t", RETROK_t }, { "RETROK_u", RETROK_u }, { "RETROK_v", RETROK_v }, { "RETROK_w", RETROK_w }, { "RETROK_x", RETROK_x }, { "RETROK_y", RETROK_y }, { "RETROK_z", RETROK_z }, { "RETROK_LEFTBRACE", RETROK_LEFTBRACE }, { "RETROK_BAR", RETROK_BAR }, { "RETROK_RIGHTBRACE", RETROK_RIGHTBRACE }, { "RETROK_TILDE", RETROK_TILDE }, { "RETROK_DELETE", RETROK_DELETE }, { "RETROK_KP0", RETROK_KP0 }, { "RETROK_KP1", RETROK_KP1 }, { "RETROK_KP2", RETROK_KP2 }, { "RETROK_KP3", RETROK_KP3 }, { "RETROK_KP4", RETROK_KP4 }, { "RETROK_KP5", RETROK_KP5 }, { "RETROK_KP6", RETROK_KP6 }, { "RETROK_KP7", RETROK_KP7 }, { "RETROK_KP8", RETROK_KP8 }, { "RETROK_KP9", RETROK_KP9 }, { "RETROK_KP_PERIOD", RETROK_KP_PERIOD }, { "RETROK_KP_DIVIDE", RETROK_KP_DIVIDE }, { "RETROK_KP_MULTIPLY", RETROK_KP_MULTIPLY }, { "RETROK_KP_MINUS", RETROK_KP_MINUS }, { "RETROK_KP_PLUS", RETROK_KP_PLUS }, { "RETROK_KP_ENTER", RETROK_KP_ENTER }, { "RETROK_KP_EQUALS", RETROK_KP_EQUALS }, { "RETROK_UP", RETROK_UP }, { "RETROK_DOWN", RETROK_DOWN }, { "RETROK_RIGHT", RETROK_RIGHT }, { "RETROK_LEFT", RETROK_LEFT }, { "RETROK_INSERT", RETROK_INSERT }, { "RETROK_HOME", RETROK_HOME }, { "RETROK_END", RETROK_END }, { "RETROK_PAGEUP", RETROK_PAGEUP }, { "RETROK_PAGEDOWN", RETROK_PAGEDOWN }, { "RETROK_F1", RETROK_F1 }, { "RETROK_F2", RETROK_F2 }, { "RETROK_F3", RETROK_F3 }, { "RETROK_F4", RETROK_F4 }, { "RETROK_F5", RETROK_F5 }, { "RETROK_F6", RETROK_F6 }, { "RETROK_F7", RETROK_F7 }, { "RETROK_F8", RETROK_F8 }, { "RETROK_F9", RETROK_F9 }, { "RETROK_F10", RETROK_F10 }, { "RETROK_F11", RETROK_F11 }, { "RETROK_F12", RETROK_F12 }, { "RETROK_F13", RETROK_F13 }, { "RETROK_F14", RETROK_F14 }, { "RETROK_F15", RETROK_F15 }, { "RETROK_NUMLOCK", RETROK_NUMLOCK }, { "RETROK_CAPSLOCK", RETROK_CAPSLOCK }, { "RETROK_SCROLLOCK", RETROK_SCROLLOCK }, { "RETROK_RSHIFT", RETROK_RSHIFT }, { "RETROK_LSHIFT", RETROK_LSHIFT }, { "RETROK_RCTRL", RETROK_RCTRL }, { "RETROK_LCTRL", RETROK_LCTRL }, { "RETROK_RALT", RETROK_RALT }, { "RETROK_LALT", RETROK_LALT }, { "RETROK_RMETA", RETROK_RMETA }, { "RETROK_LMETA", RETROK_LMETA }, { "RETROK_LSUPER", RETROK_LSUPER }, { "RETROK_RSUPER", RETROK_RSUPER }, { "RETROK_MODE", RETROK_MODE }, { "RETROK_COMPOSE", RETROK_COMPOSE }, { "RETROK_HELP", RETROK_HELP }, { "RETROK_PRINT", RETROK_PRINT }, { "RETROK_SYSREQ", RETROK_SYSREQ }, { "RETROK_BREAK", RETROK_BREAK }, { "RETROK_MENU", RETROK_MENU }, { "RETROK_POWER", RETROK_POWER }, { "RETROK_EURO", RETROK_EURO }, { "RETROK_UNDO", RETROK_UNDO }, } }, }; } int LibretroTranslator::GetFeatureIndex(const std::string& strLibretroFeature) { for (const auto &it : featureMap) { const auto &features = it.second; auto it2 = std::find_if(features.begin(), features.end(), [&strLibretroFeature](const LibretroFeature& feature) { return strLibretroFeature == feature.libretroId; }); if (it2 != features.end()) return it2->featureIndex; } return -1; } libretro_device_t LibretroTranslator::GetLibretroDevice(const std::string& strLibretroFeature) { for (const auto &it : featureMap) { const libretro_device_t deviceType = it.first; const auto &features = it.second; auto it2 = std::find_if(features.begin(), features.end(), [&strLibretroFeature](const LibretroFeature& feature) { return strLibretroFeature == feature.libretroId; }); if (it2 != features.end()) return deviceType; } return RETRO_DEVICE_NONE; } const char* LibretroTranslator::GetFeatureName(libretro_device_t type, unsigned int index, unsigned int id) { switch (type) { case RETRO_DEVICE_JOYPAD: { switch (id) { case RETRO_DEVICE_ID_JOYPAD_B: return "RETRO_DEVICE_ID_JOYPAD_B"; case RETRO_DEVICE_ID_JOYPAD_Y: return "RETRO_DEVICE_ID_JOYPAD_Y"; case RETRO_DEVICE_ID_JOYPAD_SELECT: return "RETRO_DEVICE_ID_JOYPAD_SELECT"; case RETRO_DEVICE_ID_JOYPAD_START: return "RETRO_DEVICE_ID_JOYPAD_START"; case RETRO_DEVICE_ID_JOYPAD_UP: return "RETRO_DEVICE_ID_JOYPAD_UP"; case RETRO_DEVICE_ID_JOYPAD_DOWN: return "RETRO_DEVICE_ID_JOYPAD_DOWN"; case RETRO_DEVICE_ID_JOYPAD_LEFT: return "RETRO_DEVICE_ID_JOYPAD_LEFT"; case RETRO_DEVICE_ID_JOYPAD_RIGHT: return "RETRO_DEVICE_ID_JOYPAD_RIGHT"; case RETRO_DEVICE_ID_JOYPAD_A: return "RETRO_DEVICE_ID_JOYPAD_A"; case RETRO_DEVICE_ID_JOYPAD_X: return "RETRO_DEVICE_ID_JOYPAD_X"; case RETRO_DEVICE_ID_JOYPAD_L: return "RETRO_DEVICE_ID_JOYPAD_L"; case RETRO_DEVICE_ID_JOYPAD_R: return "RETRO_DEVICE_ID_JOYPAD_R"; case RETRO_DEVICE_ID_JOYPAD_L2: return "RETRO_DEVICE_ID_JOYPAD_L2"; case RETRO_DEVICE_ID_JOYPAD_R2: return "RETRO_DEVICE_ID_JOYPAD_R2"; case RETRO_DEVICE_ID_JOYPAD_L3: return "RETRO_DEVICE_ID_JOYPAD_L3"; case RETRO_DEVICE_ID_JOYPAD_R3: return "RETRO_DEVICE_ID_JOYPAD_R3"; default: break; } break; } case RETRO_DEVICE_MOUSE: { switch (id) { case RETRO_DEVICE_ID_MOUSE_X: case RETRO_DEVICE_ID_MOUSE_Y: return "RETRO_DEVICE_MOUSE"; case RETRO_DEVICE_ID_MOUSE_LEFT: return "RETRO_DEVICE_ID_MOUSE_LEFT"; case RETRO_DEVICE_ID_MOUSE_RIGHT: return "RETRO_DEVICE_ID_MOUSE_RIGHT"; case RETRO_DEVICE_ID_MOUSE_WHEELUP: return "RETRO_DEVICE_ID_MOUSE_WHEELUP"; case RETRO_DEVICE_ID_MOUSE_WHEELDOWN: return "RETRO_DEVICE_ID_MOUSE_WHEELDOWN"; case RETRO_DEVICE_ID_MOUSE_MIDDLE: return "RETRO_DEVICE_ID_MOUSE_MIDDLE"; case RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELUP: return "RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELUP"; case RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELDOWN: return "RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELDOWN"; default: break; } break; } case RETRO_DEVICE_KEYBOARD: { switch (id) { case RETROK_BACKSPACE: return "RETROK_BACKSPACE"; case RETROK_TAB: return "RETROK_TAB"; case RETROK_CLEAR: return "RETROK_CLEAR"; case RETROK_RETURN: return "RETROK_RETURN"; case RETROK_PAUSE: return "RETROK_PAUSE"; case RETROK_ESCAPE: return "RETROK_ESCAPE"; case RETROK_SPACE: return "RETROK_SPACE"; case RETROK_EXCLAIM: return "RETROK_EXCLAIM"; case RETROK_QUOTEDBL: return "RETROK_QUOTEDBL"; case RETROK_HASH: return "RETROK_HASH"; case RETROK_DOLLAR: return "RETROK_DOLLAR"; case RETROK_AMPERSAND: return "RETROK_AMPERSAND"; case RETROK_QUOTE: return "RETROK_QUOTE"; case RETROK_LEFTPAREN: return "RETROK_LEFTPAREN"; case RETROK_RIGHTPAREN: return "RETROK_RIGHTPAREN"; case RETROK_ASTERISK: return "RETROK_ASTERISK"; case RETROK_PLUS: return "RETROK_PLUS"; case RETROK_COMMA: return "RETROK_COMMA"; case RETROK_MINUS: return "RETROK_MINUS"; case RETROK_PERIOD: return "RETROK_PERIOD"; case RETROK_SLASH: return "RETROK_SLASH"; case RETROK_0: return "RETROK_0"; case RETROK_1: return "RETROK_1"; case RETROK_2: return "RETROK_2"; case RETROK_3: return "RETROK_3"; case RETROK_4: return "RETROK_4"; case RETROK_5: return "RETROK_5"; case RETROK_6: return "RETROK_6"; case RETROK_7: return "RETROK_7"; case RETROK_8: return "RETROK_8"; case RETROK_9: return "RETROK_9"; case RETROK_COLON: return "RETROK_COLON"; case RETROK_SEMICOLON: return "RETROK_SEMICOLON"; case RETROK_LESS: return "RETROK_LESS"; case RETROK_EQUALS: return "RETROK_EQUALS"; case RETROK_GREATER: return "RETROK_GREATER"; case RETROK_QUESTION: return "RETROK_QUESTION"; case RETROK_AT: return "RETROK_AT"; case RETROK_LEFTBRACKET: return "RETROK_LEFTBRACKET"; case RETROK_BACKSLASH: return "RETROK_BACKSLASH"; case RETROK_RIGHTBRACKET: return "RETROK_RIGHTBRACKET"; case RETROK_CARET: return "RETROK_CARET"; case RETROK_UNDERSCORE: return "RETROK_UNDERSCORE"; case RETROK_BACKQUOTE: return "RETROK_BACKQUOTE"; case RETROK_a: return "RETROK_a"; case RETROK_b: return "RETROK_b"; case RETROK_c: return "RETROK_c"; case RETROK_d: return "RETROK_d"; case RETROK_e: return "RETROK_e"; case RETROK_f: return "RETROK_f"; case RETROK_g: return "RETROK_g"; case RETROK_h: return "RETROK_h"; case RETROK_i: return "RETROK_i"; case RETROK_j: return "RETROK_j"; case RETROK_k: return "RETROK_k"; case RETROK_l: return "RETROK_l"; case RETROK_m: return "RETROK_m"; case RETROK_n: return "RETROK_n"; case RETROK_o: return "RETROK_o"; case RETROK_p: return "RETROK_p"; case RETROK_q: return "RETROK_q"; case RETROK_r: return "RETROK_r"; case RETROK_s: return "RETROK_s"; case RETROK_t: return "RETROK_t"; case RETROK_u: return "RETROK_u"; case RETROK_v: return "RETROK_v"; case RETROK_w: return "RETROK_w"; case RETROK_x: return "RETROK_x"; case RETROK_y: return "RETROK_y"; case RETROK_z: return "RETROK_z"; case RETROK_LEFTBRACE: return "RETROK_LEFTBRACE"; case RETROK_BAR: return "RETROK_BAR"; case RETROK_RIGHTBRACE: return "RETROK_RIGHTBRACE"; case RETROK_TILDE: return "RETROK_TILDE"; case RETROK_DELETE: return "RETROK_DELETE"; case RETROK_KP0: return "RETROK_KP0"; case RETROK_KP1: return "RETROK_KP1"; case RETROK_KP2: return "RETROK_KP2"; case RETROK_KP3: return "RETROK_KP3"; case RETROK_KP4: return "RETROK_KP4"; case RETROK_KP5: return "RETROK_KP5"; case RETROK_KP6: return "RETROK_KP6"; case RETROK_KP7: return "RETROK_KP7"; case RETROK_KP8: return "RETROK_KP8"; case RETROK_KP9: return "RETROK_KP9"; case RETROK_KP_PERIOD: return "RETROK_KP_PERIOD"; case RETROK_KP_DIVIDE: return "RETROK_KP_DIVIDE"; case RETROK_KP_MULTIPLY: return "RETROK_KP_MULTIPLY"; case RETROK_KP_MINUS: return "RETROK_KP_MINUS"; case RETROK_KP_PLUS: return "RETROK_KP_PLUS"; case RETROK_KP_ENTER: return "RETROK_KP_ENTER"; case RETROK_KP_EQUALS: return "RETROK_KP_EQUALS"; case RETROK_UP: return "RETROK_UP"; case RETROK_DOWN: return "RETROK_DOWN"; case RETROK_RIGHT: return "RETROK_RIGHT"; case RETROK_LEFT: return "RETROK_LEFT"; case RETROK_INSERT: return "RETROK_INSERT"; case RETROK_HOME: return "RETROK_HOME"; case RETROK_END: return "RETROK_END"; case RETROK_PAGEUP: return "RETROK_PAGEUP"; case RETROK_PAGEDOWN: return "RETROK_PAGEDOWN"; case RETROK_F1: return "RETROK_F1"; case RETROK_F2: return "RETROK_F2"; case RETROK_F3: return "RETROK_F3"; case RETROK_F4: return "RETROK_F4"; case RETROK_F5: return "RETROK_F5"; case RETROK_F6: return "RETROK_F6"; case RETROK_F7: return "RETROK_F7"; case RETROK_F8: return "RETROK_F8"; case RETROK_F9: return "RETROK_F9"; case RETROK_F10: return "RETROK_F10"; case RETROK_F11: return "RETROK_F11"; case RETROK_F12: return "RETROK_F12"; case RETROK_F13: return "RETROK_F13"; case RETROK_F14: return "RETROK_F14"; case RETROK_F15: return "RETROK_F15"; case RETROK_NUMLOCK: return "RETROK_NUMLOCK"; case RETROK_CAPSLOCK: return "RETROK_CAPSLOCK"; case RETROK_SCROLLOCK: return "RETROK_SCROLLOCK"; case RETROK_RSHIFT: return "RETROK_RSHIFT"; case RETROK_LSHIFT: return "RETROK_LSHIFT"; case RETROK_RCTRL: return "RETROK_RCTRL"; case RETROK_LCTRL: return "RETROK_LCTRL"; case RETROK_RALT: return "RETROK_RALT"; case RETROK_LALT: return "RETROK_LALT"; case RETROK_RMETA: return "RETROK_RMETA"; case RETROK_LMETA: return "RETROK_LMETA"; case RETROK_LSUPER: return "RETROK_LSUPER"; case RETROK_RSUPER: return "RETROK_RSUPER"; case RETROK_MODE: return "RETROK_MODE"; case RETROK_COMPOSE: return "RETROK_COMPOSE"; case RETROK_HELP: return "RETROK_HELP"; case RETROK_PRINT: return "RETROK_PRINT"; case RETROK_SYSREQ: return "RETROK_SYSREQ"; case RETROK_BREAK: return "RETROK_BREAK"; case RETROK_MENU: return "RETROK_MENU"; case RETROK_POWER: return "RETROK_POWER"; case RETROK_EURO: return "RETROK_EURO"; case RETROK_UNDO: return "RETROK_UNDO"; default: break; } break; } case RETRO_DEVICE_LIGHTGUN: { switch (id) { case RETRO_DEVICE_ID_LIGHTGUN_X: case RETRO_DEVICE_ID_LIGHTGUN_Y: return "RETRO_DEVICE_LIGHTGUN"; case RETRO_DEVICE_ID_LIGHTGUN_TRIGGER: return "RETRO_DEVICE_ID_LIGHTGUN_TRIGGER"; case RETRO_DEVICE_ID_LIGHTGUN_CURSOR: return "RETRO_DEVICE_ID_LIGHTGUN_CURSOR"; case RETRO_DEVICE_ID_LIGHTGUN_TURBO: return "RETRO_DEVICE_ID_LIGHTGUN_TURBO"; case RETRO_DEVICE_ID_LIGHTGUN_PAUSE: return "RETRO_DEVICE_ID_LIGHTGUN_PAUSE"; case RETRO_DEVICE_ID_LIGHTGUN_START: return "RETRO_DEVICE_ID_LIGHTGUN_START"; default: break; } break; } case RETRO_DEVICE_ANALOG: { switch (index) { case RETRO_DEVICE_INDEX_ANALOG_LEFT: return "RETRO_DEVICE_INDEX_ANALOG_LEFT"; case RETRO_DEVICE_INDEX_ANALOG_RIGHT: return "RETRO_DEVICE_INDEX_ANALOG_RIGHT"; case RETRO_DEVICE_INDEX_ANALOG_BUTTON: return GetFeatureName(RETRO_DEVICE_JOYPAD, index, id); default: break; } break; } case RETRO_DEVICE_POINTER: { break; // TODO } default: break; } return ""; } int LibretroTranslator::GetAxisID(const std::string& axisId) { if (axisId == "RETRO_DEVICE_ID_ANALOG_X") return RETRO_DEVICE_ID_ANALOG_X; else if (axisId == "RETRO_DEVICE_ID_ANALOG_Y") return RETRO_DEVICE_ID_ANALOG_Y; else if (axisId == "RETRO_DEVICE_ID_MOUSE_X") return RETRO_DEVICE_ID_MOUSE_X; else if (axisId == "RETRO_DEVICE_ID_MOUSE_Y") return RETRO_DEVICE_ID_MOUSE_Y; else if (axisId == "RETRO_DEVICE_ID_LIGHTGUN_X") return RETRO_DEVICE_ID_LIGHTGUN_X; else if (axisId == "RETRO_DEVICE_ID_LIGHTGUN_Y") return RETRO_DEVICE_ID_LIGHTGUN_Y; else if (axisId == "RETRO_DEVICE_ID_POINTER_X") return RETRO_DEVICE_ID_POINTER_X; else if (axisId == "RETRO_DEVICE_ID_POINTER_Y") return RETRO_DEVICE_ID_POINTER_Y; return -1; } const char* LibretroTranslator::GetComponentName(libretro_device_t type, unsigned int index, unsigned int id) { switch (type) { case RETRO_DEVICE_ANALOG: { switch (id) { case RETRO_DEVICE_ID_ANALOG_X: return "RETRO_DEVICE_ID_ANALOG_X"; case RETRO_DEVICE_ID_ANALOG_Y: return "RETRO_DEVICE_ID_ANALOG_Y"; default: break; } break; } case RETRO_DEVICE_MOUSE: { switch (id) { case RETRO_DEVICE_ID_MOUSE_X: return "RETRO_DEVICE_ID_MOUSE_X"; case RETRO_DEVICE_ID_MOUSE_Y: return "RETRO_DEVICE_ID_MOUSE_Y"; default: break; } break; } case RETRO_DEVICE_LIGHTGUN: { switch (id) { case RETRO_DEVICE_ID_LIGHTGUN_X: return "RETRO_DEVICE_ID_LIGHTGUN_X"; case RETRO_DEVICE_ID_LIGHTGUN_Y: return "RETRO_DEVICE_ID_LIGHTGUN_Y"; default: break; } break; } case RETRO_DEVICE_POINTER: { switch (id) { case RETRO_DEVICE_ID_POINTER_X: return "RETRO_DEVICE_ID_POINTER_X"; case RETRO_DEVICE_ID_POINTER_Y: return "RETRO_DEVICE_ID_POINTER_Y"; default: break; } break; } default: break; } return ""; } std::string LibretroTranslator::GetMotorName(retro_rumble_effect effect) { switch (effect) { case RETRO_RUMBLE_STRONG: return "RETRO_RUMBLE_STRONG"; case RETRO_RUMBLE_WEAK: return "RETRO_RUMBLE_WEAK"; default: break; } return ""; } retro_mod LibretroTranslator::GetKeyModifiers(GAME_KEY_MOD modifiers) { retro_mod mods = RETROKMOD_NONE; if (modifiers & GAME_KEY_MOD_SHIFT) mods = mods | RETROKMOD_SHIFT; if (modifiers & GAME_KEY_MOD_CTRL) mods = mods | RETROKMOD_CTRL; if (modifiers & GAME_KEY_MOD_ALT) mods = mods | RETROKMOD_ALT; if (modifiers & GAME_KEY_MOD_META) mods = mods | RETROKMOD_META; // GAME_KEY_MOD_SUPER not implemented in libretro API if (modifiers & GAME_KEY_MOD_NUMLOCK) mods = mods | RETROKMOD_NUMLOCK; if (modifiers & GAME_KEY_MOD_CAPSLOCK) mods = mods | RETROKMOD_CAPSLOCK; if (modifiers & GAME_KEY_MOD_SCROLLOCK) mods = mods | RETROKMOD_SCROLLOCK; return mods; } game.libretro-20.2.4-Nexus/src/libretro/LibretroTranslator.h000066400000000000000000000113431445145641500240620ustar00rootroot00000000000000/* * Copyright (C) 2015-2021 Team Kodi (https://kodi.tv) * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSE.md for more information. */ #pragma once #include "input/LibretroDevice.h" #include "libretro-common/libretro.h" #include #include class TiXmlNode; namespace LIBRETRO { /*! * \brief Translates data types from the Game API to the corresponding one in libretro (and vice versa). * * This class is stateless. */ class LibretroTranslator { LibretroTranslator() = delete; public: // --- Audo/video translation ---------------------------------------------- /*! * \brief Translate video format (libretro to Game API). * \param format The video format to translate. * \return Translated video format. */ static GAME_PIXEL_FORMAT GetVideoFormat(retro_pixel_format format); /*! * \brief Translate video format (Game API to libretro). * \param format The video format to translate. * \return Translated video format. */ static retro_pixel_format GetLibretroVideoFormat(GAME_PIXEL_FORMAT format); /*! * \brief Translate video format (libretro to string suitable for logging) * \param format The video format to translate * \return String representation of video format */ static const char *VideoFormatToString(retro_pixel_format format); /*! * \brief Translate video rotation (libretro to Game API). * \param rotation The video rotation to translate as set by RETRO_ENVIRONMENT_SET_ROTATION. * \return Translated video rotation. */ static GAME_VIDEO_ROTATION GetVideoRotation(unsigned int rotation); // --- Hardware rendering translation -------------------------------------- /*! * \brief Translate HW context type (libretro to Game API) * \param type The HW context type to translate (e.g. OpenGL, OpenGLES). * \return Translated HW context type. */ static GAME_HW_CONTEXT_TYPE GetHWContextType(retro_hw_context_type type); // --- Input translation -------------------------------------------------- /*! * \brief Translate device type (Game API to libretro). * \param strType The device type to translate. * \return Translated device values. */ static libretro_device_t GetDeviceType(const std::string& strLibretroType); /*! * \brief Translate device type (libretro) to string representation (e.g. for logging). * \param type The device type to stringify. * \return String representation of device type. */ static const char* GetDeviceName(libretro_device_t type); /*! * \brief Translate button/feature name (libretro buttonmap "mapto" field) to libretro index value. * \param strFeatureName The feature name to translate. * \return Translated button/feature id. */ static int GetFeatureIndex(const std::string& strLibretroFeature); /*! * \brief Translate button/feature name (libretro buttonmap "mapto" field) to libretro index value. * \param strFeatureName The feature name to translate. * \return Translated button/feature id. */ static libretro_device_t GetLibretroDevice(const std::string& strLibretroFeature); /*! * \brief Translate identifiers to feature name (libretro buttonmap "mapto" field). * \param type The libretro device type * \param index The libretro index * \param id The libretro ID * \return Translated feature name */ static const char* GetFeatureName(libretro_device_t type, unsigned int index, unsigned int id); /*! * \brief Translate identifiers to component name of a feature, e.g. individual axes * \param type The libretro device type * \param index The libretro index * \param id The libretro ID * \return Translated name of a feature's component */ static const char* GetComponentName(libretro_device_t type, unsigned int index, unsigned int id); /*! * \brief Translate libretro axis ID (libretro buttonmap "axis" field) to axis ID value in libretro.h * \param axisId The axis ID * \return Translated value of the axis ID */ static int GetAxisID(const std::string& axisId); /*! * \brief Translate rumble motor name (libretro) to string representation (e.g. for logging). * \param effect The rumble motor name to translate. * \return String representation of rumble motor name. */ static std::string GetMotorName(retro_rumble_effect effect); /*! * \brief Translate key modifiers (Game API to libretro). * \param modifiers The key modifiers to translate (e.g. Shift, Ctrl). * \return Translated key modifiers. */ static retro_mod GetKeyModifiers(GAME_KEY_MOD modifiers); }; } game.libretro-20.2.4-Nexus/src/libretro/MemoryMap.cpp000066400000000000000000000053501445145641500224700ustar00rootroot00000000000000/* * Copyright (C) 2014-2020 Team Kodi (https://kodi.tv) * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSE.md for more information. */ #include "MemoryMap.h" using namespace LIBRETRO; void CMemoryMap::Initialize(const retro_memory_map& mmap) { for (unsigned int i = 0; i < mmap.num_descriptors; i++) m_mmap.push_back({mmap.descriptors[i], 0}); PreprocessDescriptors(); } const retro_memory_descriptor_kodi& CMemoryMap::operator[](int index) const { return m_mmap[index]; } size_t CMemoryMap::Size() const { return m_mmap.size(); } bool CMemoryMap::PreprocessDescriptors() { size_t top_addr = 1; for (auto& desc : m_mmap) { if (desc.descriptor.select != 0) top_addr |= desc.descriptor.select; else top_addr |= desc.descriptor.start + desc.descriptor.len - 1; } top_addr = AddBitsDown(top_addr); for (auto& desc : m_mmap) { if (desc.descriptor.select == 0) { if (desc.descriptor.len == 0) return false; if ((desc.descriptor.len & (desc.descriptor.len - 1)) != 0) return false; desc.descriptor.select = top_addr & ~Inflate(AddBitsDown(desc.descriptor.len - 1), desc.descriptor.disconnect); } if (desc.descriptor.len == 0) { desc.descriptor.len = AddBitsDown(Reduce(top_addr & ~desc.descriptor.select, desc.descriptor.disconnect)) + 1; } if (desc.descriptor.start & ~desc.descriptor.select) return false; while (Reduce(top_addr & ~desc.descriptor.select, desc.descriptor.disconnect) >> 1 > desc.descriptor.len - 1) { desc.descriptor.disconnect |= HighestBit(top_addr & ~desc.descriptor.select & ~desc.descriptor.disconnect); } desc.disconnectMask = AddBitsDown(desc.descriptor.len - 1); desc.descriptor.disconnect &= desc.disconnectMask; while ((~desc.disconnectMask) >> 1 & desc.descriptor.disconnect) { desc.disconnectMask >>= 1; desc.descriptor.disconnect &= desc.disconnectMask; } } return true; } size_t CMemoryMap::AddBitsDown(size_t num) { num |= num >> 1; num |= num >> 2; num |= num >> 4; num |= num >> 8; num |= num >> 16; if (sizeof(size_t) > 4) num |= num >> 16 >> 16; return num; } size_t CMemoryMap::Inflate(size_t addr, size_t mask) { while (mask) { size_t tmp = (mask - 1) & ~mask; addr = ((addr & ~tmp) << 1) | (addr & tmp); mask = mask & (mask - 1); } return addr; } size_t CMemoryMap::Reduce(size_t addr, size_t mask) { while (mask) { size_t tmp = (mask - 1) & ~mask; addr = (addr & tmp) | ((addr >> 1) & ~tmp); mask = (mask & (mask - 1)) >> 1; } return addr; } size_t CMemoryMap::HighestBit(size_t num) { num = AddBitsDown(num); return num ^ (num >> 1); } game.libretro-20.2.4-Nexus/src/libretro/MemoryMap.h000066400000000000000000000014311445145641500221310ustar00rootroot00000000000000/* * Copyright (C) 2014-2020 Team Kodi (https://kodi.tv) * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSE.md for more information. */ #pragma once #include #include "libretro-common/libretro.h" struct retro_memory_descriptor_kodi { retro_memory_descriptor descriptor; size_t disconnectMask; }; namespace LIBRETRO { class CMemoryMap { public: void Initialize(const retro_memory_map& mmap); const retro_memory_descriptor_kodi& operator[](int index) const; size_t Size() const; private: bool PreprocessDescriptors(); size_t AddBitsDown(size_t num); size_t Inflate(size_t addr, size_t mask); size_t Reduce(size_t addr, size_t mask); size_t HighestBit(size_t num); std::vector m_mmap; }; } // namespace LIBRETRO game.libretro-20.2.4-Nexus/src/log/000077500000000000000000000000001445145641500170125ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/src/log/ILog.h000066400000000000000000000015471445145641500200240ustar00rootroot00000000000000/* * Copyright (C) 2014-2021 Team Kodi (https://kodi.tv) * Portions Copyright (C) 2013-2014 Lars Op den Kamp * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSE.md for more information. */ #pragma once namespace LIBRETRO { enum SYS_LOG_LEVEL { SYS_LOG_NONE = 0, SYS_LOG_ERROR, SYS_LOG_INFO, SYS_LOG_DEBUG }; enum SYS_LOG_TYPE { SYS_LOG_TYPE_NULL, // Discard log SYS_LOG_TYPE_CONSOLE, // Log to stdout SYS_LOG_TYPE_ADDON // Log to frontend }; /*! * \brief Logging interface */ class ILog { public: virtual ~ILog(void) { } /*! * \brief Send a message to the log */ virtual void Log(SYS_LOG_LEVEL level, const char* logline) = 0; /*! * \brief Get the type of logging used in the implementation */ virtual SYS_LOG_TYPE Type(void) const = 0; }; } game.libretro-20.2.4-Nexus/src/log/Log.cpp000066400000000000000000000047161445145641500202470ustar00rootroot00000000000000/* * Copyright (C) 2014-2021 Team Kodi (https://kodi.tv) * Portions Copyright (C) 2013-2014 Lars Op den Kamp * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSE.md for more information. */ #include "Log.h" #include "LogAddon.h" #include "LogConsole.h" #include #include using namespace LIBRETRO; #define SYS_LOG_BUFFER_SIZE 256 // bytes CLog::CLog(ILog* pipe) : m_pipe(pipe), m_level(SYS_LOG_DEBUG) { } CLog& CLog::Get(void) { static CLog _instance(new CLogConsole); return _instance; } CLog::~CLog(void) { SetPipe(nullptr); } bool CLog::SetType(SYS_LOG_TYPE type) { std::unique_lock lock(m_mutex); if (m_pipe && m_pipe->Type() == type) return true; // Already set switch (type) { case SYS_LOG_TYPE_CONSOLE: SetPipe(new CLogConsole); break; case SYS_LOG_TYPE_NULL: SetPipe(nullptr); break; case SYS_LOG_TYPE_ADDON: SetPipe(new CLogAddon); break; default: Log(SYS_LOG_ERROR, "Failed to set log type to %s", TypeToString(type)); return false; } return true; } void CLog::SetPipe(ILog* pipe) { delete m_pipe; m_pipe = pipe; } void CLog::SetLevel(SYS_LOG_LEVEL level) { std::unique_lock lock(m_mutex); m_level = level; } void CLog::SetLogPrefix(const std::string& strLogPrefix) { m_strLogPrefix = strLogPrefix; } void CLog::Log(SYS_LOG_LEVEL level, const char* format, ...) { std::string strLogPrefix; if (m_pipe && m_pipe->Type() == SYS_LOG_TYPE_CONSOLE) strLogPrefix = GetLogPrefix(level) + m_strLogPrefix; else strLogPrefix = m_strLogPrefix; char fmt[SYS_LOG_BUFFER_SIZE]; char buf[SYS_LOG_BUFFER_SIZE]; va_list ap; va_start(ap, format); snprintf(fmt, sizeof(fmt), "%s%s", strLogPrefix.c_str(), format); vsnprintf(buf, SYS_LOG_BUFFER_SIZE - 1, fmt, ap); va_end(ap); std::unique_lock lock(m_mutex); if (level > m_level) return; if (m_pipe) m_pipe->Log(level, buf); } const char* CLog::TypeToString(SYS_LOG_TYPE type) { switch (type) { case SYS_LOG_TYPE_NULL: return "null"; case SYS_LOG_TYPE_CONSOLE: return "console"; case SYS_LOG_TYPE_ADDON: return "addon"; default: return "unknown"; } } const char* CLog::GetLogPrefix(SYS_LOG_LEVEL level) { switch (level) { case SYS_LOG_ERROR: return "[ERROR] "; case SYS_LOG_INFO: return "[INFO] "; case SYS_LOG_DEBUG: return "[DEBUG] "; case SYS_LOG_NONE: default: return "[?????] "; } } game.libretro-20.2.4-Nexus/src/log/Log.h000066400000000000000000000026461445145641500177140ustar00rootroot00000000000000/* * Copyright (C) 2014-2021 Team Kodi (https://kodi.tv) * Portions Copyright (C) 2013-2014 Lars Op den Kamp * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSE.md for more information. */ #pragma once #include "ILog.h" #include #include // --- Shorthand logging ------------------------------------------------------- #ifndef esyslog #define esyslog(...) LIBRETRO::CLog::Get().Log(SYS_LOG_ERROR, __VA_ARGS__) #endif #ifndef isyslog #define isyslog(...) LIBRETRO::CLog::Get().Log(SYS_LOG_INFO, __VA_ARGS__) #endif #ifndef dsyslog #define dsyslog(...) LIBRETRO::CLog::Get().Log(SYS_LOG_DEBUG, __VA_ARGS__) #endif #define LOG_ERROR_STR(str) esyslog("ERROR (%s, %d): %s: %m", __FILE__, __LINE__, str) // --- CLog -------------------------------------------------------------------- namespace LIBRETRO { class CLog { private: CLog(ILog* pipe); public: static CLog& Get(void); ~CLog(void); bool SetType(SYS_LOG_TYPE type); void SetLevel(SYS_LOG_LEVEL level); void SetLogPrefix(const std::string& strLogPrefix); void Log(SYS_LOG_LEVEL level, const char* format, ...); static const char* TypeToString(SYS_LOG_TYPE type); private: void SetPipe(ILog* pipe); static const char* GetLogPrefix(SYS_LOG_LEVEL level); ILog* m_pipe; SYS_LOG_LEVEL m_level; std::string m_strLogPrefix; std::mutex m_mutex; }; } game.libretro-20.2.4-Nexus/src/log/LogAddon.cpp000066400000000000000000000015371445145641500212130ustar00rootroot00000000000000/* * Copyright (C) 2014-2021 Team Kodi (https://kodi.tv) * Portions Copyright (C) 2013-2014 Lars Op den Kamp * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSE.md for more information. */ #include "LogAddon.h" #include #include using namespace LIBRETRO; // --- TranslateLogLevel() ----------------------------------------------------- ADDON_LOG TranslateLogLevel(SYS_LOG_LEVEL level) { switch (level) { case SYS_LOG_ERROR: return ADDON_LOG_ERROR; case SYS_LOG_INFO: return ADDON_LOG_INFO; case SYS_LOG_DEBUG: return ADDON_LOG_DEBUG; default: break; } return ADDON_LOG_INFO; } // -- CLogAddon ---------------------------------------------------------------- void CLogAddon::Log(SYS_LOG_LEVEL level, const char* logline) { kodi::Log(TranslateLogLevel(level), "%s", logline); } game.libretro-20.2.4-Nexus/src/log/LogAddon.h000066400000000000000000000010371445145641500206530ustar00rootroot00000000000000/* * Copyright (C) 2014-2021 Team Kodi (https://kodi.tv) * Portions Copyright (C) 2013-2014 Lars Op den Kamp * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSE.md for more information. */ #pragma once #include "ILog.h" namespace LIBRETRO { class CLogAddon : public ILog { public: CLogAddon() = default; virtual ~CLogAddon(void) { } // implementation of ILog virtual void Log(SYS_LOG_LEVEL level, const char* logline); virtual SYS_LOG_TYPE Type(void) const { return SYS_LOG_TYPE_ADDON; } }; } game.libretro-20.2.4-Nexus/src/log/LogConsole.cpp000066400000000000000000000007211445145641500215620ustar00rootroot00000000000000/* * Copyright (C) 2014-2021 Team Kodi (https://kodi.tv) * Portions Copyright (C) 2013-2014 Lars Op den Kamp * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSE.md for more information. */ #include "LogConsole.h" #include using namespace LIBRETRO; void CLogConsole::Log(SYS_LOG_LEVEL level, const char* logline) { std::unique_lock lock(m_mutex); // TODO: Prepend current date std::cout << logline << std::endl; } game.libretro-20.2.4-Nexus/src/log/LogConsole.h000066400000000000000000000011001445145641500212170ustar00rootroot00000000000000/* * Copyright (C) 2014-2021 Team Kodi (https://kodi.tv) * Portions Copyright (C) 2013-2014 Lars Op den Kamp * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSE.md for more information. */ #pragma once #include "ILog.h" #include namespace LIBRETRO { class CLogConsole : public ILog { public: virtual ~CLogConsole(void) { } // implementation of ILog virtual void Log(SYS_LOG_LEVEL level, const char* logline); virtual SYS_LOG_TYPE Type(void) const { return SYS_LOG_TYPE_CONSOLE; } private: std::mutex m_mutex; }; } game.libretro-20.2.4-Nexus/src/settings/000077500000000000000000000000001445145641500200715ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/src/settings/LanguageGenerator.cpp000066400000000000000000000045151445145641500241740ustar00rootroot00000000000000/* * Copyright (C) 2016-2021 Team Kodi (https://kodi.tv) * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSE.md for more information. */ #include "LanguageGenerator.h" #include using namespace LIBRETRO; CLanguageGenerator::CLanguageGenerator(const std::string& addonId, const std::string& generatedDir) : m_strAddonId(addonId) { m_strFilePath = generatedDir + "/" SETTINGS_GENERATED_LANGUAGE_NAME; } bool CLanguageGenerator::GenerateLanguage(const LibretroSettings& settings) { if (m_strAddonId.empty()) return false; std::ofstream file(m_strFilePath, std::ios::trunc); if (!file.is_open()) return false; file << "# " << m_strAddonId << " language file" << std::endl; file << "# Addon Name: " << m_strAddonId << std::endl; file << "# Addon id: " << m_strAddonId << std::endl; file << "# Addon Provider: libretro" << std::endl; file << "msgid \"\"" << std::endl; file << "msgstr \"\"" << std::endl; file << "\"Project-Id-Version: " << m_strAddonId << "\\n\"" << std::endl; file << "\"Report-Msgid-Bugs-To: translations@kodi.tv\\n\"" << std::endl; file << "\"POT-Creation-Date: 2016-10-25 17:00+8\\n\"" << std::endl; file << "\"PO-Revision-Date: 2016-10-25 17:00+8\\n\"" << std::endl; file << "\"Last-Translator: Kodi Translation Team\\n\"" << std::endl; file << "\"Language-Team: English (United Kingdom) (https://kodi.weblate.cloud/languages/en_gb/)\\n\"" << std::endl; file << "\"MIME-Version: 1.0\\n\"" << std::endl; file << "\"Content-Type: text/plain; charset=UTF-8\\n\"" << std::endl; file << "\"Content-Transfer-Encoding: 8bit\\n\"" << std::endl; file << "\"Language: en\\n\"" << std::endl; file << "\"Plural-Forms: nplurals=2; plural=(n != 1);\\n\"" << std::endl; file << std::endl; unsigned int settingId = SETTING_ID_START; // Category name file << "msgctxt \"#" << settingId++ << "\"" << std::endl; file << "msgid \"Settings\"" << std::endl; file << "msgstr \"\"" << std::endl; file << std::endl; for (const auto& setting : settings) { // TODO: xml-encode description const std::string& description = setting.second.Description(); file << "msgctxt \"#" << settingId++ << "\"" << std::endl; file << "msgid \"" << description << "\"" << std::endl; file << "msgstr \"\"" << std::endl; file << std::endl; } file.close(); return true; } game.libretro-20.2.4-Nexus/src/settings/LanguageGenerator.h000066400000000000000000000007701445145641500236400ustar00rootroot00000000000000/* * Copyright (C) 2016-2021 Team Kodi (https://kodi.tv) * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSE.md for more information. */ #pragma once #include "SettingsTypes.h" #include namespace LIBRETRO { class CLanguageGenerator { public: CLanguageGenerator(const std::string& addonId, const std::string& generatedDir); bool GenerateLanguage(const LibretroSettings& settings); private: std::string m_strAddonId; std::string m_strFilePath; }; } game.libretro-20.2.4-Nexus/src/settings/LibretroSetting.cpp000066400000000000000000000051641445145641500237230ustar00rootroot00000000000000/* * Copyright (C) 2016-2021 Team Kodi (https://kodi.tv) * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSE.md for more information. */ #include "LibretroSetting.h" #include "libretro-common/libretro.h" using namespace LIBRETRO; CLibretroSetting::CLibretroSetting(const retro_variable* libretroVariable) : m_key(libretroVariable->key) { Parse(libretroVariable->value); SetCurrentValue(DefaultValue()); } const std::string& CLibretroSetting::DefaultValue() const { static std::string empty; if (!m_values.empty()) return m_values[0]; return empty; } void CLibretroSetting::Parse(const std::string& libretroValue) { // Example retro_variable: // { "foo_option", "Speed hack coprocessor X; false|true" } // // Text before first ';' is description. This ';' must be followed by // a space, and followed by a list of possible values split up with '|'. // First, Split the string into description and value list auto SplitDescription = [](const std::string& retroVal, std::string& description, std::string& values) { // Look for ; separating the description from the pipe-separated values size_t pos; if ((pos = retroVal.find(';')) != std::string::npos) { // Set description description = retroVal.substr(0, pos); // Advance past semicolon pos++; // Advance past spaces while (pos < retroVal.size() && retroVal[pos] == ' ') pos++; // Set values values = retroVal.substr(pos); } else { // No semicolon found values = retroVal; } }; std::string strDescription; std::string strValues; SplitDescription(libretroValue, strDescription, strValues); if (strDescription.empty()) { // Use key name as a backup strDescription = m_key; } // Split the values on | delimiter auto SplitValues = [](const std::string& strValues, std::vector& vecValues) { std::string remainingValues = strValues; while (!remainingValues.empty()) { std::string strValue; size_t pos; if ((pos = remainingValues.find('|')) == std::string::npos) { strValue = remainingValues; remainingValues.clear(); } else { strValue = remainingValues.substr(0, pos); remainingValues.erase(0, pos + 1); } vecValues.push_back(strValue); } }; std::vector vecValues; SplitValues(strValues, vecValues); m_description = std::move(strDescription); m_values = std::move(vecValues); m_valuesStr = std::move(strValues); } game.libretro-20.2.4-Nexus/src/settings/LibretroSetting.h000066400000000000000000000024121445145641500233610ustar00rootroot00000000000000/* * Copyright (C) 2016-2021 Team Kodi (https://kodi.tv) * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSE.md for more information. */ #pragma once #include #include struct retro_variable; namespace LIBRETRO { class CLibretroSetting { public: CLibretroSetting(const retro_variable* libretroVariable); const std::string& Key() const { return m_key; } const std::string& Description() const { return m_description; } const std::vector& Values() const { return m_values; } const std::string& ValuesStr() const { return m_valuesStr; } // Original pipe-deliminated values string const std::string& CurrentValue() const { return m_currentValue; } // The libretro API defaults the setting to its first value const std::string& DefaultValue() const; void SetCurrentValue(const std::string& newValue) { m_currentValue = newValue; } private: void Parse(const std::string& libretroValue); std::string m_key; std::string m_description; std::vector m_values; std::string m_valuesStr; std::string m_currentValue; }; } // namespace LIBRETRO game.libretro-20.2.4-Nexus/src/settings/LibretroSettings.cpp000066400000000000000000000125331445145641500241040ustar00rootroot00000000000000/* * Copyright (C) 2016-2021 Team Kodi (https://kodi.tv) * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSE.md for more information. */ #include "LibretroSettings.h" #include "LanguageGenerator.h" #include "SettingsGenerator.h" #include "libretro-common/libretro.h" #include "log/Log.h" #include "client.h" #include #include #include #include using namespace LIBRETRO; CLibretroSettings::CLibretroSettings() : m_addon(nullptr), m_bChanged(true), m_bGenerated(false) { } void CLibretroSettings::Initialize(CGameLibRetro* addon) { m_addon = addon; assert(m_addon != nullptr); m_profileDirectory = m_addon->ProfileDirectory(); } void CLibretroSettings::Deinitialize() { m_addon = nullptr; } bool CLibretroSettings::Changed() { std::unique_lock lock(m_mutex); return m_bChanged; } void CLibretroSettings::SetUnchanged() { std::unique_lock lock(m_mutex); m_bChanged = false; } void CLibretroSettings::SetAllSettings(const retro_variable* libretroVariables) { // Keep track of whether Kodi has the correct settings bool bValid = true; std::unique_lock lock(m_mutex); if (m_settings.empty()) { for (const retro_variable* variable = libretroVariables; variable && variable->key && variable->value; variable++) { CLibretroSetting setting(variable); if (setting.Values().empty()) { esyslog("Setting \"%s\": No pipe-delimited options: \"%s\"", variable->key, variable->value); continue; } // Query current value for setting from the frontend std::string valueBuf; if (kodi::addon::CheckSettingString(variable->key, valueBuf)) { if (std::find(setting.Values().begin(), setting.Values().end(), valueBuf) != setting.Values().end()) { dsyslog("Setting %s has value \"%s\" in Kodi", setting.Key().c_str(), valueBuf.c_str()); setting.SetCurrentValue(valueBuf); } else { esyslog("Setting %s: invalid value \"%s\" (values are: %s)", setting.Key().c_str(), valueBuf.c_str(), variable->value); bValid = false; } } else { esyslog("Setting %s not found by Kodi", setting.Key().c_str()); bValid = false; } m_settings.insert(std::make_pair(setting.Key(), std::move(setting))); } m_bChanged = true; } if (!bValid) GenerateSettings(); } const char* CLibretroSettings::GetCurrentValue(const std::string& settingName) { std::unique_lock lock(m_mutex); auto it = m_settings.find(settingName); if (it == m_settings.end()) { esyslog("Unknown setting ID: %s", settingName.c_str()); return ""; } return it->second.CurrentValue().c_str(); } void CLibretroSettings::SetCurrentValue(const std::string& name, const std::string& value) { std::unique_lock lock(m_mutex); if (m_settings.empty()) { // RETRO_ENVIRONMENT_SET_VARIABLES hasn't been called yet. We don't need to // record the setting now because it will be retrieved from the frontend // later. return; } // Keep track of whether Kodi has the correct settings bool bValid = true; // Check to make sure value is a valid value reported by libretro auto it = m_settings.find(name); if (it == m_settings.end()) { esyslog("Kodi setting %s unknown to libretro!", name.c_str()); bValid = false; } else if (it->second.CurrentValue() != value) { it->second.SetCurrentValue(value); m_bChanged = true; } if (!bValid) GenerateSettings(); } void CLibretroSettings::GenerateSettings() { if (!m_bGenerated && !m_settings.empty()) { isyslog("Invalid settings detected, generating new settings and language files"); std::string generatedPath = m_profileDirectory; std::string addonId = kodi::vfs::GetFileName(generatedPath); generatedPath += "/" SETTINGS_GENERATED_DIRECTORY_NAME; // Ensure folder exists if (!kodi::vfs::DirectoryExists(generatedPath)) { dsyslog("Creating directory for settings and language files: %s", generatedPath.c_str()); kodi::vfs::CreateDirectory(generatedPath); } bool bSuccess = false; CSettingsGenerator settingsGen(generatedPath); if (!settingsGen.GenerateSettings(m_settings)) esyslog("Failed to generate %s", SETTINGS_GENERATED_SETTINGS_NAME); else bSuccess = true; generatedPath += "/" SETTINGS_GENERATED_LANGUAGE_SUBDIR; // Ensure language folder exists if (!kodi::vfs::DirectoryExists(generatedPath)) { dsyslog("Creating directory for settings and language files: %s", generatedPath.c_str()); kodi::vfs::CreateDirectory(generatedPath); } generatedPath += "/" SETTINGS_GENERATED_LANGUAGE_ENGLISH_SUBDIR; // Ensure English folder exists if (!kodi::vfs::DirectoryExists(generatedPath)) { dsyslog("Creating directory for settings and language files: %s", generatedPath.c_str()); kodi::vfs::CreateDirectory(generatedPath); } CLanguageGenerator languageGen(addonId, generatedPath); if (!languageGen.GenerateLanguage(m_settings)) esyslog("Failed to generate %s", SETTINGS_GENERATED_LANGUAGE_NAME); else bSuccess = true; if (bSuccess) isyslog("Settings and language files have been placed in %s", generatedPath.c_str()); m_bGenerated = true; } } game.libretro-20.2.4-Nexus/src/settings/LibretroSettings.h000066400000000000000000000022601445145641500235450ustar00rootroot00000000000000/* * Copyright (C) 2016-2021 Team Kodi (https://kodi.tv) * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSE.md for more information. */ #pragma once #include "SettingsTypes.h" #include #include #include class CGameLibRetro; struct retro_variable; namespace LIBRETRO { class CLibretroSettings { public: CLibretroSettings(); void Initialize(CGameLibRetro* addon); void Deinitialize(); bool Changed(); void SetUnchanged(); void SetAllSettings(const retro_variable* libretroVariables); const char* GetCurrentValue(const std::string& settingName); void SetCurrentValue(const std::string& name, const std::string& value); private: /*! * \brief Generate settings and language files for Kodi */ void GenerateSettings(); // Frontend variables CGameLibRetro* m_addon; std::string m_profileDirectory; // Settings variables LibretroSettings m_settings; bool m_bChanged; bool m_bGenerated; // True if settings and language files have been generated std::mutex m_mutex; }; } // namespace LIBRETRO game.libretro-20.2.4-Nexus/src/settings/Settings.cpp000066400000000000000000000013461445145641500224010ustar00rootroot00000000000000/* * Copyright (C) 2016-2021 Team Kodi (https://kodi.tv) * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSE.md for more information. */ #include "Settings.h" using namespace LIBRETRO; #define SETTING_CROP_OVERSCAN "cropoverscan" CSettings::CSettings(void) : m_bInitialized(false), m_bCropOverscan(false) { } CSettings& CSettings::Get(void) { static CSettings _instance; return _instance; } void CSettings::SetSetting(const std::string& strName, const kodi::addon::CSettingValue& value) { if (strName == SETTING_CROP_OVERSCAN) { m_bCropOverscan = value.GetBoolean(); //dsyslog("Setting \"%s\" set to %f", SETTING_CROP_OVERSCAN, m_bCropOverscan ? "true" : "false"); } m_bInitialized = true; } game.libretro-20.2.4-Nexus/src/settings/Settings.h000066400000000000000000000012741445145641500220460ustar00rootroot00000000000000/* * Copyright (C) 2016-2021 Team Kodi (https://kodi.tv) * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSE.md for more information. */ #pragma once #include #include namespace LIBRETRO { class CSettings { private: CSettings(void); public: static CSettings& Get(void); bool IsInitialized(void) const { return m_bInitialized; } void SetSetting(const std::string& strName, const kodi::addon::CSettingValue& value); /*! * \brief True if the libretro core should crop overscan */ bool CropOverscan(void) const { return m_bCropOverscan; } private: bool m_bInitialized; bool m_bCropOverscan; }; } game.libretro-20.2.4-Nexus/src/settings/SettingsGenerator.cpp000066400000000000000000000024421445145641500242460ustar00rootroot00000000000000/* * Copyright (C) 2016-2021 Team Kodi (https://kodi.tv) * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSE.md for more information. */ #include "SettingsGenerator.h" #include using namespace LIBRETRO; CSettingsGenerator::CSettingsGenerator(const std::string& generatedDir) { m_strFilePath = generatedDir + "/" SETTINGS_GENERATED_SETTINGS_NAME; } bool CSettingsGenerator::GenerateSettings(const LibretroSettings& settings) { std::ofstream file(m_strFilePath, std::ios::trunc); if (!file.is_open()) return false; unsigned int settingId = SETTING_ID_START; file << "" << std::endl; file << "" << std::endl; file << "\t" << std::endl; for (const auto& setting : settings) { const std::string& key = setting.first; const std::string& strValues = setting.second.ValuesStr(); const std::string& defaultValue = setting.second.DefaultValue(); file << "\t\t" << std::endl; } file << "\t" << std::endl; file << "" << std::endl; file.close(); return true; } game.libretro-20.2.4-Nexus/src/settings/SettingsGenerator.h000066400000000000000000000006761445145641500237220ustar00rootroot00000000000000/* * Copyright (C) 2016-2021 Team Kodi (https://kodi.tv) * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSE.md for more information. */ #pragma once #include "SettingsTypes.h" #include namespace LIBRETRO { class CSettingsGenerator { public: CSettingsGenerator(const std::string& generatedDir); bool GenerateSettings(const LibretroSettings& settings); private: std::string m_strFilePath; }; } game.libretro-20.2.4-Nexus/src/settings/SettingsTypes.h000066400000000000000000000016141445145641500230710ustar00rootroot00000000000000/* * Copyright (C) 2016-2021 Team Kodi (https://kodi.tv) * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSE.md for more information. */ #pragma once #include "LibretroSetting.h" #include #include /*! * \brief Directory name for generated settings and language files */ #define SETTINGS_GENERATED_DIRECTORY_NAME "generated" /*! * \brief File name of the generated settings.xml file */ #define SETTINGS_GENERATED_SETTINGS_NAME "settings.xml" /*! * \brief File name and subdirectory of the generated language file */ #define SETTINGS_GENERATED_LANGUAGE_SUBDIR "language" #define SETTINGS_GENERATED_LANGUAGE_ENGLISH_SUBDIR "English" #define SETTINGS_GENERATED_LANGUAGE_NAME "strings.po" #define SETTING_ID_START 30000 namespace LIBRETRO { typedef std::string SettingKey; typedef std::map LibretroSettings; } game.libretro-20.2.4-Nexus/src/utils/000077500000000000000000000000001445145641500173715ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/src/utils/Timer.cpp000066400000000000000000000005761445145641500211650ustar00rootroot00000000000000/* * Copyright (C) 2014-2021 Team Kodi (https://kodi.tv) * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSE.md for more information. */ #include "Timer.h" using namespace LIBRETRO; uint64_t Timer::microseconds() { const auto currenttime = m_clock.now().time_since_epoch(); return std::chrono::duration_cast(currenttime).count(); } game.libretro-20.2.4-Nexus/src/utils/Timer.h000066400000000000000000000007341445145641500206260ustar00rootroot00000000000000/* * Copyright (C) 2018-2021 Team Kodi (https://kodi.tv) * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSE.md for more information. */ #pragma once #include #include namespace LIBRETRO { /*! * \brief Utility to get the current time. */ class Timer { public: /*! * \brief Returns current time in microseconds. */ uint64_t microseconds(); private: std::chrono::high_resolution_clock m_clock; }; } game.libretro-20.2.4-Nexus/src/video/000077500000000000000000000000001445145641500173375ustar00rootroot00000000000000game.libretro-20.2.4-Nexus/src/video/VideoGeometry.cpp000066400000000000000000000011661445145641500226310ustar00rootroot00000000000000/* * Copyright (C) 2018-2021 Team Kodi (https://kodi.tv) * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSE.md for more information. */ #include "VideoGeometry.h" #include "libretro-common/libretro.h" using namespace LIBRETRO; CVideoGeometry::CVideoGeometry(const retro_game_geometry &geometry) { UpdateVideoGeometry(geometry); } void CVideoGeometry::UpdateVideoGeometry(const retro_game_geometry &geometry) { m_nominalWidth = geometry.base_width; m_nominalHeight = geometry.base_height; m_maxWidth = geometry.max_width; m_maxHeight = geometry.max_height; m_aspectRatio = geometry.aspect_ratio; } game.libretro-20.2.4-Nexus/src/video/VideoGeometry.h000066400000000000000000000016751445145641500223030ustar00rootroot00000000000000/* * Copyright (C) 2018-2021 Team Kodi (https://kodi.tv) * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSE.md for more information. */ #pragma once struct retro_game_geometry; namespace LIBRETRO { class CVideoGeometry { public: CVideoGeometry() = default; CVideoGeometry(CVideoGeometry&) = default; CVideoGeometry(const retro_game_geometry &geometry); void UpdateVideoGeometry(const retro_game_geometry &geometry); unsigned int NominalWidth() const { return m_nominalWidth; } unsigned int NominalHeight() const { return m_nominalHeight; } unsigned int MaxWidth() const { return m_maxWidth; } unsigned int MaxHeight() const { return m_maxHeight; } float AspectRatio() const { return m_aspectRatio; } private: unsigned int m_nominalWidth = 0; unsigned int m_nominalHeight = 0; unsigned int m_maxWidth = 0; unsigned int m_maxHeight = 0; float m_aspectRatio = 0.0f; }; } game.libretro-20.2.4-Nexus/src/video/VideoStream.cpp000066400000000000000000000121401445145641500222630ustar00rootroot00000000000000/* * Copyright (C) 2016-2021 Team Kodi (https://kodi.tv) * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSE.md for more information. */ #include "VideoStream.h" #include "VideoGeometry.h" #include "libretro/LibretroEnvironment.h" #include "client.h" using namespace LIBRETRO; CVideoStream::CVideoStream() : m_addon(nullptr), m_geometry(new CVideoGeometry) { } void CVideoStream::Initialize(CGameLibRetro* addon) { m_addon = addon; } void CVideoStream::Deinitialize() { if (m_addon == nullptr) return; CloseStream(); m_addon = nullptr; } void CVideoStream::SetGeometry(const CVideoGeometry &geometry) { // Close stream so it can be reopened with the updated geometry if (m_addon != nullptr) CloseStream(); *m_geometry = geometry; } bool CVideoStream::EnableHardwareRendering(const game_stream_hw_framebuffer_properties &properties) { if (m_addon == nullptr) return false; CloseStream(); game_stream_properties streamProps{}; streamProps.type = GAME_STREAM_HW_FRAMEBUFFER; streamProps.hw_framebuffer = properties; if (!m_stream.Open(streamProps)) return false; m_streamType = GAME_STREAM_HW_FRAMEBUFFER; return true; } uintptr_t CVideoStream::GetHwFramebuffer() { if (m_addon == nullptr) return 0; if (!m_stream.IsOpen() || m_streamType != GAME_STREAM_HW_FRAMEBUFFER) return 0; if (!m_framebuffer) { m_framebuffer.reset(new game_stream_buffer{}); if (!m_stream.GetBuffer(0, 0, *m_framebuffer)) return 0; } return m_framebuffer->hw_framebuffer.framebuffer; } bool CVideoStream::GetSwFramebuffer(unsigned int width, unsigned int height, GAME_PIXEL_FORMAT requestedFormat, game_stream_sw_framebuffer_buffer &framebuffer) { if (m_addon == nullptr) return false; if (!m_stream.IsOpen()) { game_stream_properties properties{}; properties.type = GAME_STREAM_SW_FRAMEBUFFER; properties.sw_framebuffer.format = requestedFormat; properties.sw_framebuffer.nominal_width = m_geometry->NominalWidth(); properties.sw_framebuffer.nominal_height = m_geometry->NominalHeight(); properties.sw_framebuffer.max_width = m_geometry->MaxWidth(); properties.sw_framebuffer.max_height = m_geometry->MaxHeight(); properties.sw_framebuffer.aspect_ratio = m_geometry->AspectRatio(); m_stream.Open(properties); m_streamType = GAME_STREAM_SW_FRAMEBUFFER; } if (!m_stream.IsOpen() || m_streamType != GAME_STREAM_SW_FRAMEBUFFER) return false; if (!m_framebuffer) { m_framebuffer.reset(new game_stream_buffer{}); if (!m_stream.GetBuffer(width, height, *m_framebuffer)) return false; } framebuffer = m_framebuffer->sw_framebuffer; return true; } void CVideoStream::AddFrame(const uint8_t* data, unsigned int size, unsigned int width, unsigned int height, GAME_PIXEL_FORMAT format, GAME_VIDEO_ROTATION rotation) { if (m_addon == nullptr) return; // Only care if format changes for video stream if (m_streamType == GAME_STREAM_VIDEO) { if (m_format != format) { // Close stream so it can be reopened with the updated format CloseStream(); } } if (!m_stream.IsOpen()) { game_stream_properties properties{}; properties.type = GAME_STREAM_VIDEO; properties.video.format = format; properties.video.nominal_width = m_geometry->NominalWidth(); properties.video.nominal_height = m_geometry->NominalHeight(); properties.video.max_width = m_geometry->MaxWidth(); properties.video.max_height = m_geometry->MaxHeight(); properties.video.aspect_ratio = m_geometry->AspectRatio(); m_stream.Open(properties); m_streamType = GAME_STREAM_VIDEO; // Save format to detect unwanted changes m_format = format; } if (!m_stream.IsOpen()) return; game_stream_packet packet{}; switch (m_streamType) { case GAME_STREAM_VIDEO: { packet.type = GAME_STREAM_VIDEO; packet.video.width = width; packet.video.height = height; packet.video.rotation = rotation; packet.video.data = data; packet.video.size = size; break; } case GAME_STREAM_SW_FRAMEBUFFER: { packet.type = GAME_STREAM_SW_FRAMEBUFFER; packet.sw_framebuffer.width = width; packet.sw_framebuffer.height = height; packet.sw_framebuffer.rotation = rotation; packet.sw_framebuffer.data = data; packet.sw_framebuffer.size = size; break; } default: return; } m_stream.AddData(packet); } void CVideoStream::RenderHwFrame() { if (m_addon == nullptr) return; if (!m_stream.IsOpen() || m_streamType != GAME_STREAM_HW_FRAMEBUFFER) return; if (!m_framebuffer) return; game_stream_packet packet{}; packet.type = GAME_STREAM_HW_FRAMEBUFFER; packet.hw_framebuffer.framebuffer = m_framebuffer->hw_framebuffer.framebuffer; m_stream.AddData(packet); } void CVideoStream::OnFrameEnd() { if (m_addon == nullptr) return; if (!m_stream.IsOpen()) return; if (!m_framebuffer) return; m_stream.ReleaseBuffer(*m_framebuffer); m_framebuffer.reset(); } void CVideoStream::CloseStream() { if (m_stream.IsOpen()) { m_stream.Close(); m_format = GAME_PIXEL_FORMAT_UNKNOWN; } } game.libretro-20.2.4-Nexus/src/video/VideoStream.h000066400000000000000000000027071445145641500217400ustar00rootroot00000000000000/* * Copyright (C) 2016-2021 Team Kodi (https://kodi.tv) * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSE.md for more information. */ #pragma once #include #include #include class CGameLibRetro; namespace LIBRETRO { class CVideoGeometry; class ATTR_DLL_LOCAL CVideoStream { public: CVideoStream(); void Initialize(CGameLibRetro* addon); void Deinitialize(); void SetGeometry(const CVideoGeometry &geometry); bool EnableHardwareRendering(const game_stream_hw_framebuffer_properties &properties); uintptr_t GetHwFramebuffer(); bool GetSwFramebuffer(unsigned int width, unsigned int height, GAME_PIXEL_FORMAT requestedFormat, game_stream_sw_framebuffer_buffer &framebuffer); void AddFrame(const uint8_t* data, unsigned int size, unsigned int width, unsigned int height, GAME_PIXEL_FORMAT format, GAME_VIDEO_ROTATION rotation); void DupeFrame() { } // Not supported void RenderHwFrame(); void OnFrameEnd(); private: void CloseStream(); // Initialization parameters CGameLibRetro* m_addon; // Stream properties kodi::addon::CInstanceGame::CStream m_stream; std::unique_ptr m_geometry; GAME_STREAM_TYPE m_streamType = GAME_STREAM_UNKNOWN; GAME_PIXEL_FORMAT m_format = GAME_PIXEL_FORMAT_UNKNOWN; // Guard against libretro changing formats std::unique_ptr m_framebuffer; }; }