kodi-game / controller-topology-project

The Controller Topology Project models how controllers connect to and map to each other for all gaming history
Open Data Commons Open Database License v1.0
21 stars 15 forks source link

Add Genesis Team Player #206

Closed KOPRajs closed 1 year ago

KOPRajs commented 1 year ago

This PR adds the Team Player for Sega Genesis. It depends on https://github.com/kodi-game/controller-topology-project/pull/203.

@garbear Please check this out.

I haven't tested this yet, so WIP.

KOPRajs commented 1 year ago

@garbear The problem with Sega multitaps is that there are more variations and I'm not sure, if we are able to cover them with the single multitap controller profile.

See here: https://github.com/libretro/Genesis-Plus-GX/blob/4d400a673daa2ff393f21ef48fd6a10a6150bd0b/libretro/libretro.c#L57

There are different _RETRO_DEVICEJOYPAD subclasses defined for every combination of 3 and 6 button controllers. Is there a way to create a buttonmap which can handle this? Or do we need 2 Team Player profiles? One for 3 button controller and the other one for 6 button controller?

Like in Retroarch: 3 button 6 button 3 button + Team Player 6 button + Team Player 3 button + 4 Way Play 6 button + 4 Way Play

garbear commented 1 year ago

Great job! Everything looks so good I had to bike shed on the description.

Like in Retroarch: 3 button 6 button 3 button + Team Player 6 button + Team Player 3 button + 4 Way Play 6 button + 4 Way Play

Part of the goal of the controller topology project is to map a configuration experience contorted by the libretro API to a more basic and intuitive experience.

You'll notice that the button maps in this repo use physicaltopology. They describe how controller profiles physically connect, so you would have 4 profiles:

Both multitaps physically accept both controllers.

The next step is to modify the logicaltopology in https://github.com/kodi-game/game.libretro.genplus/blob/master/game.libretro.genplus/resources/topology.xml. This file says what configurations the emulator "logically" understands.

In this case, the Team Player and 4 Way Play logically understand both controllers, so they'd work the exact same way in the Port Setup dialog.

The final step is to modify game.libretro to calculate subclasses based on the entire "path" of the controller tree instead of just the leaf. You can treat the path as a vector and create an "outer product", giving 8 possible combinations. Then sort the combinations and map them to 0-7 in game.libretro.

KOPRajs commented 1 year ago

What if we change the logical topology like this:

<?xml version="1.0" encoding="UTF-8"?>
<logicaltopology>
  <port type="controller" id="1">
    <accepts controller="game.controller.genesis.3button"/>
    <accepts controller="game.controller.genesis.6button"/>
    <accepts controller="game.controller.genesis.teamplayer">
      <port type="controller" id="1" connectionPort="-1" forceConnected="true">
        <accepts controller="game.controller.genesis.3button" type="RETRO_DEVICE_JOYPAD" subclass="5"/>
        <accepts controller="game.controller.genesis.6button" type="RETRO_DEVICE_JOYPAD" subclass="6"/>
      </port>
      <port type="controller" id="2" connectionPort="-1" forceConnected="true">
        <accepts controller="game.controller.genesis.3button" type="RETRO_DEVICE_JOYPAD" subclass="5"/>
        <accepts controller="game.controller.genesis.6button" type="RETRO_DEVICE_JOYPAD" subclass="6"/>
      </port>
      <port type="controller" id="3" connectionPort="-1" forceConnected="true">
        <accepts controller="game.controller.genesis.3button" type="RETRO_DEVICE_JOYPAD" subclass="5"/>
        <accepts controller="game.controller.genesis.6button" type="RETRO_DEVICE_JOYPAD" subclass="6"/>
      </port>
      <port type="controller" id="4" connectionPort="-1" forceConnected="true">
        <accepts controller="game.controller.genesis.3button" type="RETRO_DEVICE_JOYPAD" subclass="5"/>
        <accepts controller="game.controller.genesis.6button" type="RETRO_DEVICE_JOYPAD" subclass="6"/>
      </port>
    </accepts>
    <accepts controller="game.controller.genesis.mouse"/>
  </port>
  ...
</logicaltopology>

The type and the subclass attributes are moved from the buttonmap to the logical topology in this case. We can make the attributes optional (override of the default) for the profile.

We would keep the default attributes in the buttonmap like this:

<controller id="game.controller.genesis.3button" type="RETRO_DEVICE_JOYPAD" subclass="0">
<controller id="game.controller.genesis.6button" type="RETRO_DEVICE_JOYPAD" subclass="1">

