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
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.
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

View File

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

View File

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