feat(session): add explicit leave and immediate slot release
This commit is contained in:
@@ -66,6 +66,8 @@ maze32_lobby_result_t maze32_lobby_join_observer(maze32_lobby_t* lobby, int conn
|
||||
maze32_lobby_result_t maze32_lobby_restore(maze32_lobby_t* lobby, int connection_id,
|
||||
const char* token, maze32_session_t** session);
|
||||
void maze32_lobby_disconnect(maze32_lobby_t* lobby, int connection_id);
|
||||
int maze32_lobby_leave(maze32_lobby_t* lobby, int connection_id, maze32_role_t* role,
|
||||
unsigned int* player_slot);
|
||||
maze32_lobby_result_t maze32_lobby_start(maze32_lobby_t* lobby, int connection_id, uint64_t now_ms);
|
||||
int maze32_lobby_activate_if_due(maze32_lobby_t* lobby, uint64_t now_ms);
|
||||
void maze32_lobby_reset_match(maze32_lobby_t* lobby);
|
||||
|
||||
@@ -22,6 +22,7 @@ typedef enum {
|
||||
MAZE32_MESSAGE_MOVE,
|
||||
MAZE32_MESSAGE_DROP_KEY,
|
||||
MAZE32_MESSAGE_RESTART,
|
||||
MAZE32_MESSAGE_LEAVE,
|
||||
MAZE32_MESSAGE_HEARTBEAT,
|
||||
} maze32_message_type_t;
|
||||
|
||||
|
||||
@@ -167,6 +167,30 @@ void maze32_lobby_disconnect(maze32_lobby_t* lobby, int connection_id) {
|
||||
}
|
||||
}
|
||||
|
||||
int maze32_lobby_leave(maze32_lobby_t* lobby, int connection_id, maze32_role_t* role,
|
||||
unsigned int* player_slot) {
|
||||
if (lobby == NULL) {
|
||||
return 0;
|
||||
}
|
||||
for (size_t index = 0U; index < MAZE32_SESSION_LIMIT; ++index) {
|
||||
maze32_session_t* session = &lobby->sessions[index];
|
||||
if (session->role != MAZE32_ROLE_NONE && session->connected &&
|
||||
session->connection_id == connection_id) {
|
||||
if (role != NULL) {
|
||||
*role = session->role;
|
||||
}
|
||||
if (player_slot != NULL) {
|
||||
*player_slot = session->player_slot;
|
||||
}
|
||||
memset(session, 0, sizeof(*session));
|
||||
session->connection_id = -1;
|
||||
lobby->revision++;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
maze32_lobby_result_t maze32_lobby_start(maze32_lobby_t* lobby, int connection_id,
|
||||
uint64_t now_ms) {
|
||||
if (lobby == NULL || lobby->phase != MAZE32_LOBBY_WAITING) {
|
||||
|
||||
@@ -193,6 +193,9 @@ static maze32_message_type_t message_type(const char* value) {
|
||||
if (strcmp(value, "restart") == 0) {
|
||||
return MAZE32_MESSAGE_RESTART;
|
||||
}
|
||||
if (strcmp(value, "leave") == 0) {
|
||||
return MAZE32_MESSAGE_LEAVE;
|
||||
}
|
||||
if (strcmp(value, "heartbeat") == 0) {
|
||||
return MAZE32_MESSAGE_HEARTBEAT;
|
||||
}
|
||||
|
||||
@@ -948,6 +948,40 @@ static void handle_message(maze32_gateway_t* gateway, maze32_gateway_connection_
|
||||
"Сначала выберите роль или восстановите сессию");
|
||||
return;
|
||||
}
|
||||
if (message->type == MAZE32_MESSAGE_LEAVE) {
|
||||
maze32_role_t leaving_role = session->role;
|
||||
int cancel_match = leaving_role == MAZE32_ROLE_PLAYER &&
|
||||
gateway->lobby.phase != MAZE32_LOBBY_WAITING &&
|
||||
gateway->game.phase != MAZE32_GAME_PHASE_FINISHED;
|
||||
char acknowledgement[192] = "";
|
||||
size_t length = 0U;
|
||||
char prefix[96];
|
||||
int written = snprintf(prefix, sizeof(prefix),
|
||||
"{\"v\":1,\"type\":\"ack\",\"seq\":%" PRIu32 ",\"requestId\":",
|
||||
next_server_sequence(gateway));
|
||||
if (written >= 0 && (size_t)written < sizeof(prefix) &&
|
||||
append_text(acknowledgement, sizeof(acknowledgement), &length, prefix) &&
|
||||
append_json_string(acknowledgement, sizeof(acknowledgement), &length,
|
||||
message->request_id) &&
|
||||
append_text(acknowledgement, sizeof(acknowledgement), &length,
|
||||
",\"payload\":{\"command\":\"leave\"}}")) {
|
||||
enqueue(gateway, socket_fd, acknowledgement);
|
||||
}
|
||||
if (cancel_match) {
|
||||
esp_timer_stop(gateway->countdown_timer);
|
||||
esp_timer_stop(gateway->reconnect_timer);
|
||||
esp_timer_stop(gateway->finish_timer);
|
||||
initialize_game(gateway);
|
||||
maze32_lobby_reset_match(&gateway->lobby);
|
||||
}
|
||||
maze32_lobby_leave(&gateway->lobby, socket_fd, NULL, NULL);
|
||||
if (cancel_match) {
|
||||
broadcast_match_event(gateway, "reset", "{}");
|
||||
}
|
||||
broadcast_snapshot(gateway);
|
||||
drain_queue(gateway);
|
||||
return;
|
||||
}
|
||||
if (message->type == MAZE32_MESSAGE_START) {
|
||||
if (session->role == MAZE32_ROLE_OBSERVER) {
|
||||
ESP_LOGW(TAG, "Observer mutation rejected: fd=%d, type=start", socket_fd);
|
||||
@@ -977,18 +1011,29 @@ static void handle_message(maze32_gateway_t* gateway, maze32_gateway_connection_
|
||||
return;
|
||||
}
|
||||
if (message->type == MAZE32_MESSAGE_HEARTBEAT) {
|
||||
int64_t heartbeat_started_us = esp_timer_get_time();
|
||||
char response[MAZE32_GATEWAY_OUTGOING_LIMIT] = "";
|
||||
size_t length = 0U;
|
||||
char prefix[128];
|
||||
char handling_text[32];
|
||||
int written = snprintf(prefix, sizeof(prefix), "{\"v\":1,\"type\":\"ack\",\"seq\":%" PRIu32,
|
||||
next_server_sequence(gateway));
|
||||
if (written >= 0 && (size_t)written < sizeof(prefix) &&
|
||||
uint64_t handling_ms = (uint64_t)(esp_timer_get_time() - heartbeat_started_us) / 1000U;
|
||||
if (handling_ms > 1000U) {
|
||||
handling_ms = 1000U;
|
||||
}
|
||||
int handling_written =
|
||||
snprintf(handling_text, sizeof(handling_text), "%" PRIu64, handling_ms);
|
||||
if (written >= 0 && (size_t)written < sizeof(prefix) && handling_written >= 0 &&
|
||||
(size_t)handling_written < sizeof(handling_text) &&
|
||||
append_text(response, sizeof(response), &length, prefix) &&
|
||||
append_text(response, sizeof(response), &length, ",\"requestId\":") &&
|
||||
append_json_string(response, sizeof(response), &length, message->request_id) &&
|
||||
append_text(response, sizeof(response), &length,
|
||||
",\"payload\":{\"command\":\"heartbeat\"}}")) {
|
||||
enqueue(gateway, socket_fd, response);
|
||||
",\"payload\":{\"command\":\"heartbeat\",\"handlingMs\":") &&
|
||||
append_text(response, sizeof(response), &length, handling_text) &&
|
||||
append_text(response, sizeof(response), &length, "}}")) {
|
||||
enqueue_with_policy(gateway, socket_fd, response, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user