summaryrefslogtreecommitdiff
path: root/src/net_server.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/net_server.c')
-rw-r--r--src/net_server.c213
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);
}
}
-