But we would implement the optional override in the logical topology like seen above.

@garbear I can modify the buttonmaps and the topology for all Genesis emulators, but the implementation of the override support in the logical topology is beyond my abilities.

garbear commented 1 year ago

That should work! I'll add override support when I get a chance next.

KOPRajs commented 1 year ago

@garbear I've finally tested it! It works as expected and even without the possibility to change the subclass depending on the controller, it actually covers all the real use cases already:

  1. 2 player games works
  2. 4 player games works
  3. changing the controller type works (3 button vs. 6 button)
  4. easy swapping between 2 different buttonmapps (3 button vs. 6 button games)

In theory, I'm not able to tell the emulator that I have 4x 6 button controllers connected, but I don't know if there is even any game, where it would be needed. Also we are missing the 4 Way Play adapter for the 4 player support in EA Sports games. I'll try to create it as well, but so far I was having difficulty finding a usable image for it.

This PR should be ready to merge now.

obrazek obrazek obrazek

garbear commented 1 year ago

I got this in my latest round of test builds! What changes need to be made to the genesis add-ons (genplus, genplus-wide and picodrive)?

garbear commented 1 year ago

I also added the override feature, also included in my upcoming test builds: https://github.com/kodi-game/game.libretro/pull/105

KOPRajs commented 1 year ago

@garbear I'm using the following buttonmap.xml and topology.xml for the Genesis Plus GX (applies for the wide version as well):

CoreELEC:~ # cat .kodi/addons/game.libretro.genplus/resources/buttonmap.xml 
<?xml version="1.0" encoding="UTF-8"?>
<buttonmap version="2">
  <controller id="game.controller.genesis.3button" type="RETRO_DEVICE_JOYPAD" subclass="0">
    <feature name="a" mapto="RETRO_DEVICE_ID_JOYPAD_Y"/>
    <feature name="b" mapto="RETRO_DEVICE_ID_JOYPAD_B"/>
    <feature name="c" mapto="RETRO_DEVICE_ID_JOYPAD_A"/>
    <feature name="start" mapto="RETRO_DEVICE_ID_JOYPAD_START"/>
    <feature name="mode" mapto="RETRO_DEVICE_ID_JOYPAD_SELECT"/>
    <feature name="up" mapto="RETRO_DEVICE_ID_JOYPAD_UP"/>
    <feature name="down" mapto="RETRO_DEVICE_ID_JOYPAD_DOWN"/>
    <feature name="right" mapto="RETRO_DEVICE_ID_JOYPAD_RIGHT"/>
    <feature name="left" mapto="RETRO_DEVICE_ID_JOYPAD_LEFT"/>
  </controller>
  <controller id="game.controller.genesis.6button" type="RETRO_DEVICE_JOYPAD" subclass="1">
    <feature name="a" mapto="RETRO_DEVICE_ID_JOYPAD_Y"/>
    <feature name="b" mapto="RETRO_DEVICE_ID_JOYPAD_B"/>
    <feature name="c" mapto="RETRO_DEVICE_ID_JOYPAD_A"/>
    <feature name="x" mapto="RETRO_DEVICE_ID_JOYPAD_L"/>
    <feature name="y" mapto="RETRO_DEVICE_ID_JOYPAD_X"/>
    <feature name="z" mapto="RETRO_DEVICE_ID_JOYPAD_R"/>
    <feature name="start" mapto="RETRO_DEVICE_ID_JOYPAD_START"/>
    <feature name="mode" mapto="RETRO_DEVICE_ID_JOYPAD_SELECT"/>
    <feature name="up" mapto="RETRO_DEVICE_ID_JOYPAD_UP"/>
    <feature name="down" mapto="RETRO_DEVICE_ID_JOYPAD_DOWN"/>
    <feature name="right" mapto="RETRO_DEVICE_ID_JOYPAD_RIGHT"/>
    <feature name="left" mapto="RETRO_DEVICE_ID_JOYPAD_LEFT"/>
  </controller>
  <controller id="game.controller.genesis.mouse" type="RETRO_DEVICE_MOUSE">
    <feature name="left" mapto="RETRO_DEVICE_ID_MOUSE_LEFT"/>
    <feature name="right" mapto="RETRO_DEVICE_ID_MOUSE_RIGHT"/>
    <feature name="middle" mapto="RETRO_DEVICE_ID_MOUSE_WHEELDOWN"/>
    <feature name="start" mapto="RETRO_DEVICE_ID_MOUSE_MIDDLE"/>
    <feature name="pointer" mapto="RETRO_DEVICE_MOUSE"/>
  </controller>
  <controller id="game.controller.genesis.teamplayer" type="RETRO_DEVICE_JOYPAD" subclass="5"/>
