Maelstrom: Actually wire up the networked players and start a game together!

https://github.com/libsdl-org/Maelstrom/commit/d5c2b7aaeb76e53bfdab9da0a4dcd3df0a81bfc8

From d5c2b7aaeb76e53bfdab9da0a4dcd3df0a81bfc8 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Sun, 6 Nov 2011 10:57:27 -0500
Subject: [PATCH] Actually wire up the networked players and start a game
 together! At this point we have functional multiplayer from the lobby screen.
 Now we just have to handle the many edge cases and improve user flow.

---
 netlogic/gameinfo.h  | 45 ++++++++++++++++---------------
 netlogic/lobby.cpp   | 30 ++++++++++++++++++---
 netlogic/lobby.h     |  1 +
 netlogic/netplay.cpp | 64 ++++++++------------------------------------
 netlogic/netplay.h   |  5 ++--
 5 files changed, 66 insertions(+), 79 deletions(-)

diff --git a/netlogic/gameinfo.h b/netlogic/gameinfo.h
index 24facc3f..bde72ab7 100644
--- a/netlogic/gameinfo.h
+++ b/netlogic/gameinfo.h
@@ -36,6 +36,24 @@ enum {
 	CONTROL_NETWORK,
 };
 
+struct GameInfoPlayer
+{
+	Uint32 playerID;
+	IPaddress address;
+	char name[MAX_NAMELEN+1];
+
+	struct {
+		UIElementCheckbox *enabled;
+		UIElement *name;
+		UIElement *host;
+		UIElement *ping;
+		UIElementRadioGroup *control;
+		UIElement *keyboard;
+		UIElement *joystick;
+		UIElement *network;
+	} UI;
+};
+
 class GameInfo
 {
 public:
@@ -59,6 +77,10 @@ class GameInfo
 	bool ReadFromPacket(DynamicPacket &packet);
 	void WriteToPacket(DynamicPacket &packet);
 
+	GameInfoPlayer *GetPlayer(int index) {
+		return &players[index];
+	}
+
 	bool HasPlayer(Uint32 playerID) {
 		for (int i = 0; i < MAX_PLAYERS; ++i) {
 			if (players[i].playerID == playerID) {
@@ -86,34 +108,15 @@ class GameInfo
 	}
 
 	void BindPlayerToUI(int index, UIElement *element);
+	void UpdateUI();
+	void UpdateUI(GameInfoPlayer *player);
 
 public:
 	Uint32 gameID;
 	Uint8 deathMatch;
-
-	struct GameInfoPlayer {
-		Uint32 playerID;
-		IPaddress address;
-		char name[MAX_NAMELEN+1];
-
-		struct {
-			UIElementCheckbox *enabled;
-			UIElement *name;
-			UIElement *host;
-			UIElement *ping;
-			UIElementRadioGroup *control;
-			UIElement *keyboard;
-			UIElement *joystick;
-			UIElement *network;
-		} UI;
-	};
 	GameInfoPlayer players[MAX_PLAYERS];
 
 	Uint32 localID;
-
-protected:
-	void UpdateUI();
-	void UpdateUI(GameInfoPlayer *player);
 };
 
 #endif // _gameinfo_h
diff --git a/netlogic/lobby.cpp b/netlogic/lobby.cpp
index fea0cd91..00875bf1 100644
--- a/netlogic/lobby.cpp
+++ b/netlogic/lobby.cpp
@@ -25,6 +25,7 @@
 
 #include "SDL_net.h"
 #include "../Maelstrom_Globals.h"
+#include "../screenlib/UIElement.h"
 #include "../screenlib/UIElementCheckbox.h"
 #include "../screenlib/UIElementRadio.h"
 #include "lobby.h"
@@ -143,6 +144,16 @@ LobbyDialogDelegate::OnHide()
 {
 	// Start the game!
 	if (m_dialog->GetDialogStatus() > 0) {
+		for (int i = 0; i < MAX_PLAYERS; ++i) {
+			GameInfoPlayer *player = m_game.GetPlayer(i);
+			if (player->playerID) {
+				if (player->playerID == m_game.localID) {
+					AddLocalPlayer(i);
+				} else {
+					AddNetworkPlayer(i, player->address);
+				}
+			}
+		}
 		NewGame();
 	}
 
@@ -369,6 +380,9 @@ LobbyDialogDelegate::ProcessPacket(DynamicPacket &packet)
 		return;
 	}
 	if (cmd != LOBBY_MSG) {
+		if (cmd == NEW_GAME) {
+			ProcessNewGame(packet);
+		}
 		return;
 	}
 	if (!m_packet.Read(cmd)) {
@@ -419,6 +433,15 @@ LobbyDialogDelegate::ProcessPacket(DynamicPacket &packet)
 	}
 }
 
+void
+LobbyDialogDelegate::ProcessNewGame(DynamicPacket &packet)
+{
+	// Ooh, ooh, they're starting!
+	if (m_game.HasPlayer(packet.address)) {
+		m_playButton->OnClick();
+	}
+}
+
 void
 LobbyDialogDelegate::ProcessAnnouncePlayer(DynamicPacket &packet)
 {
@@ -487,7 +510,7 @@ LobbyDialogDelegate::ProcessRequestJoin(DynamicPacket &packet)
 	assert(slot < MAX_PLAYERS);
 
 	// Fill in the data
-	GameInfo::GameInfoPlayer *player = &m_game.players[slot];
+	GameInfoPlayer *player = m_game.GetPlayer(slot);
 	player->playerID = playerID;
 	player->address = packet.address;
 	SDL_strlcpy(player->name, name, sizeof(player->name));
@@ -496,9 +519,10 @@ LobbyDialogDelegate::ProcessRequestJoin(DynamicPacket &packet)
 	m_reply.StartLobbyMessage(LOBBY_GAME_INFO);
 	m_game.WriteToPacket(m_reply);
 	for (slot = 0; slot < MAX_PLAYERS; ++slot) {
-		Uint32 playerID = m_game.players[slot].playerID;
+		GameInfoPlayer *player = m_game.GetPlayer(slot);
+		Uint32 playerID = player->playerID;
 		if (playerID && playerID != m_uniqueID) {
-			m_reply.address = m_game.players[slot].address;
+			m_reply.address = player->address;
 			SDLNet_UDP_Send(gNetFD, -1, &m_reply);
 		}
 	}
diff --git a/netlogic/lobby.h b/netlogic/lobby.h
index 01ec2a29..9ee95bd9 100644
--- a/netlogic/lobby.h
+++ b/netlogic/lobby.h
@@ -68,6 +68,7 @@ class LobbyDialogDelegate : public UIDialogDelegate
 	void PackAddresses(DynamicPacket &packet);
 
 	void ProcessPacket(DynamicPacket &packet);
+	void ProcessNewGame(DynamicPacket &packet);
 	void ProcessAnnouncePlayer(DynamicPacket &packet);
 	void ProcessRequestGameInfo(DynamicPacket &packet);
 	void ProcessRequestJoin(DynamicPacket &packet);
diff --git a/netlogic/netplay.cpp b/netlogic/netplay.cpp
index 6d2460be..6af5016e 100644
--- a/netlogic/netplay.cpp
+++ b/netlogic/netplay.cpp
@@ -79,7 +79,7 @@ int InitNetData(bool hosting)
 
 	/* Initialize the networking subsystem */
 	if ( SDLNet_Init() < 0 ) {
-		error("Couldn't initialize networking: %s\n", SDL_GetError());
+		error("Couldn't initialize networking: %s\n", SDLNet_GetError());
 		return(-1);
 	}
 
@@ -91,7 +91,7 @@ int InitNetData(bool hosting)
 	}
 	gNetFD = SDLNet_UDP_Open(port);
 	if ( gNetFD == NULL ) {
-		error("Couldn't create bound network socket\n");
+		error("Couldn't create socket bound to port %d: %s\n", port, SDLNet_GetError());
 		return(-1);
 	}
 	SocketSet = SDLNet_AllocSocketSet(1);
@@ -147,59 +147,17 @@ void HaltNetData(void)
 	SDLNet_Quit();
 }
 
