https://github.com/libsdl-org/Maelstrom/commit/9a6992d9433ca9870164b165be80b30a5c6ec9d0
From 9a6992d9433ca9870164b165be80b30a5c6ec9d0 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Sun, 6 Nov 2011 11:55:11 -0500
Subject: [PATCH] Added state transition and completed protocol implementation
for join/leave/kick
---
netlogic/gameinfo.h | 11 +++
netlogic/lobby.cpp | 173 +++++++++++++++++++++++++++++++++++---------
netlogic/lobby.h | 10 ++-
netlogic/protocol.h | 9 ++-
4 files changed, 164 insertions(+), 39 deletions(-)
diff --git a/netlogic/gameinfo.h b/netlogic/gameinfo.h
index bde72ab7..da505a4e 100644
--- a/netlogic/gameinfo.h
+++ b/netlogic/gameinfo.h
@@ -77,9 +77,20 @@ class GameInfo
bool ReadFromPacket(DynamicPacket &packet);
void WriteToPacket(DynamicPacket &packet);
+ GameInfoPlayer *GetHost() {
+ return GetPlayer(0);
+ }
GameInfoPlayer *GetPlayer(int index) {
return &players[index];
}
+ GameInfoPlayer *GetPlayerByID(Uint32 playerID) {
+ for (int i = 0; i < MAX_PLAYERS; ++i) {
+ if (players[i].playerID == playerID) {
+ return &players[i];
+ }
+ }
+ return NULL;
+ }
bool HasPlayer(Uint32 playerID) {
for (int i = 0; i < MAX_PLAYERS; ++i) {
diff --git a/netlogic/lobby.cpp b/netlogic/lobby.cpp
index 42aa66b0..9d1dadb6 100644
--- a/netlogic/lobby.cpp
+++ b/netlogic/lobby.cpp
@@ -155,6 +155,8 @@ LobbyDialogDelegate::OnHide()
}
}
NewGame();
+ } else {
+ SetState(STATE_NONE);
}
// Shut down networking
@@ -176,6 +178,8 @@ LobbyDialogDelegate::OnTick()
AdvertiseGame();
} else if (m_state == STATE_LISTING) {
GetGameList();
+ } else if (m_state == STATE_JOINING) {
+ SendJoinRequest();
} else {
GetGameInfo();
}
@@ -204,23 +208,17 @@ LobbyDialogDelegate::SetHostOrJoin(void*, int value)
return;
}
- if (value == HOST_GAME) {
- m_state = STATE_HOSTING;
- } else {
- m_state = STATE_LISTING;
- }
m_uniqueID = rand();
- m_lastRefresh = 0;
+ m_game.SetLocalID(m_uniqueID);
- if (m_state == STATE_HOSTING) {
- m_game.SetHostInfo(m_uniqueID, prefs->GetString(PREFERENCES_HANDLE));
+ if (value == HOST_GAME) {
+ SetState(STATE_HOSTING);
+ } else {
+ SetState(STATE_LISTING);
}
- m_game.SetLocalID(m_uniqueID);
} else {
- m_state = STATE_NONE;
+ SetState(STATE_NONE);
}
-
- UpdateUI();
}
void
@@ -281,6 +279,38 @@ LobbyDialogDelegate::UpdateUI()
}
}
+void
+LobbyDialogDelegate::SetState(LOBBY_STATE state)
+{
+ // Handle any state transitions here
+ if (state == STATE_NONE) {
+ if (m_state == STATE_HOSTING) {
+ // Notify the players that the game is gone
+ for (int i = 0; i < MAX_PLAYERS; ++i) {
+ SendKick(i);
+ }
+ } else if (m_state == STATE_JOINING ||
+ m_state == STATE_JOINED) {
+ // Notify the host that we're gone
+ SendLeaveRequest();
+ }
+ } else if (state == STATE_HOSTING) {
+ m_game.SetHostInfo(m_uniqueID, prefs->GetString(PREFERENCES_HANDLE));
+ } else if (state == STATE_LISTING) {
+ ClearGameList();
+ }
+
+ // Set the state
+ m_state = state;
+
+ // Update the UI for the new state
+ UpdateUI();
+
+ // Send any packet requests immediately
+ // Comment this out to simulate initial packet loss
+ m_lastRefresh = 0;
+}
+
void
LobbyDialogDelegate::AdvertiseGame()
{
@@ -325,24 +355,56 @@ void
LobbyDialogDelegate::GetGameInfo()
{
m_packet.StartLobbyMessage(LOBBY_REQUEST_GAME_INFO);
- m_packet.address = m_game.players[0].address;
+ m_packet.address = m_game.GetHost()->address;
SDLNet_UDP_Send(gNetFD, -1, &m_packet);
}
void
LobbyDialogDelegate::JoinGame(GameInfo &game)
+{
+ m_game.CopyFrom(game);
+ SetState(STATE_JOINING);
+}
+
+void
+LobbyDialogDelegate::SendJoinRequest()
{
m_packet.StartLobbyMessage(LOBBY_REQUEST_JOIN);
- m_packet.Write(game.gameID);
+ m_packet.Write(m_game.gameID);
m_packet.Write(m_uniqueID);
m_packet.Write(prefs->GetString(PREFERENCES_HANDLE));
- m_packet.address = game.players[0].address;;
+ m_packet.address = m_game.GetHost()->address;
SDLNet_UDP_Send(gNetFD, -1, &m_packet);
+}
- m_game.CopyFrom(game);
- m_state = STATE_JOINING;
- UpdateUI();
+void
+LobbyDialogDelegate::SendLeaveRequest()
+{
+ m_packet.StartLobbyMessage(LOBBY_REQUEST_LEAVE);
+ m_packet.Write(m_game.gameID);
+ m_packet.Write(m_uniqueID);
+ m_packet.address = m_game.GetHost()->address;
+
+ SDLNet_UDP_Send(gNetFD, -1, &m_packet);
+}
+
+void
+LobbyDialogDelegate::SendKick(int index)
+{
+ GameInfoPlayer *player;
+
+ player = m_game.GetPlayer(index);
+ if (!player->playerID || player->playerID == m_uniqueID) {
+ return;
+ }
+
+ m_packet.StartLobbyMessage(LOBBY_KICK);
+ m_packet.Write(m_game.gameID);
+ m_packet.Write(player->playerID);
+ m_packet.address = player->address;
+
+ SDLNet_UDP_Send(gNetFD, -1, &m_packet);
}
void
@@ -408,7 +470,7 @@ LobbyDialogDelegate::ProcessPacket(DynamicPacket &packet)
} else if (cmd == LOBBY_REQUEST_JOIN) {
ProcessRequestJoin(packet);
} else if (cmd == LOBBY_REQUEST_LEAVE) {
- //ProcessRequestLeave(packet);
+ ProcessRequestLeave(packet);
}
return;
@@ -421,7 +483,6 @@ LobbyDialogDelegate::ProcessPacket(DynamicPacket &packet)
}
return;
}
-
}
// These packets we handle in all the join states
@@ -430,6 +491,8 @@ LobbyDialogDelegate::ProcessPacket(DynamicPacket &packet)
//RejectPing(packet);
} else if (cmd == LOBBY_GAME_INFO) {
ProcessGameInfo(packet);
+ } else if (cmd == LOBBY_KICK) {
+ ProcessKick(packet);
}
}
@@ -531,6 +594,27 @@ LobbyDialogDelegate::ProcessRequestJoin(DynamicPacket &packet)
UpdateUI();
}
+void
+LobbyDialogDelegate::ProcessRequestLeave(DynamicPacket &packet)
+{
+ Uint32 gameID;
+ Uint32 playerID;
+
+ if (!packet.Read(gameID) || gameID != m_game.gameID) {
+ return;
+ }
+ if (!packet.Read(playerID) || !m_game.HasPlayer(playerID)) {
+ return;
+ }
+
+ // Okay, clear them from the list!
+ GameInfoPlayer *player = m_game.GetPlayerByID(playerID);
+ SDL_zero(*player);
+
+ // Update our own UI
+ UpdateUI();
+}
+
void
LobbyDialogDelegate::ProcessGameInfo(DynamicPacket &packet)
{
@@ -540,7 +624,19 @@ LobbyDialogDelegate::ProcessGameInfo(DynamicPacket &packet)
return;
}
- if (m_state != STATE_LISTING) {
+ if (m_state == STATE_LISTING) {
+ // Add or update the game list
+ int i;
+ for (i = 0; i < m_gameList.length(); ++i) {
+ if (game.gameID == m_gameList[i].gameID) {
+ m_gameList[i].CopyFrom(game);
+ break;
+ }
+ }
+ if (i == m_gameList.length()) {
+ m_gameList.add(game);
+ }
+ } else {
if (game.gameID != m_game.gameID) {
// Probably an old packet...
return;
@@ -551,31 +647,36 @@ LobbyDialogDelegate::ProcessGameInfo(DynamicPacket &packet)
if (m_state == STATE_JOINING) {
if (m_game.HasPlayer(m_uniqueID)) {
// We successfully joined the game
- m_state = STATE_JOINED;
+ SetState(STATE_JOINED);
}
} else {
if (!m_game.HasPlayer(m_uniqueID)) {
// We were kicked from the game
- m_state = STATE_LISTING;
+ SetState(STATE_LISTING);
}
}
}
- if (m_state == STATE_LISTING) {
- // Add or update the game list
- int i;
- for (i = 0; i < m_gameList.length(); ++i) {
- if (game.gameID == m_gameList[i].gameID) {
- m_gameList[i].CopyFrom(game);
- break;
- }
- }
- if (i == m_gameList.length()) {
- m_gameList.add(game);
- }
+ UpdateUI();
+}
+
+void
+LobbyDialogDelegate::ProcessKick(DynamicPacket &packet)
+{
+ Uint32 gameID;
+ Uint32 playerID;
+
+ if (m_state != STATE_JOINING && m_state != STATE_JOINED) {
+ return;
+ }
+ if (!packet.Read(gameID) || gameID != m_game.gameID) {
+ return;
+ }
+ if (!packet.Read(playerID) || playerID != m_uniqueID) {
+ return;
}
- UpdateUI();
+ SetState(STATE_LISTING);
}
void
diff --git a/netlogic/lobby.h b/netlogic/lobby.h
index 9ee95bd9..a33a5a52 100644
--- a/netlogic/lobby.h
+++ b/netlogic/lobby.h
@@ -62,6 +62,9 @@ class LobbyDialogDelegate : public UIDialogDelegate
void GetGameList();
void GetGameInfo();
void JoinGame(GameInfo &game);
+ void SendJoinRequest();
+ void SendLeaveRequest();
+ void SendKick(int index);
void ClearGameInfo();
void ClearGameList();
@@ -72,14 +75,16 @@ class LobbyDialogDelegate : public UIDialogDelegate
void ProcessAnnouncePlayer(DynamicPacket &packet);
void ProcessRequestGameInfo(DynamicPacket &packet);
void ProcessRequestJoin(DynamicPacket &packet);
+ void ProcessRequestLeave(DynamicPacket &packet);
void ProcessGameServerList(DynamicPacket &packet);
void ProcessGameInfo(DynamicPacket &packet);
+ void ProcessKick(DynamicPacket &packet);
protected:
IPaddress m_globalServer;
array<IPaddress> m_addresses;
- enum {
+ enum LOBBY_STATE {
STATE_NONE,
STATE_HOSTING,
STATE_LISTING,
@@ -103,6 +108,9 @@ class LobbyDialogDelegate : public UIDialogDelegate
UIElement *m_gameInfoArea;
UIElement *m_gameInfoPlayers[MAX_PLAYERS];
UIElement *m_playButton;
+
+protected:
+ void SetState(LOBBY_STATE state);
};
#endif // _lobby_h
diff --git a/netlogic/protocol.h b/netlogic/protocol.h
index fc69178c..40185b26 100644
--- a/netlogic/protocol.h
+++ b/netlogic/protocol.h
@@ -151,7 +151,6 @@ enum LobbyProtocol {
LOBBY_REQUEST_JOIN,
/* Sent by the joining game
- Uint32 sequence;
Uint32 gameID
Uint32 playerID
Uint8 namelen
@@ -161,7 +160,13 @@ enum LobbyProtocol {
LOBBY_REQUEST_LEAVE,
/* Sent by the joining game
- Uint32 sequence;
+ Uint32 gameID
+ Uint32 playerID
+ */
+
+ LOBBY_KICK,
+ /* Sent by the hosting game
+
Uint32 gameID
Uint32 playerID
*/