</buttonmap>
CoreELEC:~ # cat .kodi/addons/game.libretro.genplus/resources/topology.xml 
<?xml version="1.0" encoding="UTF-8"?>
<logicaltopology>
  <port type="controller" id="1" connectionPort="0">
    <accepts controller="game.controller.genesis.3button"/>
    <accepts controller="game.controller.genesis.6button"/>
    <accepts controller="game.controller.genesis.mouse"/>
    <accepts controller="game.controller.genesis.teamplayer">
      <port type="controller" id="1" connectionPort="-1" forceConnected="true">
        <accepts controller="game.controller.genesis.3button"/>
        <accepts controller="game.controller.genesis.6button"/>
      </port>
      <port type="controller" id="2" connectionPort="-1" forceConnected="true">
        <accepts controller="game.controller.genesis.3button"/>
        <accepts controller="game.controller.genesis.6button"/>
      </port>
      <port type="controller" id="3" connectionPort="-1" forceConnected="true">
        <accepts controller="game.controller.genesis.3button"/>
        <accepts controller="game.controller.genesis.6button"/>
      </port>
      <port type="controller" id="4" connectionPort="-1" forceConnected="true">
        <accepts controller="game.controller.genesis.3button"/>
        <accepts controller="game.controller.genesis.6button"/>
      </port>
    </accepts>
  </port>
  <port type="controller" id="2" connectionPort="1">
    <accepts controller="game.controller.genesis.3button"/>
    <accepts controller="game.controller.genesis.6button"/>
    <accepts controller="game.controller.genesis.mouse"/>
    <accepts controller="game.controller.genesis.teamplayer">
      <port type="controller" id="1" connectionPort="-1" forceConnected="true">
        <accepts controller="game.controller.genesis.3button"/>
        <accepts controller="game.controller.genesis.6button"/>
      </port>
      <port type="controller" id="2" connectionPort="-1" forceConnected="true">
        <accepts controller="game.controller.genesis.3button"/>
        <accepts controller="game.controller.genesis.6button"/>
      </port>
      <port type="controller" id="3" connectionPort="-1" forceConnected="true">
        <accepts controller="game.controller.genesis.3button"/>
        <accepts controller="game.controller.genesis.6button"/>
      </port>
      <port type="controller" id="4" connectionPort="-1" forceConnected="true">
        <accepts controller="game.controller.genesis.3button"/>
        <accepts controller="game.controller.genesis.6button"/>
      </port>
    </accepts>
  </port>
</logicaltopology>

This is without the new override support, but I can still switch between 3 and 6 button, because I've set different mapping for each.

For 3 button: "A"->"X" "B"->"A" "C"->"B"

For 6 button: "A"->"A" "B"->"B" "C"->"R" "X"->"X" "Y"->"Y" "Z"->"L"

I can create PR for these changes, if you want, but I was planning to add the 4 Way Play profile first and then update the buttonmaps and the topology for all controller profiles at once.

Also it seems that the Picodrive doesn't support the libretro input type settings yet (similar to PCSX-reARMed). There are settings for the controller types inside the core: https://github.com/kodi-game/game.libretro.picodrive/blob/25900e5380495051583bc7e4c7c313d938e74990/game.libretro.picodrive/resources/settings.xml#L17

Please note, that up until the last update (https://github.com/kodi-game/game.libretro.picodrive/commit/544726f86a7ecb67947399cca6d5053e62599993) there was support for 2 players only. They've just added the support for 4 player adapters, but in the current state we would have to use the "flattened topology" as in PCSX. Maybe they are going to change it to the new model soon.

garbear commented 1 year ago

Nice! Let's get the 4 Way Profile done first then we can update the buttonmaps and typologies all at once.

Can https://github.com/kodi-game/game.libretro/pull/105 still help? Assuming it works it's a really minor code change for a feature we may need someday.

Because Picodrive uses advanced settings for its input, there's not much we can do currently except for the flat approach taken by PCSX-reARMed.

KOPRajs commented 1 year ago

Can kodi-game/game.libretro#105 still help?

Yes, it is still needed if we want to utilize all the possible emulator settings, which we should. I'll try to compile the game.libretro for my Amlogic device and test it. The problem is that I don't know any specific game where I can see if it actually works.