diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6bad850a9cf7b56857a19af20bbd139ea2ebdb62..bc9b599f04da6d49a158e42294f79b496a8eaad6 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -8,6 +8,7 @@ set(SRB2_CORE_SOURCES comptime.c console.c d_clisrv.c + d_datawrap.c d_enet.c d_main.c d_netcmd.c @@ -52,6 +53,7 @@ set(SRB2_CORE_HEADERS command.h console.h d_clisrv.h + d_datawrap.h d_enet.h d_event.h d_main.h diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 55d1880232e3a2a2eb1774e882c6fb6e78bae35f..0e6a9999f7ed3d3d2a1dc37caa9e766f389e12f6 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -481,6 +481,7 @@ static boolean CL_SendJoin(void) return true; } // NET TODO + Net_SendJoin(); return true; } @@ -643,6 +644,12 @@ static void CL_LoadReceivedSavegame(void) #ifndef NONET static void SendAskInfo(INT32 node, boolean viams) { + //if (server) + {// I'm the server, skip this. + // I'm the server, skip this. + cl_mode = cl_askjoin; + return; + } // NET TODO } @@ -722,10 +729,7 @@ static void CL_ConnectToServer(boolean viams) sprintf(tmpsave, "%s" PATHSEP TMPSAVENAME, srb2home); #endif - if (servernode == 0) - cl_mode = cl_askjoin; - else - cl_mode = cl_searching; + cl_mode = cl_searching; #ifdef CLIENT_LOADINGSCREEN lastfilenum = 0; @@ -891,15 +895,9 @@ static void CL_ConnectToServer(boolean viams) cl_mode = cl_askjoin; // don't break case continue to cljoin request now case cl_askjoin: - if (!server) + if (!server) // the server already has their files loaded, duh! CL_LoadServerFiles(); -#ifdef JOININGAME - // prepare structures to save the file - // WARNING: this can be useless in case of server not in GS_LEVEL - // but since the network layer doesn't provide ordered packets... - CL_PrepareDownloadSaveGame(tmpsave); -#endif - if (CL_SendJoin()) + if (CL_SendJoin()) // Send join request, server instantly connects. cl_mode = server ? cl_connected : cl_waitjoinresponse; break; #ifdef JOININGAME diff --git a/src/d_datawrap.c b/src/d_datawrap.c new file mode 100644 index 0000000000000000000000000000000000000000..1db92357cae6fa64d5a25fef0f46ffcd24318ffb --- /dev/null +++ b/src/d_datawrap.c @@ -0,0 +1,55 @@ +#include "doomdef.h" +#include "doomstat.h" +#include "byteptr.h" +#include "d_datawrap.h" +#include "z_zone.h" + +static void CheckEOF(DataWrap dw, size_t l) +{ + if (dw->p - dw->data + l > dw->len) + { + Z_Free(dw); + longjmp(*dw->eofjmp, 1); + } +} + +static UINT8 ReadUINT8(DataWrap dw) +{ + CheckEOF(dw, 1); + return READUINT8(dw->p); +} + +static UINT16 ReadUINT16(DataWrap dw) +{ + CheckEOF(dw, 2); + return READUINT16(dw->p); +} + +static char *ReadStringn(DataWrap dw, size_t n) +{ + char *string = ZZ_Alloc(n+1); + char *p = string; + int i; + for (i = 0; i < n; i++, p++) + { + CheckEOF(dw,1); + *p = READUINT8(dw->p); + if (!*p) + break; + } + *p = '\0'; + return string; +} + +DataWrap D_NewDataWrap(const void *data, size_t len, jmp_buf *eofjmp) +{ + DataWrap dw = ZZ_Alloc(sizeof(struct DataWrap_s)); + dw->data = dw->p = data; + dw->len = len; + dw->eofjmp = eofjmp; + + dw->ReadUINT8 = ReadUINT8; + dw->ReadUINT16 = ReadUINT16; + dw->ReadStringn = ReadStringn; + return dw; +} diff --git a/src/d_datawrap.h b/src/d_datawrap.h new file mode 100644 index 0000000000000000000000000000000000000000..5e7374de4249c293b89f33be265c57d395fc1455 --- /dev/null +++ b/src/d_datawrap.h @@ -0,0 +1,14 @@ +// Basically SDL_RWops I guess. +#include <setjmp.h> + +typedef struct DataWrap_s { + const void *data, *p; + size_t len; + jmp_buf *eofjmp; + + UINT8 (*ReadUINT8)(struct DataWrap_s *); + UINT16 (*ReadUINT16)(struct DataWrap_s *); + char *(*ReadStringn)(struct DataWrap_s *, size_t n); +} *DataWrap; + +DataWrap D_NewDataWrap(const void *data, size_t len, jmp_buf *eofjmp); diff --git a/src/d_enet.c b/src/d_enet.c index 5db2b8ffc88eb9f4ef0ef0f991fbe98a2c741512..fd3b2b04a4d041a36b49c8e0a13ec53ba1c2bdae 100644 --- a/src/d_enet.c +++ b/src/d_enet.c @@ -2,9 +2,11 @@ #include "doomdef.h" #include "doomstat.h" +#include "byteptr.h" #include "d_enet.h" #include "z_zone.h" #include "m_menu.h" +#include "d_datawrap.h" UINT8 net_nodecount, net_playercount; UINT8 playernode[MAXPLAYERS]; @@ -15,7 +17,12 @@ boolean nodeingame[MAXNETNODES]; // set false as nodes leave game #define NETCHANNELS 4 -#define DISCONNECT_SHUTDOWN 1 +enum { + DISCONNECT_UNKNOWN = 0, + DISCONNECT_SHUTDOWN, + + CLIENT_JOIN = 0 +}; static ENetHost *ServerHost = NULL, *ClientHost = NULL; @@ -24,7 +31,7 @@ static UINT8 nodeleaving[MAXNETNODES]; typedef struct PeerData_s { UINT8 node; -} PeerData_t; +} PeerData; boolean Net_GetNetStat(void) { @@ -32,17 +39,36 @@ boolean Net_GetNetStat(void) return false; } +static void ServerHandlePacket(UINT8 node, DataWrap data) +{ + switch(data->ReadUINT8(data)) + { + case CLIENT_JOIN: + { + UINT16 version = data->ReadUINT16(data); + UINT16 subversion = data->ReadUINT16(data); + if (version != VERSION || subversion != SUBVERSION) + CONS_Printf("NETWORK: Version mismatch!?\n"); + char *name = data->ReadStringn(data, MAXPLAYERNAME); + CONS_Printf("NETWORK: Player '%s' joining...\n", name); + break; + } + default: + CONS_Printf("NETWORK: Unknown message type recieved from node %u!\n", node); + break; + } +} + void Net_AckTicker(void) { ENetEvent e; UINT8 i; - PeerData_t *pdata; + PeerData *pdata; + jmp_buf safety; while (ClientHost && enet_host_service(ClientHost, &e, 0) > 0) switch (e.type) { - case ENET_EVENT_TYPE_CONNECT: - break; case ENET_EVENT_TYPE_DISCONNECT: if (!server) { @@ -54,9 +80,11 @@ void Net_AckTicker(void) M_StartMessage(M_GetText("Disconnected from server.\n\nPress ESC\n"), NULL, MM_NOTHING); } break; + case ENET_EVENT_TYPE_RECEIVE: enet_packet_destroy(e.packet); break; + default: break; } @@ -65,16 +93,19 @@ void Net_AckTicker(void) switch (e.type) { case ENET_EVENT_TYPE_CONNECT: - for (i = 0; i < MAXNETNODES && nodetopeer[i]; i++) + for (i = 0; i < MAXNETNODES && nodeingame[i]; i++) ; I_Assert(i < MAXNETNODES); // ENet should not be able to send connect events when nodes are full. + nodeingame[i] = true; nodetopeer[i] = e.peer; pdata = ZZ_Alloc(sizeof(*pdata)); pdata->node = i; e.peer->data = pdata; + CONS_Printf("NETWORK: Node %u connected.\n", i); break; + case ENET_EVENT_TYPE_DISCONNECT: - pdata = (PeerData_t *)e.peer->data; + pdata = (PeerData *)e.peer->data; if (!nodeleaving[pdata->node]) { XBOXSTATIC UINT8 buf[2]; @@ -93,9 +124,16 @@ void Net_AckTicker(void) Z_Free(pdata); e.peer->data = NULL; break; + case ENET_EVENT_TYPE_RECEIVE: + pdata = (PeerData *)e.peer->data; + if (setjmp(safety)) + CONS_Printf("NETWORK: There was an EOF error in a recieved packet! Node %u, len %u\n", pdata->node, e.packet->dataLength); + else + ServerHandlePacket(pdata->node, D_NewDataWrap(e.packet->data, e.packet->dataLength, &safety)); enet_packet_destroy(e.packet); break; + default: break; } @@ -118,7 +156,9 @@ void D_NetOpen(void) ServerHost = enet_host_create(&address, MAXNETNODES, NETCHANNELS, 0, 0); if (!ServerHost) I_Error("ENet failed to open server host. (Check if the port is in use?)"); + servernode = 0; + nodeingame[servernode] = true; } void D_NetConnect(const char *hostname, const char *port) @@ -131,7 +171,7 @@ void D_NetConnect(const char *hostname, const char *port) I_Error("ENet failed to initialize client host."); netgame = multiplayer = true; - servernode = 1; + servernode = 0; enet_address_set_host(&address, hostname); address.port = 5029; @@ -141,6 +181,7 @@ void D_NetConnect(const char *hostname, const char *port) nodetopeer[servernode] = enet_host_connect(ClientHost, &address, NETCHANNELS, 0); if (!nodetopeer[servernode]) I_Error("Failed to allocate ENet peer for connecting ???"); + nodeingame[servernode] = true; if (enet_host_service(ClientHost, &e, 5000) > 0 && e.type == ENET_EVENT_TYPE_CONNECT) @@ -175,13 +216,16 @@ void D_CloseConnection(void) ENetEvent e; if (ServerHost) { - UINT8 i; + UINT8 i, waiting=0; // tell everyone to go away for (i = 0; i < MAXNETNODES; i++) if (nodeingame[i]) + { enet_peer_disconnect(nodetopeer[i], DISCONNECT_SHUTDOWN); + waiting++; + } // wait for messages to go through. - while (enet_host_service(ServerHost, &e, 3000) > 0) + while (waiting > 0 && enet_host_service(ServerHost, &e, 3000) > 0) switch (e.type) { // i don't care, shut up. @@ -190,6 +234,7 @@ void D_CloseConnection(void) break; // good, go away. case ENET_EVENT_TYPE_DISCONNECT: + waiting--; break; // no, we're shutting down. case ENET_EVENT_TYPE_CONNECT: @@ -199,24 +244,28 @@ void D_CloseConnection(void) // alright, we're finished. enet_host_destroy(ServerHost); } + if (ClientHost) { enet_peer_disconnect(nodetopeer[servernode], 0); while (enet_host_service(ServerHost, &e, 3000) > 0) - switch (e.type) + { + if (e.type == ENET_EVENT_TYPE_DISCONNECT) + break; + else switch (e.type) { case ENET_EVENT_TYPE_RECEIVE: enet_packet_destroy(e.packet); break; - case ENET_EVENT_TYPE_DISCONNECT: - break; case ENET_EVENT_TYPE_CONNECT: // how the what ??? enet_peer_reset(e.peer); break; } + } enet_host_destroy(ClientHost); } + netgame = false; addedtogame = false; servernode = 0; @@ -234,14 +283,26 @@ void Net_CloseConnection(INT32 node) enet_peer_disconnect(nodetopeer[node], 0); } -void Net_AbortPacketType(UINT8 packettype) +void Net_SendAcks(INT32 node) { } -void Net_SendAcks(INT32 node) +void Net_WaitAllAckReceived(UINT32 timeout) { } -void Net_WaitAllAckReceived(UINT32 timeout) +// Client: Can I play? =3 My name is Player so-and-so! +void Net_SendJoin(void) { + ENetPacket *packet; + UINT8 data[5+MAXPLAYERNAME]; + UINT8 *buf = data; + + WRITEUINT8(buf, CLIENT_JOIN); + WRITEUINT16(buf, VERSION); + WRITEUINT16(buf, SUBVERSION); + WRITESTRINGN(buf, cv_playername.string, MAXPLAYERNAME); + + packet = enet_packet_create(data, buf-data, ENET_PACKET_FLAG_RELIABLE); + enet_peer_send(nodetopeer[servernode], 0, packet); } diff --git a/src/d_enet.h b/src/d_enet.h index 6cc954a6da29f572434652ca5cbee63d0673f88f..6d249e52d93bb33cbc1913748966afd0e6b25d38 100644 --- a/src/d_enet.h +++ b/src/d_enet.h @@ -17,6 +17,7 @@ boolean D_CheckNetGame(void); void D_CloseConnection(void); void Net_UnAcknowledgPacket(INT32 node); void Net_CloseConnection(INT32 node); -void Net_AbortPacketType(UINT8 packettype); void Net_SendAcks(INT32 node); void Net_WaitAllAckReceived(UINT32 timeout); + +void Net_SendJoin(void);