leezer3 / OpenBVE

OpenBVE- A free train simulator
http://www.openbve-project.net
280 stars 52 forks source link

Input device plugins and hold brake #528

Closed marcriera closed 4 years ago

marcriera commented 4 years ago

Summary

I am currently developing an input device plugin for the "Densha de GO!" controllers for the PS1. No problem regarding the controller themselves, with adapters they show up as USB gamepads and then it is just a matter of assigning the correct button combinations to OpenBVE commands. Once it is mature enough (soon, I hope!), I will send a pull request to get it in the main source repo.

While developing, I have noticed two issues regarding the use of input device plugins with trains with a hold brake.

Issues

  1. Currently, input plugins have no way of knowing whether the train they are controlling has a hold brake or not. The command to apply or release the hold brake (OpenBveApi.Interface.Translations.Command.HoldBrake) works, but depending on the train it will be needed or not. In-game, OpenBVE presents the hold brake as an extra notch between N and B1, so it makes sense to bind it to that physical position in a real controller. The presence or not of a hold brake thus affects the binding of the rest of brake notches.

  2. When using the hold brake application command directly, OpenBVE currently does not change the brake notch. This way, if the brake notch is B1 and the hold brake is applied, the regular brakes will still be applied. This is inconsistent with how the feature is presented to the user in-game (as mentioned before) and is not limited to input device plugins, as it affects any use of OpenBveApi.Interface.Translations.Command.HoldBrake.

Proposed solutions

  1. Extend the arguments in the SetMaxNotch method, currently informing about the maximum notches for the driver. This would be backwards incompatible with existing plugins. There is at least one existing plugin outside of the main repo (https://github.com/TetsuOtter/BIDSSMemLib) that would require changes, but fortunately the changes would be minimal. To prevent further issues if we need to expand this again in the future, it would be wiser to replace it with something equal or similar to SetVehicleSpecs for train plugins, with driver notches instead of "internal" notches.

  2. Ensure we move the brake notch to 0 when applying the hold brake.

I can take care of both fixes once we agree on the solutions (specially the first aspect).

leezer3 commented 4 years ago

My initial instinct would be to add something like a new SetTrainSpecs function with an appropriate struct and leave the old one alone entirely.

This preserves the backward compatability & would allow for future expansion if another controller required a more esoteric property.

The other option would be to implement it into the main tree completely, same basic way as a RailDriver, although that might be tricky if it's not easily detectable. Doing that you'd have full visibility of the internals of everything.

@s520 thoughts?

s520 commented 4 years ago

I support the first idea of @leezer3.

Defines a new interface that inherits the current interface. Create an overload of the Load function and pass the version information of the main program as its second argument. By doing so, the plugin can decide whether to support the version of the main program that the user uses. Then add the new required functions.

If we go in this direction, I think it's better to discuss not only this but also other necessary functions. I would also like him, who develops input device plugins outside of us, to participate in this discussion.

marcriera commented 4 years ago

If it is possible to add a new function without breaking backwards compatibility, then count me in.

Regarding the implementation in the main tree, they are not easily detectable, at least not the older ones. Newer controllers for the series use USB (PS2 and PC), but the original controllers used the same connector and protocol as a standard controller. The PS1 controllers, despite having a completely different appearance to a standard controller, use the same button data. Many of them are permanently pressed (I guess it is partly how the games identify them), while others are used in groups as matrices to define the notches. This is not a problem per se, but remember that we need a PlayStation to USB converter in the middle. There are lots of different ones and each one maps the buttons indices differently. The converter I use even has a mode switch, each with its own mapping.

For this reason, users will need to calibrate their adapters by choosing which index corresponds to which button. This will be done in the configuration dialog of the plugin, potentially with a list of possible presets and the ability to define and save their own. And of course, given how the notches may not match 1:1 between the controller and the train, users will also need to define how the notches will be mapped (similarly to what the SanYing plugin currently does).

leezer3 commented 4 years ago

Hmm... Still thinking about this.

The new interface / method works, but could get messy if we need to modify this again someday, so I'm thinking about places where the current problem could be added.

Now, the plugin is informed about the train every frame via the ElapseData (which is also provided to runtime train plugins for that matter) One of the components of this is the Handles: https://github.com/leezer3/OpenBVE/blob/master/source/OpenBveApi/Runtime/Runtime.cs#L587

We could easily add a HoldBrake something to this. My first thought would be an enum, e.g.

enum HoldBrakeState
{
NotFitted = 0,
Released = 1,
Applied = 2
}

This would be disparate to the others though.

Thoughts?

leezer3 commented 4 years ago

Marginally related (saving this here for reference as much as anything) as I've been doing a little digging: http://web.archive.org/web/20190402235015/https://assemblergames.com/threads/densha-de-go-64-train-controller-info.56965/ https://sites.google.com/site/consoleprotocols/home/nintendo-joy-bus-documentation/n64-specific/train-controller

I'd presume the PS2 version is going to be much the same hardware internally implementation wise. See the note at the bottom about telling the difference between a controller and a pad.

marcriera commented 4 years ago

Hmm... Still thinking about this.

The new interface / method works, but could get messy if we need to modify this again someday, so I'm thinking about places where the current problem could be added.

Now, the plugin is informed about the train every frame via the ElapseData (which is also provided to runtime train plugins for that matter) One of the components of this is the Handles: https://github.com/leezer3/OpenBVE/blob/master/source/OpenBveApi/Runtime/Runtime.cs#L587

We could easily add a HoldBrake something to this. My first thought would be an enum, e.g.

enum HoldBrakeState
{
NotFitted = 0,
Released = 1,
Applied = 2
}

This would be disparate to the others though.

Thoughts?

This could be used for the purpose of the plugin, indeed.

Marginally related (saving this here for reference as much as anything) as I've been doing a little digging: http://web.archive.org/web/20190402235015/https://assemblergames.com/threads/densha-de-go-64-train-controller-info.56965/ https://sites.google.com/site/consoleprotocols/home/nintendo-joy-bus-documentation/n64-specific/train-controller

I'd presume the PS2 version is going to be much the same hardware internally implementation wise. See the note at the bottom about telling the difference between a controller and a pad.

I found the second site while looking for documentation and thought that the PS1 controllers probably have a similar quirk, but it makes no difference. It would be useful if we were interfacing directly with the hardware (or using an Arduino board or something similar), but we do not have access to the original hardware signals because there is a converter in the middle doing a conversion to standard USB gamepad input. So I guess we are limited to making the configuration as friendly as possible.

marcriera commented 4 years ago

Here is a page with technical details regarding the controllers: https://marcriera.github.io/ddgo-controller-docs/

I have yet to confirm whether the fixed analog stick position is reported on an actual console, but it could be used to help with autodetection, at least to prevent other controllers from interfering with the plugin. USB adapters may report more than 4 axes (mine reports 7, for example), but an axis with a value of 0.34019 is easier to detect than several pressed or unpressed buttons.

Regarding the buttons, I have been thinking about offering a series of prompts asking the user to move the handles to a certain notch so the plugin can guess the mapping automatically. If you take a look at the gist, you will see that many notches are assigned to just one button; we can easily find out the rest of buttons by comparison in notches with multiple buttons.