i wanted to poll the guys responsible for the controller API on how they are planning to solve the player -> controller mapping. As i see it, the ODK currently assigns those based on which controller was interacted with first (decompiled the ODK jars, is there an official source repo?).
That's not a bad solution to initiate the mapping. However, as soon as a controller disconnects and reconnects, there doesn't appear to be any way using default Android APIs (InputManager) to reestablished that the reconnected controller represents the original player. This situation gets more complicated with more controllers.
A unique controller ID would help, but that doesn't seem to be available. InputDevice#getId is not unique, it's actually incremental. InputDevice#getDescriptor is meant to be a unique id but fails in reality, as the descriptor reported by each Ouya controller is the same.
I might overlook something, but it seems that the player number functionality of the API can't actually be implemented in any way. I guess a solution to this problem would benefit not only folks using the ODK Java API, but also the Unity side of things. The solution we propose to our users is to use the initial mapping, then listen for disconnects, and ask the user to plug in the controller of the disconnected player, listening for the first connection event in that case.
The current ODK API suggests that the outlined solution is not necessary as the ODK will take care of it. If it can't, then devs might have to restructure their code considerably (adding new UI instead of reyling on the mapping to work in all circumstances).
Yup, you are correct on how it currently works! This is a just a temporary implementation until we finish the real solution. The current plan is to use the bluetooth addresses of the controllers to provide a consistent mapping between player & controller.
Please take into account that XBox controllers and other probably other third party USB controllers seem to duplicate their "serial number" across all their sticks :(
I have a scheme which works mostly ok for 2 players, where if a new controller comes in it takes over the controller which was used the longest ago. So, why would this work?
Say somebody's batteries went out on controller 1and they have to replace them. Controller 2 presses pause. (controller 1 is now the oldest). When controller 1 comes back online, or another controller is turned on and connected, then that controller will immediately take over controller 1.
In code this looks like:
// Determine Player number.
int deviceId = AInputEvent_getDeviceId(event);
static int inputCounter = 0;
++inputCounter;
static int playerIds[2] = {-1,-1};
static int playerLast[2] = {-1,-1};
int playerNum = -1;
for(unsigned i = 0; i < _countof(playerIds); ++i) {
if(playerIds[i] == deviceId) {
playerLast[i] = inputCounter;
playerNum = i;
break;
}
}
if(playerNum == -1) {
int bestIdx = 0, bestCnt = INT_MAX;
for(unsigned i = 0; i < _countof(playerIds); ++i) {
if(playerLast[i] < bestCnt) {
bestIdx = i;
bestCnt = playerLast[i];
}
}
playerIds[bestIdx] = deviceId;
playerLast[bestIdx] = inputCounter;
playerNum = bestIdx;
printf("Registered %i as player number %i", deviceId, playerNum);
Comments
CC: @Buddy
Please take into account that XBox controllers and other probably other third party USB controllers seem to duplicate their "serial number" across all their sticks :(