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 189e824f..585f0eac 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"
@@ -96,6 +97,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;
@@ -109,6 +114,10 @@ typedef struct
unsigned int is_freedoom;
+ // Player class (for Hexen)
+
+ int player_class;
+
} net_client_t;
// structure used for the recv window
@@ -135,7 +144,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;
@@ -150,7 +159,7 @@ static unsigned int master_resolve_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))
@@ -239,7 +248,7 @@ static void NET_SV_AssignPlayers(void)
}
}
- for (; pl<MAXPLAYERS; ++pl)
+ for (; pl<NET_MAXPLAYERS; ++pl)
{
sv_players[pl] = NULL;
}
@@ -254,7 +263,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]))
{
@@ -265,6 +274,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)
@@ -354,7 +380,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]))
{
@@ -477,11 +503,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;
- sha1_digest_t deh_sha1sum, wad_sha1sum;
+ net_connect_data_t data;
char *player_name;
char *client_version;
int i;
@@ -531,18 +553,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_ReadSHA1Sum(packet, wad_sha1sum)
- || !NET_ReadSHA1Sum(packet, deh_sha1sum)
- || !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;
}
@@ -609,7 +632,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!");
@@ -622,33 +645,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 SHA1 checksums
- memcpy(client->wad_sha1sum, wad_sha1sum, sizeof(sha1_digest_t));
- memcpy(client->deh_sha1sum, deh_sha1sum, sizeof(sha1_digest_t));
- client->is_freedoom = is_freedoom;
+ memcpy(client->wad_sha1sum, data.wad_sha1sum, sizeof(sha1_digest_t));
+ memcpy(client->deh_sha1sum, data.deh_sha1sum, sizeof(sha1_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)
@@ -703,7 +728,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)
{
@@ -711,6 +736,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
@@ -725,8 +766,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);
}
@@ -1113,7 +1154,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
@@ -1227,71 +1268,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_sha1sum, &controller->wad_sha1sum,
+ sizeof(sha1_digest_t));
+ memcpy(&wait_data.deh_sha1sum, &controller->deh_sha1sum,
+ sizeof(sha1_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_WriteSHA1Sum(packet, controller->wad_sha1sum);
- NET_WriteSHA1Sum(packet, controller->deh_sha1sum);
- NET_WriteInt8(packet, controller->is_freedoom);
- }
- else
- {
- NET_WriteSHA1Sum(packet, client->wad_sha1sum);
- NET_WriteSHA1Sum(packet, client->deh_sha1sum);
- 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);
@@ -1301,6 +1329,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;
@@ -1324,7 +1353,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)
{
@@ -1345,6 +1376,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);
@@ -1357,7 +1401,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;
@@ -1670,7 +1714,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]))
{
@@ -1740,4 +1784,3 @@ void NET_SV_Shutdown(void)
I_Sleep(1);
}
}
-