Implement singleplayer in the dedicated server.

When set to `1`, both `deathmatch` and `coop` are forced to `0`.
`maxclients` is forced to `1`. This makes it possible to play single
player campaigns over the dedicated server.

Closes #614.
This commit is contained in:
Yamagi 2021-01-17 11:07:46 +01:00
parent f01998896f
commit 2fae58d56b
3 changed files with 44 additions and 7 deletions

View file

@ -95,6 +95,16 @@ it's `+set busywait 0` (setting the `busywait` cvar) and `-portable`
during gameplay and released otherwise (in menu, videos, console or if during gameplay and released otherwise (in menu, videos, console or if
game is paused). game is paused).
* **singleplayer**: Only available in the dedicated server. Vanilla
Quake II enforced that either `coop` or `deathmatch` is set to `1`
when running the dedicated server. That made it impossible to play
single player campaigns over the dedicated server. When set to `1`,
both `coop` and `deathmatch` are forced to `0` and `maxclients` is
forced to `1`. This can be used to run a dedicated server with an old
single player mod, where the source code isn't available, inside a
Windows 98 or XP VM and connect over network from an non Windows
system.
* **coop_pickup_weapons**: In coop a weapon can be picked up only once. * **coop_pickup_weapons**: In coop a weapon can be picked up only once.
For example, if the player already has the shotgun they cannot pickup For example, if the player already has the shotgun they cannot pickup
a second shotgun found at a later time, thus not getting the ammo that a second shotgun found at a later time, thus not getting the ammo that

View file

@ -333,6 +333,12 @@ SV_InitGame(void)
svs.initialized = true; svs.initialized = true;
if (Cvar_VariableValue("singleplayer"))
{
Cvar_FullSet("coop", "0", CVAR_SERVERINFO | CVAR_LATCH);
Cvar_FullSet("deathmatch", "0", CVAR_SERVERINFO | CVAR_LATCH);
}
if (Cvar_VariableValue("coop") && Cvar_VariableValue("deathmatch")) if (Cvar_VariableValue("coop") && Cvar_VariableValue("deathmatch"))
{ {
Com_Printf("Deathmatch and Coop both set, disabling Coop\n"); Com_Printf("Deathmatch and Coop both set, disabling Coop\n");
@ -342,12 +348,15 @@ SV_InitGame(void)
/* dedicated servers can't be single player and are usually DM /* dedicated servers can't be single player and are usually DM
so unless they explicity set coop, force it to deathmatch */ so unless they explicity set coop, force it to deathmatch */
if (dedicated->value) if (dedicated->value)
{
if (!Cvar_VariableValue("singleplayer"))
{ {
if (!Cvar_VariableValue("coop")) if (!Cvar_VariableValue("coop"))
{ {
Cvar_FullSet("deathmatch", "1", CVAR_SERVERINFO | CVAR_LATCH); Cvar_FullSet("deathmatch", "1", CVAR_SERVERINFO | CVAR_LATCH);
} }
} }
}
/* init clients */ /* init clients */
if (Cvar_VariableValue("deathmatch")) if (Cvar_VariableValue("deathmatch"))
@ -358,9 +367,10 @@ SV_InitGame(void)
} }
else if (maxclients->value > MAX_CLIENTS) else if (maxclients->value > MAX_CLIENTS)
{ {
Cvar_FullSet("maxclients", va("%i", Cvar_FullSet("maxclients", va("%i", MAX_CLIENTS), CVAR_SERVERINFO | CVAR_LATCH);
MAX_CLIENTS), CVAR_SERVERINFO | CVAR_LATCH);
} }
Cvar_FullSet("singleplayer", "0", 0);
} }
else if (Cvar_VariableValue("coop")) else if (Cvar_VariableValue("coop"))
{ {
@ -368,20 +378,36 @@ SV_InitGame(void)
{ {
Cvar_FullSet("maxclients", "4", CVAR_SERVERINFO | CVAR_LATCH); Cvar_FullSet("maxclients", "4", CVAR_SERVERINFO | CVAR_LATCH);
} }
Cvar_FullSet("singleplayer", "0", 0);
} }
else /* non-deathmatch, non-coop is one player */ else /* non-deathmatch, non-coop is one player */
{ {
Cvar_FullSet("maxclients", "1", CVAR_SERVERINFO | CVAR_LATCH); Cvar_FullSet("maxclients", "1", CVAR_SERVERINFO | CVAR_LATCH);
Cvar_FullSet("singleplayer", "1", 0);
} }
svs.spawncount = randk(); svs.spawncount = randk();
svs.clients = Z_Malloc(sizeof(client_t) * maxclients->value); svs.clients = Z_Malloc(sizeof(client_t) * maxclients->value);
svs.num_client_entities = maxclients->value * UPDATE_BACKUP * 64; svs.num_client_entities = maxclients->value * UPDATE_BACKUP * 64;
svs.client_entities = svs.client_entities = Z_Malloc( sizeof(entity_state_t) * svs.num_client_entities);
Z_Malloc( sizeof(entity_state_t) * svs.num_client_entities);
/* init network stuff */ /* init network stuff */
if (dedicated->value)
{
if (Cvar_VariableValue("singleplayer"))
{
NET_Config(true);
}
else
{
NET_Config((maxclients->value > 1)); NET_Config((maxclients->value > 1));
}
}
else
{
NET_Config((maxclients->value > 1));
}
/* heartbeats will always be sent to the id master */ /* heartbeats will always be sent to the id master */
svs.last_heartbeat = -99999; /* send immediately */ svs.last_heartbeat = -99999; /* send immediately */

View file

@ -584,6 +584,7 @@ SV_Init(void)
rcon_password = Cvar_Get("rcon_password", "", 0); rcon_password = Cvar_Get("rcon_password", "", 0);
Cvar_Get("skill", "1", 0); Cvar_Get("skill", "1", 0);
Cvar_Get("singleplayer", "0", 0);
Cvar_Get("deathmatch", "0", CVAR_LATCH); Cvar_Get("deathmatch", "0", CVAR_LATCH);
Cvar_Get("coop", "0", CVAR_LATCH); Cvar_Get("coop", "0", CVAR_LATCH);
Cvar_Get("dmflags", va("%i", DF_INSTANT_ITEMS), CVAR_SERVERINFO); Cvar_Get("dmflags", va("%i", DF_INSTANT_ITEMS), CVAR_SERVERINFO);