From 259cc038c5b9db6e53c61f05d39680970c504afb Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Fri, 28 Nov 2025 17:15:44 -0800
Subject: [PATCH] Ported to SDL3_net
---
CMakeLists.txt | 39 +++--
Data/UI/lobby.xml | 20 +--
external/SDL_net | 2 +-
game/Maelstrom_Globals.h | 1 -
game/game.cpp | 6 +-
game/gameinfo.cpp | 16 ++-
game/init.cpp | 17 ++-
game/lobby.cpp | 299 ++++++++++++++++++++++++++++++---------
game/lobby.h | 7 -
game/main.cpp | 4 -
game/netplay.cpp | 137 ++++++++----------
game/netplay.h | 9 +-
game/packet.h | 72 ++++++++--
game/protocol.h | 5 +
utils/array.h | 15 +-
15 files changed, 438 insertions(+), 211 deletions(-)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index b325d310..39511f66 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -9,17 +9,6 @@ else()
set(GAME_INSTALLDIR "${CMAKE_INSTALL_PREFIX}/games/${PROJECT_NAME}")
endif()
-if(MSVC)
- add_compile_options(-W3)
-else()
- add_compile_options(-Wall)
- add_compile_options(-Wextra)
- add_compile_options(-Wno-cast-function-type)
- add_compile_options(-Wno-sign-compare)
- add_compile_options(-Wno-unused-function)
- add_compile_options(-Wno-unused-parameter)
-endif()
-
# set the output directory for built objects.
# This makes sure that the dynamic library goes into the build directory automatically.
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/$<CONFIGURATION>")
@@ -141,9 +130,35 @@ set(MAELSTROM_SOURCES
)
add_executable(Maelstrom WIN32 ${MAELSTROM_SOURCES})
+
+if(MSVC)
+ target_compile_options(Maelstrom PRIVATE -W3)
+else()
+ target_compile_options(Maelstrom PRIVATE -Wall)
+ target_compile_options(Maelstrom PRIVATE -Wextra)
+ target_compile_options(Maelstrom PRIVATE -Wno-cast-function-type)
+ target_compile_options(Maelstrom PRIVATE -Wno-sign-compare)
+ target_compile_options(Maelstrom PRIVATE -Wno-unused-function)
+ target_compile_options(Maelstrom PRIVATE -Wno-unused-parameter)
+endif()
+
+if(NOT WIN32)
+ check_c_source_compiles("
+ #include <ifaddrs.h>
+ int main() {
+ struct ifaddrs* ifap;
+ getifaddrs(&ifap);
+ return 0;
+ }
+ " HAVE_GETIFADDRS)
+ if(HAVE_GETIFADDRS)
+ target_compile_definitions(Maelstrom PRIVATE HAVE_GETIFADDRS)
+ endif()
+endif()
+
target_link_libraries(Maelstrom PRIVATE SDLmac)
target_link_libraries(Maelstrom PRIVATE SDL3::SDL3)
-target_link_libraries(Maelstrom PRIVATE SDL2_net::SDL2_net-static)
+target_link_libraries(Maelstrom PRIVATE SDL3_net::SDL3_net)
install(TARGETS Maelstrom DESTINATION "${GAME_INSTALLDIR}")
install(DIRECTORY Data DESTINATION "${GAME_INSTALLDIR}")
diff --git a/Data/UI/lobby.xml b/Data/UI/lobby.xml
index 5514b7d2..191dbf90 100644
--- a/Data/UI/lobby.xml
+++ b/Data/UI/lobby.xml
@@ -32,10 +32,10 @@
<DialogButton name="join" closeDialog="false" text="Join" default="true">
<Anchor anchorFrom="TOPLEFT" anchorTo="TOPLEFT"/>
</DialogButton>
- <DialogLabel name="name" text="This is a name">
+ <DialogLabel name="name">
<Anchor anchorFrom="LEFT" anchorTo="RIGHT" anchor="join" x="16"/>
</DialogLabel>
- <DialogLabel name="host" text="bwg101.corp.pacbell.net">
+ <DialogLabel name="host">
<Anchor anchorFrom="LEFT" anchorTo="RIGHT" anchor="join" x="120"/>
</DialogLabel>
<Image name="ping1" image="ping1">
@@ -57,10 +57,10 @@
<DialogButton name="join" closeDialog="false" text="Join">
<Anchor anchorFrom="TOPLEFT" anchorTo="TOPLEFT"/>
</DialogButton>
- <DialogLabel name="name" text="This is a name">
+ <DialogLabel name="name">
<Anchor anchorFrom="LEFT" anchorTo="RIGHT" anchor="join" x="16"/>
</DialogLabel>
- <DialogLabel name="host" text="bwg101.corp.pacbell.net">
+ <DialogLabel name="host">
<Anchor anchorFrom="LEFT" anchorTo="RIGHT" anchor="join" x="120"/>
</DialogLabel>
<Image name="ping1" image="ping1">
@@ -82,10 +82,10 @@
<DialogButton name="join" closeDialog="false" text="Join">
<Anchor anchorFrom="TOPLEFT" anchorTo="TOPLEFT"/>
</DialogButton>
- <DialogLabel name="name" text="This is a name">
+ <DialogLabel name="name">
<Anchor anchorFrom="LEFT" anchorTo="RIGHT" anchor="join" x="16"/>
</DialogLabel>
- <DialogLabel name="host" text="bwg101.corp.pacbell.net">
+ <DialogLabel name="host">
<Anchor anchorFrom="LEFT" anchorTo="RIGHT" anchor="join" x="120"/>
</DialogLabel>
<Image name="ping1" image="ping1">
@@ -107,10 +107,10 @@
<DialogButton name="join" closeDialog="false" text="Join">
<Anchor anchorFrom="TOPLEFT" anchorTo="TOPLEFT"/>
</DialogButton>
- <DialogLabel name="name" text="This is a name">
+ <DialogLabel name="name">
<Anchor anchorFrom="LEFT" anchorTo="RIGHT" anchor="join" x="16"/>
</DialogLabel>
- <DialogLabel name="host" text="bwg101.corp.pacbell.net">
+ <DialogLabel name="host">
<Anchor anchorFrom="LEFT" anchorTo="RIGHT" anchor="join" x="120"/>
</DialogLabel>
<Image name="ping1" image="ping1">
@@ -132,10 +132,10 @@
<DialogButton name="join" closeDialog="false" text="Join">
<Anchor anchorFrom="TOPLEFT" anchorTo="TOPLEFT"/>
</DialogButton>
- <DialogLabel name="name" text="This is a name">
+ <DialogLabel name="name">
<Anchor anchorFrom="LEFT" anchorTo="RIGHT" anchor="join" x="16"/>
</DialogLabel>
- <DialogLabel name="host" text="bwg101.corp.pacbell.net">
+ <DialogLabel name="host">
<Anchor anchorFrom="LEFT" anchorTo="RIGHT" anchor="join" x="120"/>
</DialogLabel>
<Image name="ping1" image="ping1">
diff --git a/external/SDL_net b/external/SDL_net
index 3064cfe8..56a77f31 160000
--- a/external/SDL_net
+++ b/external/SDL_net
@@ -1 +1 @@
-Subproject commit 3064cfe8bb62d27063e4ad313036d0e612ca9033
+Subproject commit 56a77f3137e3ea208c95a0269466a314c3eb8800
diff --git a/game/Maelstrom_Globals.h b/game/Maelstrom_Globals.h
index 1dad8efb..129e53c6 100644
--- a/game/Maelstrom_Globals.h
+++ b/game/Maelstrom_Globals.h
@@ -24,7 +24,6 @@
#define _Maelstrom_Globals_h
#include <SDL3/SDL.h>
-#include <SDL_net.h>
#include "../screenlib/SDL_FrameBuf.h"
#include "../screenlib/UIManager.h"
diff --git a/game/game.cpp b/game/game.cpp
index a14db4ce..14acd2a3 100644
--- a/game/game.cpp
+++ b/game/game.cpp
@@ -108,6 +108,8 @@ static bool SetupPlayers(void)
void NewGame(void)
{
+ InitNetData();
+
/* Start the replay */
gReplay.HandleNewGame();
@@ -1055,9 +1057,11 @@ GamePanelDelegate::NextWave()
void
GamePanelDelegate::GameOver()
{
- ui->ShowPanel(PANEL_GAMEOVER);
+ CloseSocket();
QuitPlayerControls();
+
+ ui->ShowPanel(PANEL_GAMEOVER);
}
/* ----------------------------------------------------------------- */
diff --git a/game/gameinfo.cpp b/game/gameinfo.cpp
index 2e3bc94d..a9e95def 100644
--- a/game/gameinfo.cpp
+++ b/game/gameinfo.cpp
@@ -324,9 +324,9 @@ GameInfo::RemoveNode(Uint32 nodeID)
i = 0;
while (i < GetNumNodes()) {
if (nodeID == nodes[i].nodeID) {
- SDL_memcpy(&nodes[i], &nodes[i+1],
- (MAX_NODES-i-1)*sizeof(nodes[i]));
- SDL_zero(nodes[MAX_NODES-1]);
+ for (int j = i; j < (GetNumNodes() - 1); ++j) {
+ nodes[j] = nodes[j + 1];
+ }
--numNodes;
} else {
++i;
@@ -543,13 +543,15 @@ GameInfo::UpdateUI(GameInfoPlayer *player)
player->UI.name->Show();
player->UI.name->SetText(player->name);
player->UI.host->Show();
- player->UI.host->SetText(SDLNet_ResolveIP(&node->address));
+ player->UI.host->SetText(NET_GetAddressString(node->address.host));
}
}
- char name[128];
- SDL_snprintf(name, sizeof(name), "control%d", player->controlMask);
- player->UI.control->SetImage(name);
+ if (player->UI.control) {
+ char name[128];
+ SDL_snprintf(name, sizeof(name), "control%d", player->controlMask);
+ player->UI.control->SetImage(name);
+ }
if (player->UI.desc) {
const char *desc = NULL;
diff --git a/game/init.cpp b/game/init.cpp
index 2f32cf9f..05689f03 100644
--- a/game/init.cpp
+++ b/game/init.cpp
@@ -740,6 +740,7 @@ void CleanUp(void)
delete prefs;
prefs = NULL;
}
+ NET_Quit();
SDL_Quit();
}
@@ -748,7 +749,16 @@ void CleanUp(void)
int DoInitializations(Uint32 window_flags)
{
int w, h;
- SDL_Surface *icon;
+ SDL_Surface* icon;
+
+ if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_GAMEPAD)) {
+ error("Couldn't initialize SDL: %s\n", SDL_GetError());
+ return(-1);
+ }
+ if (!NET_Init()) {
+ error("Couldn't initialize SDL_net: %s\n", SDL_GetError());
+ return(-1);
+ }
// -- Initialize some variables
gLastHigh = -1;
@@ -763,11 +773,6 @@ int DoInitializations(Uint32 window_flags)
// -- Load our controls
LoadControls();
- if ( !SDL_Init(SDL_INIT_VIDEO|SDL_INIT_AUDIO|SDL_INIT_GAMEPAD) ) {
- error("Couldn't initialize SDL: %s\n", SDL_GetError());
- return(-1);
- }
-
/* Load the Maelstrom icon */
icon = SDL_LoadSurface_IO(OpenRead("icon.png"), true);
if ( icon == NULL ) {
diff --git a/game/lobby.cpp b/game/lobby.cpp
index f6e7c23c..5d442f55 100644
--- a/game/lobby.cpp
+++ b/game/lobby.cpp
@@ -20,7 +20,6 @@
slouken@libsdl.org
*/
-#include "SDL_net.h"
#include "Maelstrom_Globals.h"
#include "../screenlib/UIElement.h"
#include "../screenlib/UIElementRadio.h"
@@ -29,6 +28,18 @@
#include "netplay.h"
#include "game.h"
+#ifdef SDL_PLATFORM_WIN32
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <winsock.h>
+#include <iphlpapi.h>
+#endif
+
+#ifdef HAVE_GETIFADDRS
+#include <ifaddrs.h>
+#include <netinet/in.h>
+#endif
+
class SelectControlCallback : public UIClickCallback
{
@@ -130,16 +141,8 @@ bool
LobbyDialogDelegate::OnLoad()
{
int i, count;
- IPaddress addresses[32];
char name[32];
- // Get the addresses for this machine
- count = SDLNet_GetLocalAddresses(addresses, SDL_arraysize(addresses));
- m_addresses.clear();
- for (i = 0; i < count; ++i) {
- m_addresses.add(addresses[i]);
- }
-
m_hostOrJoin = m_dialog->GetElement<UIElementRadioGroup>("hostOrJoin");
if (!m_hostOrJoin) {
SDL_Log("Warning: Couldn't find radio group 'hostOrJoin'");
@@ -222,10 +225,8 @@ LobbyDialogDelegate::OnHide()
NewGame();
} else {
SetState(STATE_NONE);
+ CloseSocket();
}
-
- // Shut down networking
- HaltNetData();
}
void
@@ -252,11 +253,17 @@ LobbyDialogDelegate::OnPoll()
}
// See if there are any packets on the network
- m_packet.Reset();
- while (SDLNet_UDP_Recv(gNetFD, &m_packet)) {
- ProcessPacket(m_packet);
- m_packet.Reset();
+ NET_Datagram *datagram;
+ DynamicPacket packet;
+ while (NET_ReceiveDatagram(gSocket, &datagram) && datagram) {
+ packet.data = datagram->buf;
+ packet.len = datagram->buflen;
+ packet.address.host = datagram->addr;
+ packet.address.port = datagram->port;
+ ProcessPacket(packet);
+ packet.Reset();
}
+ packet.address.host = nullptr;
// Do this after processing packets in case a pong was pending
if (!m_lastPing || (now - m_lastPing) > PING_INTERVAL) {
@@ -268,16 +275,12 @@ LobbyDialogDelegate::OnPoll()
void
LobbyDialogDelegate::SetHostOrJoin(void*, int value)
{
- // Remove the game before shutting down the network
- if (m_state == STATE_HOSTING) {
- RemoveGame();
- }
-
// This is called when the lobby switches from hosting to joining
- HaltNetData();
+ CloseSocket();
if (value > 0) {
- if (InitNetData(value == HOST_GAME) < 0) {
+ bool hosting = (value == HOST_GAME);
+ if (CreateSocket(hosting) < 0) {
m_hostOrJoin->SetValue(2);
return;
}
@@ -346,8 +349,10 @@ LobbyDialogDelegate::UpdateUI()
}
if (m_state == STATE_HOSTING) {
m_playButton->SetDisabled(false);
+ m_deathmatch->SetDisabled(false);
} else {
m_playButton->SetDisabled(true);
+ m_deathmatch->SetDisabled(true);
}
}
@@ -357,9 +362,6 @@ LobbyDialogDelegate::SetState(LOBBY_STATE state)
int i;
// Handle any state transitions here
- if (m_state == STATE_HOSTING) {
- RemoveGame();
- }
if (m_state == STATE_HOSTING) {
if (m_controlDropdown) {
m_controlDropdown->Hide();
@@ -473,17 +475,198 @@ LobbyDialogDelegate::CheckPings()
for (int i = 0; i < m_game.GetNumNodes(); ++i) {
if (m_game.IsNetworkNode(i)) {
- m_packet.address = m_game.GetNode(i)->address;
-
- SDLNet_UDP_Send(gNetFD, -1, &m_packet);
+ IPaddress address = m_game.GetNode(i)->address;
+ NET_SendDatagram(gSocket, address.host, address.port, m_packet.data, m_packet.len);
}
}
}
}
-void
-LobbyDialogDelegate::RemoveGame()
+#ifdef HAVE_GETIFADDRS
+static Uint32 SockAddrToUint32(struct sockaddr* a)
+{
+ return ((a) && (a->sa_family == AF_INET)) ? SDL_Swap32BE(((struct sockaddr_in*)a)->sin_addr.s_addr) : 0;
+}
+#endif
+
+#if defined(SDL_PLATFORM_WIN32) || defined(HAVE_GETIFADDRS)
+// convert a numeric IP address into its string representation
+static void Inet_NtoA(Uint32 addr, char *ipbuf, size_t maxlen)
+{
+ SDL_snprintf(ipbuf, maxlen, "%u.%u.%u.%u", (addr >> 24) & 0xFF, (addr >> 16) & 0xFF, (addr >> 8) & 0xFF, (addr >> 0) & 0xFF);
+}
+
+// convert a string representation of an IP address into its numeric equivalent
+static Uint32 Inet_AtoN(const char* buf)
+{
+ // net_server inexplicably doesn't have this function; so I'll just fake it
+ Uint32 ret = 0;
+ int shift = 24; // fill out the MSB first
+ bool startQuad = true;
+ while ((shift >= 0) && (*buf))
+ {
+ if (startQuad)
+ {
+ unsigned char quad = (unsigned char)atoi(buf);
+ ret |= (((Uint32)quad) << shift);
+ shift -= 8;
+ }
+ startQuad = (*buf == '.');
+ buf++;
+ }
+ return ret;
+}
+#endif // SDL_PLATFORM_WIN32 || HAVE_GETIFADDRS
+
+static bool NET_SendDatagramBroadcast(NET_DatagramSocket *sock, Uint16 port, const void* buf, int buflen)
{
+#ifdef SDL_PLATFORM_WIN32
+ // Windows XP style implementation
+ HMODULE hiphlpapi = LoadLibraryA("Iphlpapi.dll");
+ typedef DWORD (WINAPI *GetIpAddrTable_t)(PMIB_IPADDRTABLE pIpAddrTable, PULONG pdwSize, BOOL bOrder);
+ GetIpAddrTable_t GetIpAddrTableFunc = (GetIpAddrTable_t)GetProcAddress(hiphlpapi, "GetIpAddrTable");
+ typedef ULONG (WINAPI *GetAdaptersInfo_t)(PIP_ADAPTER_INFO AdapterInfo, PULONG SizePointer);
+ GetAdaptersInfo_t GetAdaptersInfoFunc = (GetAdaptersInfo_t)GetProcAddress(hiphlpapi, "GetAdaptersInfo");
+
+ // Adapted from example code at http://msdn2.microsoft.com/en-us/library/aa365917.aspx
+ // Now get Windows' IPv4 addresses table. Once again, we gotta call GetIpAddrTable()
+ // multiple times in order to deal with potential race conditions properly.
+ MIB_IPADDRTABLE* ipTable = NULL;
+ {
+ ULONG iptablelen = 0;
+ for (int i = 0; i < 5; i++)
+ {
+ DWORD ipRet = GetIpAddrTableFunc(ipTable, &iptablelen, false);
+ if (ipRet == ERROR_INSUFFICIENT_BUFFER)
+ {
+ free(ipTable); // in case we had previously allocated it
+ ipTable = (MIB_IPADDRTABLE*)malloc(iptablelen);
+ }
+ else if (ipRet == NO_ERROR) break;
+ else
+ {
+ free(ipTable);
+ ipTable = NULL;
+ break;
+ }
+ }
+ }
+
+ if (ipTable)
+ {
+ // Try to get the Adapters-info table, so we can given useful names to the IP
+ // addresses we are returning. Gotta call GetAdaptersInfo() up to 5 times to handle
+ // the potential race condition between the size-query call and the get-data call.
+ // I love a well-designed API :^P
+ IP_ADAPTER_INFO* pAdapterInfo = NULL;
+ {
+ ULONG bufLen = 0;
+ for (int i = 0; i < 5; i++)
+ {
+ DWORD apRet = GetAdaptersInfoFunc(pAdapterInfo, &bufLen);
+ if (apRet == ERROR_BUFFER_OVERFLOW)
+ {
+ free(pAdapterInfo); // in case we had previously allocated it
+ pAdapterInfo = (IP_ADAPTER_INFO*)malloc(bufLen);
+ }
+ else if (apRet == ERROR_SUCCESS) break;
+ else
+ {
+ free(pAdapterInfo);
+ pAdapterInfo = NULL;
+ break;
+ }
+ }
+ }
+
+ for (DWORD i = 0; i < ipTable->dwNumEntries; i++)
+ {
+ const MIB_IPADDRROW& row = ipTable->table[i];
+
+ // Now lookup the appropriate adaptor-name in the pAdaptorInfos, if we can find it
+ const char* name = NULL;
+ const char* desc = NULL;
+ if (pAdapterInfo)
+ {
+ IP_ADAPTER_INFO* next = pAdapterInfo;
+ while ((next) && (name == NULL))
+ {
+ IP_ADDR_STRING* ipAddr = &next->IpAddressList;
+ while (ipAddr)
+ {
+ if (Inet_AtoN(ipAddr->IpAddress.String) == SDL_Swap32BE(row.dwAddr))
+ {
+ name = next->AdapterName;
+ desc = next->Description;
+ break;
+ }
+ ipAddr = ipAddr->Next;
+ }
+ next = next->Next;
+ }
+ }
+ char namebuf[128];
+ if (name == NULL)
+ {
+ SDL_snprintf(namebuf, sizeof(namebuf), "unnamed-%i", i);
+ name = namebuf;
+ }
+
+ Uint32 ipAddr = SDL_Swap32BE(row.dwAddr);
+ Uint32 netmask = SDL_Swap32BE(row.dwMask);
+ Uint32 baddr = ipAddr & netmask;
+ if (row.dwBCastAddr) baddr |= ~netmask;
+
+ char ifaAddrStr[32]; Inet_NtoA(ipAddr, ifaAddrStr, sizeof(ifaAddrStr));
+ char maskAddrStr[32]; Inet_NtoA(netmask, maskAddrStr, sizeof(maskAddrStr));
+ char dstAddrStr[32]; Inet_NtoA(baddr, dstAddrStr, sizeof(dstAddrStr));
+ //SDL_Log(" Found interface: name=[%s] desc=[%s] address=[%s] netmask=[%s] broadcastAddr=[%s]\n", name, desc ? desc : "unavailable", ifaAddrStr, maskAddrStr, dstAddrStr);
+
+ NET_Address *address = NET_ResolveHostname(dstAddrStr);
+ NET_WaitUntilResolved(address, -1);
+ NET_SendDatagram(sock, address, port, buf, buflen);
+ NET_UnrefAddress(address);
+ }
+
+ free(pAdapterInfo);
+ free(ipTable);
+ }
+ return true;
+#elif defined(HAVE_GETIFADDRS)
+ // BSD-style implementation
+ struct ifaddrs* ifap;
+ if (getifaddrs(&ifap) == 0)
+ {
+ struct ifaddrs* p = ifap;
+ while (p)
+ {
+ Uint32 ifaAddr = SockAddrToUint32(p->ifa_addr);
+ Uint32 maskAddr = SockAddrToUint32(p->ifa_netmask);
+ Uint32 dstAddr = SockAddrToUint32(p->ifa_dstaddr);
+ if (ifaAddr > 0)
+ {
+ char ifaAddrStr[32]; Inet_NtoA(ifaAddr, ifaAddrStr, sizeof(ifaAddrStr));
+ char maskAddrStr[32]; Inet_NtoA(maskAddr, maskAddrStr, sizeof(maskAddrStr));
+ char dstAddrStr[32]; Inet_NtoA(dstAddr, dstAddrStr, sizeof(dstAddrStr));
+ //SDL_Log(" Found interface: name=[%s] desc=[%s] address=[%s] netmask=[%s] broadcastAddr=[%s]\n", p->ifa_name, "unavailable", ifaAddrStr, maskAddrStr, dstAddrStr);
+
+ NET_Address* address = NET_ResolveHostname(dstAddrStr);
+ NET_WaitUntilResolved(address, -1);
+ NET_SendDatagram(sock, address, port, buf, buflen);
+ NET_UnrefAddress(address);
+ }
+ p = p->ifa_next;
+ }
+ freeifaddrs(ifap);
+ }
+ return true;
+#else
+ NET_Address *address = NET_ResolveHostname("255.255.255.255");
+ NET_WaitUntilResolved(address, -1);
+ bool result = NET_SendDatagram(sock, address, port, buf, buflen);
+ NET_UnrefAddress(address);
+ return result;
+#endif
}
void
@@ -492,9 +675,8 @@ LobbyDialogDelegate::GetGameList()
// Get game info for local games
m_packet.StartLobbyMessage(LOBBY_REQUEST_GAME_INFO);
m_packet.Write((Uint32)SDL_GetTicks());
- m_packet.address.host = INADDR_BROADCAST;
- m_packet.address.port = SDL_Swap16BE(NETPLAY_PORT);
- SDLNet_UDP_Send(gNetFD, -1, &m_packet);
+
+ NET_SendDatagramBroadcast(gSocket, NETPLAY_PORT, m_packet.data, m_packet.len);
}
void
@@ -502,8 +684,9 @@ LobbyDialogDelegate::GetGameInfo()
{
m_packet.StartLobbyMessage(LOBBY_REQUEST_GAME_INFO);
m_packet.Write((Uint32)SDL_GetTicks());
- m_packet.address = m_game.GetHost()->address;
- SDLNet_UDP_Send(gNetFD, -1, &m_packet);
+
+ IPaddress address = m_game.GetHost()->address;
+ NET_SendDatagram(gSocket, address.host, address.port, m_packet.data, m_packet.len);
}
void
@@ -521,9 +704,9 @@ LobbyDialogDelegate::SendJoinRequest()
m_packet.Write(m_game.gameID);
m_packet.Write(m_game.localID);
m_packet.Write(prefs->GetString(PREFERENCES_HANDLE));
- m_packet.address = m_game.GetHost()->address;
- SDLNet_UDP_Send(gNetFD, -1, &m_packet);
+ IPaddress address = m_game.GetHost()->address;
+ NET_SendDatagram(gSocket, address.host, address.port, m_packet.data, m_packet.len);
}
void
@@ -532,9 +715,9 @@ LobbyDialogDelegate::SendLeaveRequest()
m_packet.StartLobbyMessage(LOBBY_REQUEST_LEAVE);
m_packet.Write(m_game.gameID);
m_packet.Write(m_game.localID);
- m_packet.address = m_game.GetHost()->address;
- SDLNet_UDP_Send(gNetFD, -1, &m_packet);
+ IPaddress address = m_game.GetHost()->address;
+ NET_SendDatagram(gSocket, address.host, address.port, m_packet.data, m_packet.len);
}
void
@@ -550,9 +733,8 @@ LobbyDialogDelegate::SendKick(int index)
m_packet.StartLobbyMessage(LOBBY_KICK);
m_packet.Write(m_game.gameID);
m_packet.Write(node->nodeID);
- m_packet.address = node->address;
- SDLNet_UDP_Send(gNetFD, -1, &m_packet);
+ NET_SendDatagram(gSocket, node->address.host, node->address.port, m_packet.data, m_packet.len);
// Now remove them from the game list
m_game.RemoveNode(node->nodeID);
@@ -570,26 +752,12 @@ LobbyDialogDelegate::ClearGameList()
m_gameList.clear();
}
-void
-LobbyDialogDelegate::PackAddresses(DynamicPacket &packet)
-{
- Uint16 port;
-
- port = SDLNet_UDP_GetPeerAddress(gNetFD, -1)->port;
-
- m_packet.Write((Uint8)m_addresses.length());
- for (unsigned int i = 0; i < m_addresses.length(); ++i) {
- m_packet.Write(m_addresses[i].host);
- m_packet.Write(port);
- }
-}
-
void
LobbyDialogDelegate::ProcessPacket(DynamicPacket &packet)
{
Uint8 cmd;
- if (!m_packet.Read(cmd)) {
+ if (!packet.Read(cmd)) {
return;
}
if (cmd != LOBBY_MSG) {
@@ -598,7 +766,7 @@ LobbyDialogDelegate::ProcessPacket(DynamicPacket &packet)
}
return;
}
- if (!m_packet.Read(cmd)) {
+ if (!packet.Read(cmd)) {
return;
}
@@ -654,9 +822,8 @@ LobbyDialogDelegate::ProcessPing(DynamicPacket &packet)
m_reply.Write(gameID);
m_reply.Write(nodeID);
m_reply.Write(timestamp);
- m_reply.address = packet.address;
- SDLNet_UDP_Send(gNetFD, -1, &m_reply);
+ NET_SendDatagram(gSocket, packet.address.host, packet.address.port, m_reply.data, m_reply.len);
}
void
@@ -711,9 +878,8 @@ LobbyDialogDelegate::ProcessNewGame(DynamicPacket &packet)
m_reply.Write((Uint8)NEW_GAME_ACK);
m_reply.Write(m_game.gameID);
m_reply.Write(m_game.localID);
- m_reply.address = packet.address;
- SDLNet_UDP_Send(gNetFD, -1, &m_reply);
+ NET_SendDatagram(gSocket, packet.address.host, packet.address.port, m_reply.data, m_reply.len);
if (m_game.HasNode(packet.address)) {
m_playButton->OnClick();
@@ -732,9 +898,8 @@ LobbyDialogDelegate::ProcessRequestGameInfo(DynamicPacket &packet)
m_reply.StartLobbyMessage(LOBBY_GAME_INFO);
m_reply.Write(timestamp);
m_game.WriteToPacket(m_reply);
- m_reply.address = packet.address;
- SDLNet_UDP_Send(gNetFD, -1, &m_reply);
+ NET_SendDatagram(gSocket, packet.address.host, packet.address.port, m_reply.data, m_reply.len);
}
void
@@ -766,8 +931,8 @@ LobbyDialogDelegate::ProcessRequestJoin(DynamicPacket &packet)
m_game.WriteToPacket(m_reply);
for (int i = 0; i < m_game.GetNumNodes(); ++i) {
if (m_game.IsNetworkNode(i)) {
- m_reply.address = m_game.GetNode(i)->address;
- SDLNet_UDP_Send(gNetFD, -1, &m_reply);
+ IPaddress address = m_game.GetNode(i)->address;
+ NET_SendDatagram(gSocket, address.host, address.port, m_reply.data, m_reply.len);
}
}
}
@@ -832,6 +997,8 @@ LobbyDialogDelegate::ProcessGameInfo(DynamicPacket &packet)
m_game.CopyFrom(game);
+ UpdateUI();
+
if (m_state == STATE_JOINING) {
if (m_game.HasNode(m_game.localID)) {
// We successfully joined the game
diff --git a/game/lobby.h b/game/lobby.h
index 6094f3d4..dd0863d8 100644
--- a/game/lobby.h
+++ b/game/lobby.h
@@ -23,7 +23,6 @@
#ifndef _lobby_h
#define _lobby_h
-#include "SDL_net.h"
#include "protocol.h"
#include "packet.h"
#include "gameinfo.h"
@@ -60,7 +59,6 @@ class LobbyDialogDelegate : public UIDialogDelegate
void UpdateUI();
void CheckPings();
- void RemoveGame();
void GetGameList();
void GetGameInfo();
void JoinGame(GameInfo &game);
@@ -69,8 +67,6 @@ class LobbyDialogDelegate : public UIDialogDelegate
void ClearGameInfo();
void ClearGameList();
- void PackAddresses(DynamicPacket &packet);
-
void ProcessPacket(DynamicPacket &packet);
void ProcessPing(DynamicPacket &packet);
void ProcessPong(DynamicPacket &packet);
@@ -82,9 +78,6 @@ class LobbyDialogDelegate : public UIDialogDelegate
void ProcessKick(DynamicPacket &packet);
protected:
- IPaddress m_globalServer;
- array<IPaddress> m_addresses;
-
enum LOBBY_STATE {
STATE_NONE,
STATE_HOSTING,
diff --git a/game/main.cpp b/game/main.cpp
index a75fe0e2..42deb539 100644
--- a/game/main.cpp
+++ b/game/main.cpp
@@ -67,11 +67,7 @@ Bool gRunning;
// Main Menu actions:
static void RunSinglePlayerGame()
{
- if (InitNetData(false) < 0) {
- return;
- }
NewGame();
- HaltNetData();
}
static void RunReplayGame(const char *file)
diff --git a/game/netplay.cpp b/game/netplay.cpp
index ed6cfbb0..0cfe44ff 100644
--- a/game/netplay.cpp
+++ b/game/netplay.cpp
@@ -36,9 +36,8 @@
#define NETWORK_TIMEOUT 2*FRAME_DELAY_MS
-UDPsocket gNetFD;
+NET_DatagramSocket *gSocket = nullptr;
-static SDLNet_SocketSet SocketSet;
static Uint32 NextFrame;
static bool AdvancedFrame;
@@ -52,7 +51,6 @@ static int CurrOut;
static Uint32 WaitingAcks[MAX_NODES];
/* We cache one packet if the other player is ahead of us */
-static DynamicPacket Packet;
static struct {
Uint32 frame;
DynamicPacket packet;
@@ -63,39 +61,41 @@ static DynamicPacket QueuedInput;
static DynamicPacket FrameInput;
-int InitNetData(bool hosting)
+int CreateSocket(bool hosting)
{
- int i;
int port;
- /* Initialize the networking subsystem */
- if ( SDLNet_Init() < 0 ) {
- error("Couldn't initialize networking: %s\n", SDLNet_GetError());
- return(-1);
- }
-
- /* Oh heck, create the UDP socket here... */
+ /* Create the UDP socket */
if (hosting) {
port = NETPLAY_PORT;
} else {
port = 0;
}
- gNetFD = SDLNet_UDP_Open(port);
- if ( gNetFD == NULL ) {
- error("Couldn't create socket bound to port %d: %s\n", port, SDLNet_GetError());
- return(-1);
- }
- SocketSet = SDLNet_AllocSocketSet(1);
- if ( SocketSet == NULL ) {
- error("Couldn't create socket watch set\n");
+ gSocket = NET_CreateDatagramSocket(NULL, port);
+ if ( gSocket == NULL ) {
+ error("Couldn't create socket bound to port %d: %s\n", port, SDL_GetError());
return(-1);
}
- SDLNet_UDP_AddSocket(SocketSet, gNetFD);
#ifdef DEBUG_PACKETLOSS
- SDLNet_UDP_SetPacketLoss(gNetFD, DEBUG_PACKETLOSS);
+ SDLNet_UDP_SetPacketLoss(gSocket, DEBUG_PACKETLOSS);
#endif
+ return(0);
+}
+
+void CloseSocket(void)
+{
+ if (gSocket) {
+ NET_DestroyDatagramSocket(gSocket);
+ gSocket = NULL;
+ }
+}
+
+void InitNetData(void)
+{
+ int i;
+
/* Initialize network game variables */
NextFrame = 1;
AdvancedFrame = true;
@@ -104,28 +104,11 @@ int InitNetData(bool hosting)
CurrOut = 0;
SDL_zero(WaitingAcks);
for (i = 0; i < MAX_NODES; ++i) {
- CachedPacket[i].frame = 0;
+ CachedPacket[i].frame = ~0u;
CachedPacket[i].packet.Reset();
}
QueuedInput.Reset();
FrameInput.Reset();
-
- return(0);
-}
-
-void HaltNetData(void)
-{
- if (SocketSet) {
- SDLNet_FreeSocketSet(SocketSet);
- SocketSet = NULL;
- }
-
- if (gNetFD) {
- SDLNet_UDP_Close(gNetFD);
- gNetFD = NULL;
- }
-
- SDLNet_Quit();
}
int CheckPlayers(void)
@@ -149,15 +132,6 @@ int CheckPlayers(void)
return(-1);
}
- /* Bind all of our network nodes to the broadcast channel */
- for (i = 0; i < gGameInfo.GetNumNodes(); ++i) {
- if (gGameInfo.IsNetworkNode(i)) {
- const GameInfoNode *node = gGameInfo.GetNode(i);
- SDLNet_UDP_Bind(gNetFD, 0, &node->address);
- SDLNet_UDP_Bind(gNetFD, 1+i, &node->address);
- }
- }
-
return(0);
}
@@ -243,7 +217,8 @@ static SYNC_RESULT AwaitSync()
#if DEBUG_NETWORK >= 2
error("Sending packet for current frame (%ld)\r\n", NextFrame);
#endif
- SDLNet_UDP_Send(gNetFD, i+1, &CurrPacket);
+ const GameInfoNode *node = gGameInfo.GetNode(i);
+ NET_SendDatagram(gSocket, node->address.host, node->address.port, CurrPacket.data, CurrPacket.len);
WaitingAcks[i] = NodeTimeout(now);
}
}
@@ -272,7 +247,7 @@ error("Timed out waiting for frame %ld\r\n", NextFrame);
}
}
- int ready = SDLNet_CheckSockets(SocketSet, NextTimeout(now));
+ int ready = NET_WaitUntilInputAvailable((void**)&gSocket, 1, NextTimeout(now));
if (ready < 0) {
error("Network error: SDLNet_CheckSockets()\r\n");
return SYNC_NETERROR;
@@ -282,15 +257,18 @@ error("Timed out waiting for frame %ld\r\n", NextFrame);
}
/* We are guaranteed that there is data here */
- Packet.Reset();
- if ( SDLNet_UDP_Recv(gNetFD, &Packet) <= 0 ) {
- error("Network error: SDLNet_UDP_Recv()\r\n");
+ NET_Datagram *datagram;
+ DynamicPacket packet;
+ if (!NET_ReceiveDatagram(gSocket, &datagram) || !datagram) {
+ error("Network error: NET_ReceiveDatagram()\r\n");
return SYNC_NETERROR;
}
/* We have a packet! */
+ packet.data = datagram->buf;
+ packet.len = datagram->buflen;
Uint8 cmd;
- if (!Packet.Read(cmd)) {
+ if (!packet.Read(cmd)) {
error("Received short packet\r\n");
continue;
}
@@ -304,11 +282,11 @@ error("LOBBY_MSG packet\r\n");
#if DEBUG_NETWORK >= 2
error("NEW_GAME packet\r\n");
#endif
- Packet.Reset();
- Packet.Write((Uint8)NEW_GAME_ACK);
- Packet.Write(gGameInfo.gameID);
- Packet.Write(gGameInfo.localID);
- SDLNet_UDP_Send(gNetFD, -1, &Packet);
+ DynamicPacket reply;
+ reply.Write((Uint8)NEW_GAME_ACK);
+ reply.Write(gGameInfo.gameID);
+ reply.Write(gGameInfo.localID);
+ NET_SendDatagram(gSocket, datagram->addr, datagram->port, reply.data, reply.len);
continue;
}
if (cmd == NEW_GAME_ACK) {
@@ -324,7 +302,7 @@ error("NEW_GAME_ACK packet\r\n");
Uint32 gameID;
Uint32 nodeID;
- if (!Packet.Read(gameID) || !Packet.Read(nodeID)) {
+ if (!packet.Read(gameID) || !packet.Read(nodeID)) {
error("Received short packet\r\n");
continue;
}
@@ -339,7 +317,7 @@ error("NEW_GAME_ACK packet\r\n");
}
/* Check the frame number */
- if (!Packet.Read(frame)) {
+ if (!packet.Read(frame)) {
error("Received short packet\r\n");
continue;
}
@@ -356,7 +334,7 @@ error("Ignoring duplicate packet for frame %lu from node %d\r\n", frame, index);
}
/* Do a consistency check!! */
- if (!ProcessSync(index, Packet)) {
+ if (!ProcessSync(index, packet)) {
return SYNC_CORRUPT;
}
WaitingAcks[index] = 0;
@@ -365,8 +343,7 @@ error("Ignoring duplicate packet for frame %lu from node %d\r\n", frame, index);
#if DEBUG_NETWORK >= 1
error("Transmitting packet for old frame (%lu)\r\n", frame);
#endif
- LastPacket.address = Packet.address;
- SDLNet_UDP_Send(gNetFD, -1, &LastPacket);
+ NET_SendDatagram(gSocket, datagram->addr, datagram->port, LastPacket.data, LastPacket.len);
} else if (frame == (NextFrame+1)) {
#if DEBUG_NETWORK >= 1
error("Received packet for next frame! (%lu, current = %lu)\r\n",
@@ -375,12 +352,11 @@ error("Received packet for next frame! (%lu, current = %lu)\r\n",
/* Cache this frame for next round */
CachedPacket[index].frame = frame;
CachedPacket[index].packet.Reset();
- CachedPacket[index].packet.Write(Packet);
+ CachedPacket[index].packet.Write(packet);
CachedPacket[index].packet.Seek(0);
/* Let the node know we're still waiting */
- CurrPacket.address = Packet.address;
- SDLNet_UDP_Send(gNetFD, -1, &CurrPacket);
+ NET_SendDatagram(gSocket, datagram->addr, datagram->port, CurrPacket.data, CurrPacket.len);
}
#if DEBUG_NETWORK >= 1
else
@@ -478,7 +454,12 @@ int Se
(Patch may be truncated, please check the link at the top of this post.)