diff options
Diffstat (limited to 'src/net_server.c')
-rw-r--r-- | src/net_server.c | 213 |
1 files changed, 128 insertions, 85 deletions
diff --git a/src/net_server.c b/src/net_server.c index d889c120..b837bd70 100644 --- a/src/net_server.c +++ b/src/net_server.c @@ -21,14 +21,15 @@ // Network server code // +#include <stdio.h> #include <stdarg.h> #include <stdlib.h> #include <string.h> #include "config.h" -#include "doomdef.h" -#include "doomstat.h" +#include "doomtype.h" +#include "d_mode.h" #include "i_system.h" #include "i_timer.h" @@ -92,6 +93,10 @@ typedef struct unsigned int acknowledged; + // Value of max_players specified by the client on connect. + + int max_players; + // Observer: receives data but does not participate in the game. boolean drone; @@ -105,6 +110,10 @@ typedef struct unsigned int is_freedoom; + // Player class (for Hexen) + + int player_class; + } net_client_t; // structure used for the recv window @@ -131,7 +140,7 @@ typedef struct static net_server_state_t server_state; static boolean server_initialized = false; static net_client_t clients[MAXNETNODES]; -static net_client_t *sv_players[MAXPLAYERS]; +static net_client_t *sv_players[NET_MAXPLAYERS]; static net_context_t *server_context; static unsigned int sv_gamemode; static unsigned int sv_gamemission; @@ -145,7 +154,7 @@ static unsigned int master_refresh_time; // receive window static unsigned int recvwindow_start; -static net_client_recv_t recvwindow[BACKUPTICS][MAXPLAYERS]; +static net_client_recv_t recvwindow[BACKUPTICS][NET_MAXPLAYERS]; #define NET_SV_ExpandTicNum(b) NET_ExpandTicNum(recvwindow_start, (b)) @@ -234,7 +243,7 @@ static void NET_SV_AssignPlayers(void) } } - for (; pl<MAXPLAYERS; ++pl) + for (; pl<NET_MAXPLAYERS; ++pl) { sv_players[pl] = NULL; } @@ -249,7 +258,7 @@ static int NET_SV_NumPlayers(void) result = 0; - for (i=0; i<MAXPLAYERS; ++i) + for (i=0; i<NET_MAXPLAYERS; ++i) { if (sv_players[i] != NULL && ClientConnected(sv_players[i])) { @@ -260,6 +269,23 @@ static int NET_SV_NumPlayers(void) return result; } +// Returns the maximum number of players that can play. + +static int NET_SV_MaxPlayers(void) +{ + int i; + + for (i = 0; i < MAXNETNODES; ++i) + { + if (ClientConnected(&clients[i])) + { + return clients[i].max_players; + } + } + + return NET_MAXPLAYERS; +} + // Returns the number of drones currently connected. static int NET_SV_NumDrones(void) @@ -349,7 +375,7 @@ static void NET_SV_AdvanceWindow(void) should_advance = true; - for (i=0; i<MAXPLAYERS; ++i) + for (i=0; i<NET_MAXPLAYERS; ++i) { if (sv_players[i] == NULL || !ClientConnected(sv_players[i])) { @@ -472,11 +498,7 @@ static void NET_SV_ParseSYN(net_packet_t *packet, net_addr_t *addr) { unsigned int magic; - unsigned int cl_gamemode, cl_gamemission; - unsigned int cl_recording_lowres; - unsigned int cl_drone; - unsigned int is_freedoom; - md5_digest_t deh_md5sum, wad_md5sum; + net_connect_data_t data; char *player_name; char *client_version; int i; @@ -526,18 +548,19 @@ static void NET_SV_ParseSYN(net_packet_t *packet, // read the game mode and mission - if (!NET_ReadInt16(packet, &cl_gamemode) - || !NET_ReadInt16(packet, &cl_gamemission) - || !NET_ReadInt8(packet, &cl_recording_lowres) - || !NET_ReadInt8(packet, &cl_drone) - || !NET_ReadMD5Sum(packet, wad_md5sum) - || !NET_ReadMD5Sum(packet, deh_md5sum) - || !NET_ReadInt8(packet, &is_freedoom)) + if (!NET_ReadConnectData(packet, &data)) + { + return; + } + + if (!D_ValidGameMode(data.gamemission, data.gamemode)) { return; } - if (!NET_ValidGameMode(cl_gamemode, cl_gamemission)) + // Check max_players value. This must be in a sensible range. + + if (data.max_players > NET_MAXPLAYERS) { return; } @@ -604,7 +627,7 @@ static void NET_SV_ParseSYN(net_packet_t *packet, NET_SV_AssignPlayers(); num_players = NET_SV_NumPlayers(); - if ((!cl_drone && num_players >= MAXPLAYERS) + if ((!data.drone && num_players >= NET_SV_MaxPlayers()) || NET_SV_NumClients() >= MAXNETNODES) { NET_SV_SendReject(addr, "Server is full!"); @@ -617,33 +640,35 @@ static void NET_SV_ParseSYN(net_packet_t *packet, // Adopt the game mode and mission of the first connecting client - if (num_players == 0 && !cl_drone) + if (num_players == 0 && !data.drone) { - sv_gamemode = cl_gamemode; - sv_gamemission = cl_gamemission; + sv_gamemode = data.gamemode; + sv_gamemission = data.gamemission; } // Save the MD5 checksums - memcpy(client->wad_md5sum, wad_md5sum, sizeof(md5_digest_t)); - memcpy(client->deh_md5sum, deh_md5sum, sizeof(md5_digest_t)); - client->is_freedoom = is_freedoom; + memcpy(client->wad_md5sum, data.wad_md5sum, sizeof(md5_digest_t)); + memcpy(client->deh_md5sum, data.deh_md5sum, sizeof(md5_digest_t)); + client->is_freedoom = data.is_freedoom; + client->max_players = data.max_players; // Check the connecting client is playing the same game as all // the other clients - if (cl_gamemode != sv_gamemode || cl_gamemission != sv_gamemission) + if (data.gamemode != sv_gamemode || data.gamemission != sv_gamemission) { NET_SV_SendReject(addr, "You are playing the wrong game!"); return; } - + // Activate, initialize connection NET_SV_InitNewClient(client, addr, player_name); - client->recording_lowres = cl_recording_lowres; - client->drone = cl_drone; + client->recording_lowres = data.lowres_turn; + client->drone = data.drone; + client->player_class = data.player_class; } if (client->connection.state == NET_CONN_STATE_WAITING_ACK) @@ -698,7 +723,7 @@ static void NET_SV_ParseGameStart(net_packet_t *packet, net_client_t *client) settings.lowres_turn = false; - for (i=0; i<MAXPLAYERS; ++i) + for (i=0; i<NET_MAXPLAYERS; ++i) { if (sv_players[i] != NULL && sv_players[i]->recording_lowres) { @@ -706,6 +731,22 @@ static void NET_SV_ParseGameStart(net_packet_t *packet, net_client_t *client) } } + settings.num_players = NET_SV_NumPlayers(); + + // Copy player classes: + + for (i = 0; i < NET_MAXPLAYERS; ++i) + { + if (sv_players[i] != NULL) + { + settings.player_classes[i] = sv_players[i]->player_class; + } + else + { + settings.player_classes[i] = 0; + } + } + nowtime = I_GetTimeMS(); // Send start packets to each connected node @@ -720,8 +761,8 @@ static void NET_SV_ParseGameStart(net_packet_t *packet, net_client_t *client) startpacket = NET_Conn_NewReliable(&clients[i].connection, NET_PACKET_TYPE_GAMESTART); - NET_WriteInt8(startpacket, NET_SV_NumPlayers()); - NET_WriteInt8(startpacket, clients[i].player_number); + settings.consoleplayer = clients[i].player_number; + NET_WriteSettings(startpacket, &settings); } @@ -1108,7 +1149,7 @@ void NET_SV_SendQueryResponse(net_addr_t *addr) // Number of players/maximum players querydata.num_players = NET_SV_NumPlayers(); - querydata.max_players = MAXPLAYERS; + querydata.max_players = NET_SV_MaxPlayers(); // Game mode/mission @@ -1222,71 +1263,58 @@ static void NET_SV_Packet(net_packet_t *packet, net_addr_t *addr) static void NET_SV_SendWaitingData(net_client_t *client) { + net_waitdata_t wait_data; net_packet_t *packet; net_client_t *controller; - int num_players; int i; NET_SV_AssignPlayers(); controller = NET_SV_Controller(); - num_players = NET_SV_NumPlayers(); + wait_data.num_players = NET_SV_NumPlayers(); + wait_data.num_drones = NET_SV_NumDrones(); + wait_data.max_players = NET_SV_MaxPlayers(); + wait_data.is_controller = (client == controller); + wait_data.consoleplayer = client->player_number; - // time to send the client another status packet - - packet = NET_NewPacket(10); - NET_WriteInt16(packet, NET_PACKET_TYPE_WAITING_DATA); - - // include the number of players waiting - - NET_WriteInt8(packet, num_players); - - // send the number of drone clients - - NET_WriteInt8(packet, NET_SV_NumDrones()); - - // indicate whether the client is the controller - - NET_WriteInt8(packet, client == controller); - - // send the player number of this client - - NET_WriteInt8(packet, client->player_number); - - // send the addresses of all players + // Send the WAD and dehacked checksums of the controlling client. + // If no controller found (?), send the details that the client + // is expecting anyway. - for (i=0; i<num_players; ++i) + if (controller != NULL) { - char *addr; - - // name + controller = client; + } - NET_WriteString(packet, sv_players[i]->name); + memcpy(&wait_data.wad_md5sum, &controller->wad_md5sum, + sizeof(md5_digest_t)); + memcpy(&wait_data.deh_md5sum, &controller->deh_md5sum, + sizeof(md5_digest_t)); + wait_data.is_freedoom = controller->is_freedoom; - // address + // set name and address of each player: - addr = NET_AddrToString(sv_players[i]->addr); + for (i = 0; i < wait_data.num_players; ++i) + { + strncpy(wait_data.player_names[i], + sv_players[i]->name, + MAXPLAYERNAME); + wait_data.player_names[i][MAXPLAYERNAME-1] = '\0'; - NET_WriteString(packet, addr); + strncpy(wait_data.player_addrs[i], + NET_AddrToString(sv_players[i]->addr), + MAXPLAYERNAME); + wait_data.player_addrs[i][MAXPLAYERNAME-1] = '\0'; } - // Send the WAD and dehacked checksums of the controlling client. + // Construct packet: - if (controller != NULL) - { - NET_WriteMD5Sum(packet, controller->wad_md5sum); - NET_WriteMD5Sum(packet, controller->deh_md5sum); - NET_WriteInt8(packet, controller->is_freedoom); - } - else - { - NET_WriteMD5Sum(packet, client->wad_md5sum); - NET_WriteMD5Sum(packet, client->deh_md5sum); - NET_WriteInt8(packet, client->is_freedoom); - } + packet = NET_NewPacket(10); + NET_WriteInt16(packet, NET_PACKET_TYPE_WAITING_DATA); + NET_WriteWaitData(packet, &wait_data); - // send packet to client and free + // Send packet to client and free NET_Conn_SendPacket(&client->connection, packet); NET_FreePacket(packet); @@ -1296,6 +1324,7 @@ static void NET_SV_PumpSendQueue(net_client_t *client) { net_full_ticcmd_t cmd; int recv_index; + int num_players; int i; int starttic, endtic; @@ -1319,7 +1348,9 @@ static void NET_SV_PumpSendQueue(net_client_t *client) // Check if we can generate a new entry for the send queue // using the data in recvwindow. - for (i=0; i<MAXPLAYERS; ++i) + num_players = 0; + + for (i=0; i<NET_MAXPLAYERS; ++i) { if (sv_players[i] == client) { @@ -1340,6 +1371,19 @@ static void NET_SV_PumpSendQueue(net_client_t *client) return; } + + ++num_players; + } + + // If this is a game with only a single player in it, we might + // be sending a ticcmd set containing 0 ticcmds. This is fine; + // however, there's nothing to stop the game running on ahead + // and never stopping. Don't let the server get too far ahead + // of the client. + + if (num_players == 0 && client->sendseq > recvwindow_start + 10) + { + return; } //printf("SV: have complete ticcmd for %i\n", client->sendseq); @@ -1352,7 +1396,7 @@ static void NET_SV_PumpSendQueue(net_client_t *client) cmd.latency = 0; - for (i=0; i<MAXPLAYERS; ++i) + for (i=0; i<NET_MAXPLAYERS; ++i) { net_client_recv_t *recvobj; @@ -1632,7 +1676,7 @@ void NET_SV_Run(void) { NET_SV_AdvanceWindow(); - for (i=0; i<MAXPLAYERS; ++i) + for (i=0; i<NET_MAXPLAYERS; ++i) { if (sv_players[i] != NULL && ClientConnected(sv_players[i])) { @@ -1702,4 +1746,3 @@ void NET_SV_Shutdown(void) I_Sleep(1); } } - |