kodi-game / game.libretro

Libretro compatibility layer for the Kodi Game API
GNU General Public License v2.0
37 stars 26 forks source link

Multitap fixes #79

Closed garbear closed 2 years ago

garbear commented 2 years ago

Description

This PR joins https://github.com/xbmc/xbmc/pull/20408 to fix Multitaps and get them working in Kodi. It includes fixes, some refactoring, and two features required for Snes9x Multitaps.

Snes9x multitaps behave idiosyncratically, in a way particular to Snes9x cores. Polling for input works normally, where controllers are assigned depth-first to port IDs. For example, if two Multitaps are connected, port assignment traverses the topology depth-first and assigns ports 0-3 to the four controllers on the first multitap, and ports 4-7 to the four controllers on the second multitap.

However, connecting/disconnecting a controller uses a different port identification scheme. Port 0 is used to refer to the hardware port 0. Port 1 is used to refer to the hardware port 1. No other ports are allowed. This is incompatible with the depth-first polling, so a new strategy is needed to handle this idiosyncratic behavior.

To work around this, I added two new fields:

Libretro port ID

Here is the topology.xml file we started with:

<?xml version="1.0" encoding="UTF-8"?>
<logicaltopology>
  <port id="1">
    <accepts controller="game.controller.snes"/>
    <accepts controller="game.controller.snes.mouse"/>
    <accepts controller="game.controller.snes.multitap">
      <port id="1">
        <accepts controller="game.controller.snes"/>
      </port>
      <port id="2">
        <accepts controller="game.controller.snes"/>
      </port>
      <port id="3">
        <accepts controller="game.controller.snes"/>
      </port>
      <port id="4">
        <accepts controller="game.controller.snes"/>
      </port>
    </accepts>
  </port>
  <port id="2">
    <accepts controller="game.controller.snes"/>
    <accepts controller="game.controller.snes.mouse"/>
    <accepts controller="game.controller.snes.multitap">
      <port id="1">
        <accepts controller="game.controller.snes"/>
      </port>
      <port id="2">
        <accepts controller="game.controller.snes"/>
      </port>
      <port id="3">
        <accepts controller="game.controller.snes"/>
      </port>
      <port id="4">
        <accepts controller="game.controller.snes"/>
      </port>
    </accepts>
    <accepts controller="game.controller.snes.super.scope"/>
    <accepts controller="game.controller.konami.justifier.snes"/>
  </port>
</logicaltopology>

Here is the file with libretro port IDs:

<?xml version="1.0" encoding="UTF-8"?>
<logicaltopology>
  <port type="controller" id="1" connectionPort="0">
    <accepts controller="game.controller.snes"/>
    <accepts controller="game.controller.snes.mouse"/>
    <accepts controller="game.controller.snes.multitap">
      <port type="controller" id="1" connectionPort="-1" forceConnected="true">
        <accepts controller="game.controller.snes"/>
      </port>
      <port type="controller" id="2" connectionPort="-1" forceConnected="true">
        <accepts controller="game.controller.snes"/>
      </port>
      <port type="controller" id="3" connectionPort="-1" forceConnected="true">
        <accepts controller="game.controller.snes"/>
      </port>
      <port type="controller" id="4" connectionPort="-1" forceConnected="true">
        <accepts controller="game.controller.snes"/>
      </port>
    </accepts>
  </port>
  <port type="controller" id="2" connectionPort="1">
    <accepts controller="game.controller.snes"/>
    <accepts controller="game.controller.snes.mouse"/>
    <accepts controller="game.controller.snes.multitap">
      <port type="controller" id="1" connectionPort="-1" forceConnected="true">
        <accepts controller="game.controller.snes"/>
      </port>
      <port type="controller" id="2" connectionPort="-1" forceConnected="true">
        <accepts controller="game.controller.snes"/>
      </port>
      <port type="controller" id="3" connectionPort="-1" forceConnected="true">
        <accepts controller="game.controller.snes"/>
      </port>
      <port type="controller" id="4" connectionPort="-1" forceConnected="true">
        <accepts controller="game.controller.snes"/>
      </port>
    </accepts>
    <accepts controller="game.controller.snes.super.scope"/>
    <accepts controller="game.controller.konami.justifier.snes"/>
  </port>
</logicaltopology>

How has this been tested?

Tested as part of https://github.com/xbmc/xbmc/pull/20408