Closing active wireless sessions by updating broadcast data

This commit is contained in:
Rodrigo Alfonso 2024-01-03 11:02:35 -03:00
parent 8b58af297e
commit 8a162d429c
4 changed files with 46 additions and 11 deletions

View File

@ -196,7 +196,7 @@ Name | Return type | Description
`isActive()` | **bool** | Returns whether the library is active or not.
`activate()` | **bool** | Activates the library. When an adapter is connected, it changes the state to `AUTHENTICATED`. It can also be used to disconnect or reset the adapter.
`deactivate()` | **bool** | Puts the adapter into a low consumption mode and then deactivates the library. It returns a boolean indicating whether the transition to low consumption mode was successful.
`serve([gameName], [userName], [gameId])` | **bool** | Starts broadcasting a server and changes the state to `SERVING`. You can, optionally, provide a `gameName` (max `14` characters), a `userName` (max `8` characters), and a `gameId` *(0 ~ 0x7FFF)* that games will be able to read.
`serve([gameName], [userName], [gameId], [isUpdate])` | **bool** | Starts broadcasting a server and changes the state to `SERVING`. You can, optionally, provide a `gameName` (max `14` characters), a `userName` (max `8` characters), and a `gameId` *(0 ~ 0x7FFF)* that games will be able to read. If `isUpdate` is true, this method only updates the broadcast data.
`getServers(servers, [onWait])` | **bool** | Fills the `servers` array with all the currently broadcasting servers. This action takes 1 second to complete, but you can optionally provide an `onWait()` function which will be invoked each time VBlank starts.
`getServersAsyncStart()` | **bool** | Starts looking for broadcasting servers and changes the state to `SEARCHING`. After this, call `getServersAsyncEnd(...)` 1 second later.
`getServersAsyncEnd(servers)` | **bool** | Fills the `servers` array with all the currently broadcasting servers. Changes the state to `AUTHENTICATED` again.

View File

@ -249,6 +249,8 @@ Both Pokemon games and the multiboot ROM that the adapter sends when no cartridg
🆔 The **Game ID** is what games use to avoid listing servers from another game. This is done on the software layer (GBA), the adapter does not enforce this in any way, nor does gba-link-connection.
🔥 This command can be called even when the server has already started with `StartHost`, and the adapter will update the broadcast data. Some games include metadata in the game/user name fields, such as the player's gender or a busy flag.
#### StartHost - `0x19`
* Send length: 0, response length: 0

View File

@ -47,6 +47,8 @@
#define LINK_UNIVERSAL_DISCONNECTED LINK_CABLE_DISCONNECTED
#define LINK_UNIVERSAL_NO_DATA LINK_CABLE_NO_DATA
#define LINK_UNIVERSAL_MAX_ROOM_NUMBER 32000
#define LINK_UNIVERSAL_FULL_ROOM_NUMBER 32001
#define LINK_UNIVERSAL_FULL_ROOM_NUMBER_STR "32001"
#define LINK_UNIVERSAL_INIT_WAIT_FRAMES 10
#define LINK_UNIVERSAL_SWITCH_WAIT_FRAMES 25
#define LINK_UNIVERSAL_SWITCH_WAIT_FRAMES_RANDOM 10
@ -208,6 +210,15 @@ class LinkUniversal {
}
receiveWirelessMessages();
if (!linkWireless->_hasActiveAsyncCommand() &&
linkWireless->playerCount() == linkWireless->config.maxPlayers &&
!didCloseWirelessRoom) {
linkWireless->serve(config.gameName,
LINK_UNIVERSAL_FULL_ROOM_NUMBER_STR,
LINK_WIRELESS_MAX_GAME_ID, true);
didCloseWirelessRoom = true;
}
}
break;
@ -305,6 +316,7 @@ class LinkUniversal {
u32 switchWait = 0;
u32 subWaitCount = 0;
u32 serveWait = 0;
bool didCloseWirelessRoom = false;
volatile bool isEnabled = false;
void receiveCableMessages() {
@ -381,12 +393,13 @@ class LinkUniversal {
if (server.id == LINK_WIRELESS_END)
break;
u32 randomNumber = std::stoi(server.userName);
if (server.gameName == config.gameName &&
randomNumber > maxRandomNumber) {
maxRandomNumber = randomNumber;
serverIndex = i;
if (server.gameName == config.gameName) {
u32 randomNumber = safeStoi(server.userName);
if (randomNumber > maxRandomNumber &&
randomNumber < LINK_UNIVERSAL_FULL_ROOM_NUMBER) {
maxRandomNumber = randomNumber;
serverIndex = i;
}
}
}
@ -478,6 +491,19 @@ class LinkUniversal {
serveWait = 0;
for (u32 i = 0; i < LINK_UNIVERSAL_MAX_PLAYERS; i++)
incomingMessages[i].clear();
didCloseWirelessRoom = false;
}
u32 safeStoi(const std::string& str) {
uint32_t num = 0;
for (char ch : str) {
if (ch < '0' || ch > '9')
return 0;
num = num * 10 + (ch - '0');
}
return num;
}
};

View File

@ -251,9 +251,10 @@ class LinkWireless {
bool serve(std::string gameName = "",
std::string userName = "",
u16 gameId = LINK_WIRELESS_MAX_GAME_ID) {
u16 gameId = LINK_WIRELESS_MAX_GAME_ID,
bool isUpdate = false) {
LINK_WIRELESS_RESET_IF_NEEDED
if (state != AUTHENTICATED) {
if (state != AUTHENTICATED && (!isUpdate || state != SERVING)) {
lastError = WRONG_STATE;
return false;
}
@ -281,8 +282,13 @@ class LinkWireless {
buildU16(userName[1], userName[0])));
addData(buildU32(buildU16(userName[7], userName[6]),
buildU16(userName[5], userName[4])));
bool success = sendCommand(LINK_WIRELESS_COMMAND_BROADCAST, true).success &&
sendCommand(LINK_WIRELESS_COMMAND_START_HOST).success;
bool success = sendCommand(LINK_WIRELESS_COMMAND_BROADCAST, true).success;
if (!isUpdate) {
success =
success && sendCommand(LINK_WIRELESS_COMMAND_START_HOST).success;
}
if (!success) {
reset();
@ -513,6 +519,7 @@ class LinkWireless {
delete linkGPIO;
}
bool _hasActiveAsyncCommand() { return asyncCommand.isActive; }
bool _canSend() { return !sessionState.outgoingMessages.isFull(); }
u32 _getPendingCount() { return sessionState.outgoingMessages.size(); }
u32 _lastPacketId() { return sessionState.lastPacketId; }