-int AddPlayer(const char *playerstr)
+void AddLocalPlayer(int playernum)
 {
-	int playernum;
-	int portnum;
-	char *host=NULL, *port=NULL;
-
-	/* Extract host and port information */
-	if ( (port=strchr(playerstr, ':')) != NULL )
-		*(port++) = '\0';
-	if ( (host=strchr(playerstr, '@')) != NULL )
-		*(host++) = '\0';
-
-	/* Find out which player we are referring to */
-	if (((playernum = atoi(playerstr)) <= 0) || (playernum > MAX_PLAYERS)) {
-		error(
-"Argument to '-player' must be in integer between 1 and %d inclusive.\r\n",
-								MAX_PLAYERS);
-		PrintUsage();
-	}
-
-	/* Do some error checking */
-	if ( GotPlayer[--playernum] ) {
-		error("Player %d specified multiple times!\r\n", playernum+1);
-		return(-1);
-	}
-	if ( port ) {
-		portnum = atoi(port);
-	} else {
-		portnum = NETPLAY_PORT+playernum;
-	}
-	if ( host ) {
-		/* Resolve the remote address */
-		SDLNet_ResolveHost(&PlayAddr[playernum], host, portnum);
-		if ( PlayAddr[playernum].host == INADDR_NONE ) {
-			error("Couldn't resolve host name for %s\r\n", host);
-			return(-1);
-		}
-	} else { /* No host specified, local player */
-		if ( FoundUs ) {
-			error(
-"More than one local player!  (players %d and %d specified as local players)\r\n",
-						gOurPlayer+1, playernum+1);
-			return(-1);
-		} else {
-			gOurPlayer = playernum;
-			FoundUs = 1;
-			SDLNet_ResolveHost(&PlayAddr[playernum], NULL, portnum);
-		}
-	}
+	gOurPlayer = playernum;
+	FoundUs = 1;
+	GotPlayer[playernum] = 1;
+}
 
-	/* We're done! */
+void AddNetworkPlayer(int playernum, const IPaddress &address)
+{
+	PlayAddr[playernum] = address;
 	GotPlayer[playernum] = 1;
-	return(0);
 }
 
 /* This MUST be called after command line options have been processed. */
@@ -214,7 +172,7 @@ int CheckPlayers(void)
 	}
 	/* Add ourselves if needed */
 	if ( gNumPlayers == 0 ) {
-		AddPlayer("1");
+		AddLocalPlayer(0);
 		gNumPlayers = 1;
 		FoundUs = 1;
 	}
diff --git a/netlogic/netplay.h b/netlogic/netplay.h
index 56e64d7d..65211462 100644
--- a/netlogic/netplay.h
+++ b/netlogic/netplay.h
@@ -20,13 +20,14 @@
     slouken@libsdl.org
 */
 
-// Forward declaration from SDL_net.h
-typedef struct _UDPsocket *UDPsocket;
+#include "SDL_net.h"
 
 /* Functions in netplay.cpp */
 extern int   InitNetData(bool hosting);
 extern void  HaltNetData(void);
 extern int   AddPlayer(const char *playerstr);
+extern void  AddLocalPlayer(int playernum);
+extern void  AddNetworkPlayer(int playernum, const IPaddress &address);
 extern int   CheckPlayers(void);
 extern void  QueueKey(unsigned char Op, unsigned char Type);
 extern int   SyncNetwork(void);