https://github.com/libsdl-org/Maelstrom/commit/39c1364a76d3dfcde62ef6aee07659ead81d9475
From 39c1364a76d3dfcde62ef6aee07659ead81d9475 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Fri, 18 Nov 2011 00:49:06 -0500
Subject: [PATCH] Split the concept of network node and player so we can
potentially have the hosting game have multiple local players.
---
game/gameinfo.cpp | 234 +++++++++++++++++++++++++++++++++-------------
game/gameinfo.h | 97 ++++++++-----------
game/lobby.cpp | 137 +++++++++++++++------------
game/lobby.h | 1 -
game/main.cpp | 2 +-
game/protocol.h | 5 +-
6 files changed, 293 insertions(+), 183 deletions(-)
diff --git a/game/gameinfo.cpp b/game/gameinfo.cpp
index 9795e4ee..34c9d420 100644
--- a/game/gameinfo.cpp
+++ b/game/gameinfo.cpp
@@ -47,22 +47,30 @@ GameInfo::SetSinglePlayer(Uint8 wave, Uint8 lives, Uint8 turbo)
}
void
-GameInfo::SetMultiplayerHost(Uint32 gameID, Uint8 deathMatch, const char *name)
+GameInfo::SetMultiplayerHost(Uint8 deathMatch, const char *name)
{
- this->gameID = gameID;
+ this->gameID = localID;
this->seed = GetRandSeed();
this->wave = DEFAULT_START_WAVE;
this->lives = DEFAULT_START_LIVES;
this->turbo = DEFAULT_START_TURBO;
this->deathMatch = deathMatch;
- players[HOST_PLAYER].playerID = gameID;
- SDL_strlcpy(players[HOST_PLAYER].name, name ? name : "",
- sizeof(players[HOST_PLAYER].name));
+
+ // We are the host node
+ nodes[HOST_NODE].nodeID = localID;
+
+ // We are the first player
+ GameInfoPlayer *player = GetPlayer(0);
+ player->nodeID = localID;
+ SDL_strlcpy(player->name, name ? name : "", sizeof(player->name));
+ player->controlMask = (CONTROL_KEYBOARD|CONTROL_JOYSTICK1);
}
void
GameInfo::CopyFrom(const GameInfo &rhs)
{
+ int i;
+
gameID = rhs.gameID;
seed = rhs.seed;
wave = rhs.wave;
@@ -70,23 +78,30 @@ GameInfo::CopyFrom(const GameInfo &rhs)
turbo = rhs.turbo;
deathMatch = rhs.deathMatch;
- for (int i = 0; i < MAX_PLAYERS; ++i) {
- players[i].playerID = rhs.players[i].playerID;
- SDL_strlcpy(players[i].name, rhs.players[i].name,
- sizeof(players[i].name));
- if (players[i].address != rhs.players[i].address) {
- players[i].address = rhs.players[i].address;
+ for (i = 0; i < MAX_NODES; ++i) {
+ nodes[i].nodeID = rhs.nodes[i].nodeID;
+ if (nodes[i].address != rhs.nodes[i].address) {
+ nodes[i].address = rhs.nodes[i].address;
// Reset the ping info
InitializePing(i);
}
}
+
+ for (i = 0; i < MAX_PLAYERS; ++i) {
+ players[i].nodeID = rhs.players[i].nodeID;
+ SDL_strlcpy(players[i].name, rhs.players[i].name,
+ sizeof(players[i].name));
+ }
+
UpdateUI();
}
bool
GameInfo::ReadFromPacket(DynamicPacket &packet)
{
+ int i;
+
if (!packet.Read(gameID)) {
return false;
}
@@ -106,14 +121,20 @@ GameInfo::ReadFromPacket(DynamicPacket &packet)
return false;
}
- for (int i = 0; i < MAX_PLAYERS; ++i) {
- if (!packet.Read(players[i].playerID)) {
+ for (i = 0; i < MAX_NODES; ++i) {
+ if (!packet.Read(nodes[i].nodeID)) {
return false;
}
- if (!packet.Read(players[i].address.host)) {
+ if (!packet.Read(nodes[i].address.host)) {
return false;
}
- if (!packet.Read(players[i].address.port)) {
+ if (!packet.Read(nodes[i].address.port)) {
+ return false;
+ }
+ }
+
+ for (i = 0; i < MAX_PLAYERS; ++i) {
+ if (!packet.Read(players[i].nodeID)) {
return false;
}
if (!packet.Read(players[i].name, sizeof(players[i].name))) {
@@ -123,8 +144,8 @@ GameInfo::ReadFromPacket(DynamicPacket &packet)
// We want to get the public address of the server
// If we already have one, we assume that's the fastest interface
- if (!players[HOST_PLAYER].address.host) {
- players[HOST_PLAYER].address = packet.address;
+ if (!nodes[HOST_NODE].address.host) {
+ nodes[HOST_NODE].address = packet.address;
}
return true;
@@ -133,6 +154,8 @@ GameInfo::ReadFromPacket(DynamicPacket &packet)
void
GameInfo::WriteToPacket(DynamicPacket &packet)
{
+ int i;
+
packet.Write(gameID);
packet.Write(seed);
packet.Write(wave);
@@ -140,14 +163,79 @@ GameInfo::WriteToPacket(DynamicPacket &packet)
packet.Write(turbo);
packet.Write(deathMatch);
- for (int i = 0; i < MAX_PLAYERS; ++i) {
- packet.Write(players[i].playerID);
- packet.Write(players[i].address.host);
- packet.Write(players[i].address.port);
+ for (i = 0; i < MAX_NODES; ++i) {
+ packet.Write(nodes[i].nodeID);
+ packet.Write(nodes[i].address.host);
+ packet.Write(nodes[i].address.port);
+ }
+
+ for (i = 0; i < MAX_PLAYERS; ++i) {
+ packet.Write(players[i].nodeID);
packet.Write(players[i].name);
}
}
+bool
+GameInfo::HasNode(Uint32 nodeID)
+{
+ for (int i = 0; i < MAX_NODES; ++i) {
+ if (nodes[i].nodeID == nodeID) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+GameInfo::HasNode(const IPaddress &address)
+{
+ for (int i = 0; i < MAX_NODES; ++i) {
+ if (nodes[i].address == address) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void
+GameInfo::RemoveNode(Uint32 nodeID)
+{
+ int i;
+ for (i = 0; i < MAX_NODES; ++i) {
+ if (nodeID == nodes[i].nodeID) {
+ SDL_zero(nodes[i]);
+ }
+ }
+ for (i = 0; i < MAX_PLAYERS; ++i) {
+ if (nodeID == players[i].nodeID) {
+ SDL_zero(players[i]);
+ }
+ }
+}
+
+bool
+GameInfo::IsNetworkNode(int index)
+{
+ if (!nodes[index].nodeID) {
+ return false;
+ }
+ if (nodes[index].nodeID == localID) {
+ return false;
+ }
+ return true;
+}
+
+bool
+GameInfo::IsFull()
+{
+ for (int i = 0; i < MAX_PLAYERS; ++i) {
+ if (!players[i].nodeID) {
+ return false;
+ }
+ }
+ return true;
+}
+
void
GameInfo::BindPlayerToUI(int index, UIElement *element)
{
@@ -195,40 +283,41 @@ GameInfo::UpdateUI(GameInfoPlayer *player)
}
}
if (player->UI.host) {
- if (player->playerID == localID) {
+ GameInfoNode *node = GetNodeByID(player->nodeID);
+ if (node->nodeID == localID) {
//player->UI.host->Show();
//player->UI.host->SetText("localhost");
player->UI.host->Hide();
- } else if (player->address.host) {
+ } else if (node->address.host) {
player->UI.host->Show();
- player->UI.host->SetText(SDLNet_ResolveIP(&player->address));
+ player->UI.host->SetText(SDLNet_ResolveIP(&node->address));
} else {
player->UI.host->Hide();
}
}
if (player->UI.control) {
- if (player->playerID == localID) {
+ if (player->nodeID == localID) {
player->UI.control->SetValue(CONTROL_KEYBOARD);
} else {
player->UI.control->SetValue(CONTROL_NETWORK);
}
}
if (player->UI.keyboard) {
- if (player->playerID == localID) {
+ if (player->nodeID == localID) {
player->UI.keyboard->Show();
} else {
player->UI.keyboard->Hide();
}
}
if (player->UI.joystick) {
- if (player->playerID == localID) {
+ if (player->nodeID == localID) {
player->UI.joystick->Show();
} else {
player->UI.joystick->Hide();
}
}
if (player->UI.network) {
- if (player->playerID != localID) {
+ if (player->nodeID != localID) {
player->UI.network->Show();
} else {
player->UI.network->Hide();
@@ -237,7 +326,7 @@ GameInfo::UpdateUI(GameInfoPlayer *player)
for (int i = 0; i < NUM_PING_STATES; ++i) {
UIElement *element = player->UI.ping_states[i];
if (element) {
- if (player->ping.status == i) {
+ if (GetNodeByID(player->nodeID)->ping.status == i) {
element->Show();
} else {
element->Hide();
@@ -249,7 +338,7 @@ GameInfo::UpdateUI(GameInfoPlayer *player)
void
GameInfo::InitializePing()
{
- for (int i = 0; i < MAX_PLAYERS; ++i) {
+ for (int i = 0; i < MAX_NODES; ++i) {
InitializePing(i);
}
}
@@ -257,11 +346,12 @@ GameInfo::InitializePing()
void
GameInfo::InitializePing(int index)
{
- if (IsNetworkPlayer(index)) {
- GameInfoPlayer *player = GetPlayer(index);
- player->ping.lastPing = SDL_GetTicks();
- player->ping.roundTripTime = 0;
- player->ping.status = PING_GOOD;
+ GameInfoNode *node = GetNode(index);
+
+ if (node->nodeID != localID) {
+ node->ping.lastPing = SDL_GetTicks();
+ node->ping.roundTripTime = 0;
+ node->ping.status = PING_GOOD;
}
}
@@ -270,25 +360,25 @@ GameInfo::UpdatePingTime(int index, Uint32 timestamp)
{
Uint32 now;
Uint32 elapsed;
- GameInfoPlayer *player;
+ GameInfoNode *node;
now = SDL_GetTicks();
elapsed = (now - timestamp);
- player = GetPlayer(index);
- player->ping.lastPing = now;
- if (!player->ping.roundTripTime) {
- player->ping.roundTripTime = elapsed;
+ node = GetNode(index);
+ node->ping.lastPing = now;
+ if (!node->ping.roundTripTime) {
+ node->ping.roundTripTime = elapsed;
} else {
// Use a weighted average 2/3 previous value, 1/3 new value
- player->ping.roundTripTime = (2*player->ping.roundTripTime + 1*elapsed) / 3;
+ node->ping.roundTripTime = (2*node->ping.roundTripTime + 1*elapsed) / 3;
}
}
void
GameInfo::UpdatePingStatus()
{
- for (int i = 0; i < MAX_PLAYERS; ++i) {
+ for (int i = 0; i < MAX_NODES; ++i) {
UpdatePingStatus(i);
}
}
@@ -296,47 +386,63 @@ GameInfo::UpdatePingStatus()
void
GameInfo::UpdatePingStatus(int index)
{
- GameInfoPlayer *player = GetPlayer(index);
+ GameInfoNode *node = GetNode(index);
- if (!IsNetworkPlayer(index)) {
- player->ping.status = PING_LOCAL;
+ if (!IsNetworkNode(index)) {
+ node->ping.status = PING_LOCAL;
} else {
Uint32 sinceLastPing;
- sinceLastPing = int(SDL_GetTicks() - player->ping.lastPing);
+ sinceLastPing = int(SDL_GetTicks() - node->ping.lastPing);
if (sinceLastPing < 2*PING_INTERVAL) {
- if (player->ping.roundTripTime <= 2*FRAME_DELAY_MS) {
+ if (node->ping.roundTripTime <= 2*FRAME_DELAY_MS) {
#ifdef DEBUG_NETWORK
-printf("Game 0x%8.8x: player 0x%8.8x round trip time %d (GOOD)\n",
- gameID, player->playerID, player->ping.roundTripTime);
+printf("Game 0x%8.8x: node 0x%8.8x round trip time %d (GOOD)\n",
+ gameID, node->nodeID, node->ping.roundTripTime);
#endif
- player->ping.status = PING_GOOD;
- } else if (player->ping.roundTripTime <= 3*FRAME_DELAY_MS) {
+ node->ping.status = PING_GOOD;
+ } else if (node->ping.roundTripTime <= 3*FRAME_DELAY_MS) {
#ifdef DEBUG_NETWORK
-printf("Game 0x%8.8x: player 0x%8.8x round trip time %d (OKAY)\n",
- gameID, player->playerID, player->ping.roundTripTime);
+printf("Game 0x%8.8x: node 0x%8.8x round trip time %d (OKAY)\n",
+ gameID, node->nodeID, node->ping.roundTripTime);
#endif
- player->ping.status = PING_OKAY;
+ node->ping.status = PING_OKAY;
} else {
#ifdef DEBUG_NETWORK
-printf("Game 0x%8.8x: player 0x%8.8x round trip time %d (BAD)\n",
- gameID, player->playerID, player->ping.roundTripTime);
+printf("Game 0x%8.8x: node 0x%8.8x round trip time %d (BAD)\n",
+ gameID, node->nodeID, node->ping.roundTripTime);
#endif
- player->ping.status = PING_BAD;
+ node->ping.status = PING_BAD;
}
} else if (sinceLastPing < PING_TIMEOUT) {
#ifdef DEBUG_NETWORK
-printf("Game 0x%8.8x: player 0x%8.8x since last ping %d (BAD)\n",
- gameID, player->playerID, sinceLastPing);
+printf("Game 0x%8.8x: node 0x%8.8x since last ping %d (BAD)\n",
+ gameID, node->nodeID, sinceLastPing);
#endif
- player->ping.status = PING_BAD;
+ node->ping.status = PING_BAD;
} else {
#ifdef DEBUG_NETWORK
-printf("Game 0x%8.8x: player 0x%8.8x since last ping %d (TIMEDOUT)\n",
- gameID, player->playerID, sinceLastPing);
+printf("Game 0x%8.8x: node 0x%8.8x since last ping %d (TIMEDOUT)\n",
+ gameID, node->nodeID, sinceLastPing);
#endif
- player->ping.status = PING_TIMEDOUT;
+ node->ping.status = PING_TIMEDOUT;
}
}
- UpdateUI(player);
+
+ // Update the UI for matching players
+ for (int i = 0; i < MAX_PLAYERS; ++i) {
+ if (players[i].nodeID == node->nodeID) {
+ UpdateUI(&players[i]);
+ }
+ }
+}
+
+PING_STATUS
+GameInfo::GetPingStatus(int index)
+{
+ if (IsNetworkNode(index)) {
+ return nodes[index].ping.status;
+ } else {
+ return PING_LOCAL;
+ }
}
diff --git a/game/gameinfo.h b/game/gameinfo.h
index 969c8819..8792331b 100644
--- a/game/gameinfo.h
+++ b/game/gameinfo.h
@@ -30,7 +30,7 @@ class UIElement;
class UIElementCheckbox;
class UIElementRadioGroup;
-enum {
+enum PLAYER_CONTROL {
CONTROL_KEYBOARD = 1,
CONTROL_JOYSTICK,
CONTROL_NETWORK,
@@ -45,11 +45,11 @@ enum PING_STATUS {
NUM_PING_STATES
};
-struct GameInfoPlayer
+// This represents a physical machine (host/port combo) on the network
+struct GameInfoNode
{
- Uint32 playerID;
+ Uint32 nodeID;
IPaddress address;
- char name[MAX_NAMELEN+1];
struct {
Uint32 lastPing;
@@ -57,6 +57,20 @@ struct GameInfoPlayer
PING_STATUS status;
} ping;
+};
+
+// This represents a player in the game, on a particular network node
+//
+// The hosting node may have any number of players
+// The other nodes may each only have one player, to simplify things
+// like the join/leave/kick process.
+//
+struct GameInfoPlayer
+{
+ Uint32 nodeID;
+ char name[MAX_NAMELEN+1];
+ Uint8 controlMask;
+
struct {
UIElement *element;
UIElementCheckbox *enabled;
@@ -84,10 +98,10 @@ class GameInfo
void SetSinglePlayer(Uint8 wave, Uint8 lives, Uint8 turbo);
- void SetMultiplayerHost(Uint32 gameID, Uint8 deathMatch, const char *name);
+ void SetMultiplayerHost(Uint8 deathMatch, const char *name);
- void SetLocalID(Uint32 playerID) {
- localID = playerID;
+ void SetLocalID(Uint32 uniqueID) {
+ localID = uniqueID;
}
void CopyFrom(const GameInfo &rhs);
@@ -95,56 +109,33 @@ class GameInfo
bool ReadFromPacket(DynamicPacket &packet);
void WriteToPacket(DynamicPacket &packet);
- GameInfoPlayer *GetHost() {
- return GetPlayer(HOST_PLAYER);
+ GameInfoNode *GetHost() {
+ return GetNode(HOST_NODE);
}
- GameInfoPlayer *GetPlayer(int index) {
- return &players[index];
+ GameInfoNode *GetNode(int index) {
+ return &nodes[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) {
- if (players[i].playerID == playerID) {
- return true;
+ GameInfoNode *GetNodeByID(Uint32 nodeID) {
+ for (int i = 0; i < MAX_NODES; ++i) {
+ if (nodeID == nodes[i].nodeID) {
+ return &nodes[i];
}
}
- return false;
}
- bool HasPlayer(const IPaddress &address) {
- for (int i = 0; i < MAX_PLAYERS; ++i) {
- if (players[i].address == address) {
- return true;
- }
- }
- return false;
+ GameInfoPlayer *GetPlayer(int index) {
+ return &players[index];
}
- bool IsNetworkPlayer(int index) {
- if (!players[index].playerID) {
- return false;
- }
- if (players[index].playerID == localID) {
- return false;
- }
- return true;
- }
+ bool HasNode(Uint32 nodeID);
+ bool HasNode(const IPaddress &address);
+ void RemoveNode(Uint32 nodeID);
- bool IsFull() {
- for (int i = 0; i < MAX_PLAYERS; ++i) {
- if (!players[i].playerID) {
- return false;
- }
- }
- return true;
+ bool IsHosting() {
+ return localID == gameID;
}
+ bool IsNetworkNode(int index);
+
+ bool IsFull();
void BindPlayerToUI(int index, UIElement *element);
void UpdateUI();
@@ -155,14 +146,7 @@ class GameInfo
void UpdatePingTime(int index, Uint32 timestamp);
void UpdatePingStatus();
void UpdatePingStatus(int index);
-
- PING_STATUS GetPingStatus(int index) {
- if (IsNetworkPlayer(index)) {
- return players[index].ping.status;
- } else {
- return PING_LOCAL;
- }
- }
+ PING_STATUS GetPingStatus(int index);
public:
Uint32 gameID;
@@ -171,6 +155,7 @@ class GameInfo
Uint8 lives;
Uint8 turbo;
Uint8 deathMatch;
+ GameInfoNode nodes[MAX_NODES];
GameInfoPlayer players[MAX_PLAYERS];
Uint32 localID;
diff --git a/game/lobby.cpp b/game/lobby.cpp
index 763e1016..2702e720 100644
--- a/game/lobby.cpp
+++ b/game/lobby.cpp
@@ -46,7 +46,6 @@ LobbyDialogDelegate::LobbyDialogDelegate(UIPanel *panel) :
m_game(gGameInfo)
{
m_state = STATE_NONE;
- m_uniqueID = 0;
m_lastPing = 0;
m_lastRefresh = 0;
m_requestSequence = 1;
@@ -159,11 +158,12 @@ LobbyDialogDelegate::OnHide()
for (int i = 0; i < MAX_PLAYERS; ++i) {
GameInfoPlayer *player = m_game.GetPlayer(i);
- if (player->playerID) {
- if (player->playerID == m_game.localID) {
+ if (player->nodeID) {
+ if (player->nodeID == m_game.localID) {
AddLocalPlayer(i);
} else {
- AddNetworkPlayer(i, player->address);
+ GameInfoNode *node = m_game.GetNodeByID(player->nodeID);
+ AddNetworkPlayer(i, node->address);
}
}
}
@@ -227,8 +227,11 @@ LobbyDialogDelegate::SetHostOrJoin(void*, int value)
return;
}
- m_uniqueID = rand();
- m_game.SetLocalID(m_uniqueID);
+ Uint32 localID = rand();
+ while (localID <= 1) {
+ localID = rand();
+ }
+ m_game.SetLocalID(localID);
if (value == HOST_GAME) {
SetState(STATE_HOSTING);
@@ -285,7 +288,7 @@ LobbyDialogDelegate::UpdateUI()
for (int i = 0; (unsigned)i < SDL_arraysize(m_gameListElements); ++i) {
if (i < m_gameList.length()) {
m_gameListElements[i]->Show();
- m_gameList[i].BindPlayerToUI(HOST_PLAYER, m_gameListElements[i]);
+ m_gameList[i].BindPlayerToUI(0, m_gameListElements[i]);
} else {
m_gameListElements[i]->Hide();
}
@@ -315,7 +318,7 @@ LobbyDialogDelegate::SetState(LOBBY_STATE state)
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) {
+ for (int i = 0; i < MAX_NODES; ++i) {
SendKick(i);
}
} else if (m_state == STATE_JOINING ||
@@ -324,7 +327,7 @@ LobbyDialogDelegate::SetState(LOBBY_STATE state)
SendLeaveRequest();
}
} else if (state == STATE_HOSTING) {
- m_game.SetMultiplayerHost(m_uniqueID,
+ m_game.SetMultiplayerHost(
prefs->GetNumber(PREFERENCES_DEATHMATCH),
prefs->GetString(PREFERENCES_HANDLE));
} else if (state == STATE_LISTING) {
@@ -353,8 +356,8 @@ LobbyDialogDelegate::CheckPings()
int i = 0;
while (i < m_gameList.length()) {
GameInfo &game = m_gameList[i];
- game.UpdatePingStatus(HOST_PLAYER);
- if (game.GetPingStatus(HOST_PLAYER) == PING_TIMEDOUT) {
+ game.UpdatePingStatus(HOST_NODE);
+ if (game.GetPingStatus(HOST_NODE) == PING_TIMEDOUT) {
//printf("Game timed out, removing from list\n");
m_gameList.remove(game);
removed = true;
@@ -367,7 +370,7 @@ LobbyDialogDelegate::CheckPings()
}
} else if (m_state == STATE_HOSTING) {
m_game.UpdatePingStatus();
- for (int i = 0; i < MAX_PLAYERS; ++i) {
+ for (int i = 0; i < MAX_NODES; ++i) {
if (m_game.GetPingStatus(i) == PING_TIMEDOUT) {
//printf("Player timed out, removing from lobby\n");
SendKick(i);
@@ -375,7 +378,7 @@ LobbyDialogDelegate::CheckPings()
}
} else if (m_state == STATE_JOINED) {
m_game.UpdatePingStatus();
- if (m_game.GetPingStatus(HOST_PLAYER) == PING_TIMEDOUT) {
+ if (m_game.GetPingStatus(HOST_NODE) == PING_TIMEDOUT) {
//printf("Game timed out, leaving lobbyn");
SetState(STATE_LISTING);
}
@@ -386,12 +389,12 @@ LobbyDialogDelegate::CheckPings()
// Send pings to everyone who is still here
m_packet.StartLobbyMessage(LOBBY_PING);
m_packet.Write(m_game.gameID);
- m_packet.Write(m_uniqueID);
+ m_packet.Write(m_game.localID);
m_packet.Write(SDL_GetTicks());
- for (int i = 0; i < MAX_PLAYERS; ++i) {
- if (m_game.IsNetworkPlayer(i)) {
- m_packet.address = m_game.GetPlayer(i)->address;
+ for (int i = 0; i < MAX_NODES; ++i) {
+ if (m_game.IsNetworkNode(i)) {
+ m_packet.address = m_game.GetNode(i)->address;
SDLNet_UDP_Send(gNetFD, -1, &m_packet);
}
@@ -464,7 +467,7 @@ LobbyDialogDelegate::SendJoinRequest()
{
m_packet.StartLobbyMessage(LOBBY_REQUEST_JOIN);
m_packet.Write(m_game.gameID);
- m_packet.Write(m_uniqueID);
+ m_packet.Write(m_game.localID);
m_packet.Write(prefs->GetString(PREFERENCES_HANDLE));
m_packet.address = m_game.GetHost()->address;
@@ -476,7 +479,7 @@ LobbyDialogDelegate::SendLeaveRequest()
{
m_packet.StartLobbyMessage(LOBBY_REQUEST_LEAVE);
m_packet.Write(m_game.gameID);
- m_packet.Write(m_uniqueID);
+ m_packet.Write(m_game.localID);
m_packet.address = m_game.GetHost()->address;
SDLNet_UDP_Send(gNetFD, -1, &m_packet);
@@ -485,22 +488,22 @@ LobbyDialogDelegate::SendLeaveRequest()
void
LobbyDialogDelegate::SendKick(int index)
{
- GameInfoPlayer *player;
+ GameInfoNode *node;
- if (!m_game.IsNetworkPlayer(index)) {
+ if (!m_game.IsNetworkNode(index)) {
return;
}
- player = m_game.GetPlayer(index);
+ node = m_game.GetNode(index);
m_packet.StartLobbyMessage(LOBBY_KICK);
m_packet.Write(m_game.gameID);
- m_packet.Write(player->playerID);
- m_packet.address = player->address;
+ m_packet.Write(node->nodeID);
+ m_packet.address = node->address;
SDLNet_UDP_Send(gNetFD, -1, &m_packet);
// Now remove them from the game list
- SDL_zero(*player);
+ m_game.RemoveNode(node->nodeID);
// Update our own UI
UpdateUI();
@@ -558,7 +561,7 @@ LobbyDialogDelegate::ProcessPacket(DynamicPacket &packet)
return;
}
- if (m_game.IsFull() && !m_game.HasPlayer(packet.address)) {
+ if (m_game.IsFull() && !m_game.HasNode(packet.address)) {
return;
}
@@ -602,7 +605,7 @@ void
LobbyDialogDelegate::ProcessPing(DynamicPacket &packet)
{
Uint32 gameID;
- Uint32 playerID;
+ Uint32 nodeID;
Uint32 timestamp;
if (m_state != STATE_HOSTING && m_state != STATE_JOINED) {
@@ -611,7 +614,7 @@ LobbyDialogDelegate::ProcessPing(DynamicPacket &packet)
if (!packet.Read(gameID) || gameID != m_game.gameID) {
return;
}
- if (!packet.Read(playerID) || !m_game.HasPlayer(playerID)) {
+ if (!packet.Read(nodeID) || !m_game.HasNode(nodeID)) {
return;
}
if (!packet.Read(timestamp)) {
@@ -620,7 +623,7 @@ LobbyDialogDelegate::ProcessPing(DynamicPacket &packet)
m_reply.StartLobbyMessage(LOBBY_PONG);
m_reply.Write(gameID);
- m_reply.Write(playerID);
+ m_reply.Write(nodeID);
m_reply.Write(timestamp);
m_reply.address = packet.address;
@@ -631,7 +634,7 @@ void
LobbyDialogDelegate::ProcessPong(DynamicPacket &packet)
{
Uint32 gameID;
- Uint32 playerID;
+ Uint32 nodeID;
Uint32 timestamp;
if (m_state != STATE_HOSTING && m_state != STATE_JOINED) {
@@ -640,15 +643,15 @@ LobbyDialogDelegate::ProcessPong(DynamicPacket &packet)
if (!packet.Read(gameID) || gameID != m_game.gameID) {
return;
}
- if (!packet.Read(playerID) || playerID != m_uniqueID) {
+ if (!packet.Read(nodeID) || nodeID != m_game.localID) {
return;
}
if (!packet.Read(timestamp)) {
return;
}
- for (int i = 0; i < MAX_PLAYERS; ++i) {
- if (packet.address == m_game.players[i].address) {
+ for (int i = 0; i < MAX_NODES; ++i) {
+ if (packet.address == m_game.GetNode(i)->address) {
m_game.UpdatePingTime(i, timestamp);
}
}
@@ -666,9 +669,13 @@ LobbyDialogDelegate::ProcessNewGame(DynamicPacket &packet)
if (!packet.Read(gameID) || gameID != m_game.gameID) {
return;
}
+ if (m_game.IsHosting()) {
+ // They can't tell us to start!
+ return;
+ }
// Ooh, ooh, they're starting!
- if (m_game.HasPlayer(packet.address)) {
+ if (m_game.HasNode(packet.address)) {
m_playButton->OnClick();
}
}
@@ -717,13 +724,13 @@ void
LobbyDialogDelegate::ProcessRequestJoin(DynamicPacket &packet)
{
Uint32 gameID;
- Uint32 playerID;
+ Uint32 nodeID;
char name[MAX_NAMELEN+1];
if (!packet.Read(gameID) || gameID != m_game.gameID) {
return;
}
- if (!packet.Read(playerID)) {
+ if (!packet.Read(nodeID)) {
return;
}
if (!packet.Read(name, sizeof(name))) {
@@ -732,35 +739,45 @@ LobbyDialogDelegate::ProcessRequestJoin(DynamicPacket &packet)
// Find an empty slot
int slot;
- for (slot = 0; slot < MAX_PLAYERS; ++slot) {
- if (playerID == m_game.players[slot].playerID) {
- // We already have this player, ignore it
+ for (slot = 0; slot < MAX_NODES; ++slot) {
+ if (nodeID == m_game.nodes[slot].nodeID) {
+ // We already have this node, ignore it
return;
}
}
- if (slot == MAX_PLAYERS) {
- for (slot = 0; slot < MAX_PLAYERS; ++slot) {
- if (!m_game.players[slot].playerID) {
+ if (slot == MAX_NODES) {
+ for (slot = 0; slot < MAX_NODES; ++slot) {
+ if (!m_game.nodes[slot].nodeID) {
break;
}
}
}
+ assert(slot < MAX_NODES);
+
+ GameInfoNode *node = m_game.GetNode(slot);
+ node->nodeID = nodeID;
+ node->address = packet.address;
+ m_game.InitializePing(slot);
+
+ for (slot = 0; slot < MAX_PLAYERS; ++slot) {
+ if (!m_game.players[slot].nodeID) {
+ break;
+ }
+ }
assert(slot < MAX_PLAYERS);
- // Fill in the data
GameInfoPlayer *player = m_game.GetPlayer(slot);
- player->playerID = playerID;
- player->address = packet.address;
+ player->nodeID = nodeID;
SDL_strlcpy(player->name, name, sizeof(player->name));
- m_game.InitializePing(slot);
+ player->controlMask = CONTROL_NETWORK;
// Let everybody know!
m_reply.StartLobbyMessage(LOBBY_GAME_INFO);
m_reply.Write((Uint32)0);
m_game.WriteToPacket(m_reply);
- for (slot = 0; slot < MAX_PLAYERS; ++slot) {
- if (m_game.IsNetworkPlayer(slot)) {
- m_reply.address = m_game.players[slot].address;
+ for (slot = 0; slot < MAX_NODES; ++slot) {
+ if (m_game.IsNetworkNode(slot)) {
+ m_reply.address = m_game.nodes[slot].address;
SDLNet_UDP_Send(gNetFD, -1, &m_reply);
}
}
@@ -773,18 +790,20 @@ void
LobbyDialogDelegate::ProcessRequestLeave(DynamicPacket &packet)
{
Uint32 gameID;
- Uint32 playerID;
+ Uint32 nodeID;
if (!packet.Read(gameID) || gameID != m_game.gameID) {
return;
}
- if (!packet.Read(playerID) || !m_game.HasPlayer(playerID)) {
+ if (!packet.Read(nodeID) || !m_game.HasNode(nodeID)) {
+ return;
+ }
+ if (nodeID == m_game.localID) {
return;
}
// Okay, clear them from the list!
- GameInfoPlayer *player = m_game.GetPlayerByID(playerID);
- SDL_zero(*player);
+ m_game.RemoveNode(nodeID);
// Update our own UI
UpdateUI();
@@ -818,8 +837,8 @@ LobbyDialogDelegate::ProcessGameInfo(DynamicPacket &packet)
m_gameList.add(game);
}
if (timestamp) {
- m_gameList[i].UpdatePingTime(HOST_PLAYER, timestamp);
- m_gameList[i].UpdatePingStatus(HOST_PLAYER);
+ m_gameList[i].UpdatePingTime(HOST_NODE, timestamp);
+ m_gameList[i].UpdatePingStatus(HOST_NODE);
}
} else {
if (game.gameID != m_game.gameID) {
@@ -830,12 +849,12 @@ LobbyDialogDelegate::ProcessGameInfo(DynamicPacket &packet)
m_game.CopyFrom(game);
if (m_state == STATE_JOINING) {
- if (m_game.HasPlayer(m_uniqueID)) {
+ if (m_game.HasNode(m_game.localID)) {
// We successfully joined the game
SetState(STATE_JOINED);
}
} else {
- if (!m_game.HasPlayer(m_uniqueID)) {
+ if (!m_game.HasNode(m_game.localID)) {
// We were kicked from the game
SetState(STATE_LISTING);
}
@@ -849,7 +868,7 @@ void
LobbyDialogDelegate::ProcessKick(DynamicPacket &packet)
{
Uint32 gameID;
- Uint32 playerID;
+ Uint32 nodeID;
if (m_state != STATE_JOINING && m_state != STATE_JOINED) {
return;
@@ -857,7 +876,7 @@ LobbyDialogDelegate::ProcessKick(DynamicPacket &packet)
if (!packet.Read(gameID) || gameID != m_game.gameID) {
return;
}
- if (!packet.Read(playerID) || playerID != m_uniqueID) {
+ if (!packet.Read(nodeID) || nodeID != m_game.localID) {
return;
}
diff --git a/game/lobby.h b/game/lobby.h
index 562dac25..d0249c14 100644
--- a/game/lobby.h
+++ b/game/lobby.h
@@ -97,7 +97,6 @@ class LobbyDialogDelegate : public UIDialogDelegate
STATE_PLAYING
} m_state;
- Uint32 m_uniqueID;
Uint32 m_lastPing;
Uint32 m_lastRefresh;
Uint32 m_requestSequence;
diff --git a/game/main.cpp b/game/main.cpp
index 499fba6b..37ae7c3a 100644
--- a/game/main.cpp
+++ b/game/main.cpp
@@ -67,7 +67,7 @@ static void RunSinglePlayerGame()
if (InitNetData(false) < 0) {
return;
}
- AddLocalPlayer(HOST_PLAYER);
+ AddLocalPlayer(0);
NewGame();
HaltNetData();
}
diff --git a/game/protocol.h b/game/protocol.h
index 23a64698..2b89c80e 100644
--- a/game/protocol.h
+++ b/game/protocol.h
@@ -197,9 +197,10 @@ enum LobbyProtocol {
array in player.cpp
*/
#define MAX_PLAYERS 3
+#define MAX_NODES MAX_PLAYERS
-/* The index of the player hosting the game */
-#define HOST_PLAYER 0
+/* The index of the node hosting the game */
+#define HOST_NODE 0
/* If the other side hasn't responded in 3 seconds, we'll drop them */
#define PING_INTERVAL 1000