cvar_t pr_checkextension = {CF_SERVER | CF_READONLY, "pr_checkextension", "1", "indicates to QuakeC that the standard quakec extensions system is available (if 0, quakec should not attempt to use extensions)"};
cvar_t samelevel = {CF_SERVER | CF_NOTIFY, "samelevel","0", "repeats same level if level ends (due to timelimit or someone hitting an exit)"};
cvar_t skill = {CF_SERVER, "skill","1", "difficulty level of game, affects monster layouts in levels, 0 = easy, 1 = normal, 2 = hard, 3 = nightmare (same layout as hard but monsters fire twice)"};
cvar_t pr_checkextension = {CF_SERVER | CF_READONLY, "pr_checkextension", "1", "indicates to QuakeC that the standard quakec extensions system is available (if 0, quakec should not attempt to use extensions)"};
cvar_t samelevel = {CF_SERVER | CF_NOTIFY, "samelevel","0", "repeats same level if level ends (due to timelimit or someone hitting an exit)"};
cvar_t skill = {CF_SERVER, "skill","1", "difficulty level of game, affects monster layouts in levels, 0 = easy, 1 = normal, 2 = hard, 3 = nightmare (same layout as hard but monsters fire twice)"};
cvar_t host_timescale = {CF_CLIENT | CF_SERVER, "host_timescale", "1.0", "controls game speed, 0.5 is half speed, 2 is double speed"};
cvar_t sv_accelerate = {CF_SERVER, "sv_accelerate", "10", "rate at which a player accelerates to sv_maxspeed"};
cvar_t host_timescale = {CF_CLIENT | CF_SERVER, "host_timescale", "1.0", "controls game speed, 0.5 is half speed, 2 is double speed"};
cvar_t sv_accelerate = {CF_SERVER, "sv_accelerate", "10", "rate at which a player accelerates to sv_maxspeed"};
cvar_t sv_clmovement_enable = {CF_SERVER, "sv_clmovement_enable", "1", "whether to allow clients to use cl_movement prediction, which can cause choppy movement on the server which may annoy other players"};
cvar_t sv_clmovement_minping = {CF_SERVER, "sv_clmovement_minping", "0", "if client ping is below this time in milliseconds, then their ability to use cl_movement prediction is disabled for a while (as they don't need it)"};
cvar_t sv_clmovement_minping_disabletime = {CF_SERVER, "sv_clmovement_minping_disabletime", "1000", "when client falls below minping, disable their prediction for this many milliseconds (should be at least 1000 or else their prediction may turn on/off frequently)"};
cvar_t sv_clmovement_enable = {CF_SERVER, "sv_clmovement_enable", "1", "whether to allow clients to use cl_movement prediction, which can cause choppy movement on the server which may annoy other players"};
cvar_t sv_clmovement_minping = {CF_SERVER, "sv_clmovement_minping", "0", "if client ping is below this time in milliseconds, then their ability to use cl_movement prediction is disabled for a while (as they don't need it)"};
cvar_t sv_clmovement_minping_disabletime = {CF_SERVER, "sv_clmovement_minping_disabletime", "1000", "when client falls below minping, disable their prediction for this many milliseconds (should be at least 1000 or else their prediction may turn on/off frequently)"};
-cvar_t sv_clmovement_inputtimeout = {CF_SERVER, "sv_clmovement_inputtimeout", "0.2", "when a client does not send input for this many seconds, force them to move anyway (unlike QuakeWorld)"};
+cvar_t sv_clmovement_inputtimeout = {CF_SERVER, "sv_clmovement_inputtimeout", "0.1", "when a client does not send input for this many seconds (max 0.1), force them to move anyway (unlike QuakeWorld)"};
cvar_t sv_cullentities_nevercullbmodels = {CF_SERVER, "sv_cullentities_nevercullbmodels", "0", "if enabled the clients are always notified of moving doors and lifts and other submodels of world (warning: eats a lot of network bandwidth on some levels!)"};
cvar_t sv_cullentities_pvs = {CF_SERVER, "sv_cullentities_pvs", "1", "fast but loose culling of hidden entities"};
cvar_t sv_cullentities_stats = {CF_SERVER, "sv_cullentities_stats", "0", "displays stats on network entities culled by various methods for each client"};
cvar_t sv_cullentities_nevercullbmodels = {CF_SERVER, "sv_cullentities_nevercullbmodels", "0", "if enabled the clients are always notified of moving doors and lifts and other submodels of world (warning: eats a lot of network bandwidth on some levels!)"};
cvar_t sv_cullentities_pvs = {CF_SERVER, "sv_cullentities_pvs", "1", "fast but loose culling of hidden entities"};
cvar_t sv_cullentities_stats = {CF_SERVER, "sv_cullentities_stats", "0", "displays stats on network entities culled by various methods for each client"};
cvar_t sv_stepheight = {CF_SERVER | CF_NOTIFY, "sv_stepheight", "18", "how high you can step up (TW_SV_STEPCONTROL extension)"};
cvar_t sv_stopspeed = {CF_SERVER | CF_NOTIFY, "sv_stopspeed","100", "how fast you come to a complete stop"};
cvar_t sv_wallfriction = {CF_SERVER | CF_NOTIFY, "sv_wallfriction", "1", "how much you slow down when sliding along a wall"};
cvar_t sv_stepheight = {CF_SERVER | CF_NOTIFY, "sv_stepheight", "18", "how high you can step up (TW_SV_STEPCONTROL extension)"};
cvar_t sv_stopspeed = {CF_SERVER | CF_NOTIFY, "sv_stopspeed","100", "how fast you come to a complete stop"};
cvar_t sv_wallfriction = {CF_SERVER | CF_NOTIFY, "sv_wallfriction", "1", "how much you slow down when sliding along a wall"};
-cvar_t sv_wateraccelerate = {CF_SERVER, "sv_wateraccelerate", "-1", "rate at which a player accelerates to sv_maxspeed while in the air, if less than 0 the sv_accelerate variable is used instead"};
-cvar_t sv_waterfriction = {CF_SERVER | CF_NOTIFY, "sv_waterfriction","-1", "how fast you slow down, if less than 0 the sv_friction variable is used instead"};
+cvar_t sv_wateraccelerate = {CF_SERVER, "sv_wateraccelerate", "-1", "rate at which a player accelerates to sv_maxspeed while in water, if less than 0 the sv_accelerate variable is used instead"};
+cvar_t sv_waterfriction = {CF_SERVER | CF_NOTIFY, "sv_waterfriction","-1", "how fast you slow down in water, if less than 0 the sv_friction variable is used instead"};
cvar_t sv_warsowbunny_airforwardaccel = {CF_SERVER, "sv_warsowbunny_airforwardaccel", "1.00001", "how fast you accelerate until you reach sv_maxspeed"};
cvar_t sv_warsowbunny_accel = {CF_SERVER, "sv_warsowbunny_accel", "0.1585", "how fast you accelerate until after reaching sv_maxspeed (it gets harder as you near sv_warsowbunny_topspeed)"};
cvar_t sv_warsowbunny_topspeed = {CF_SERVER, "sv_warsowbunny_topspeed", "925", "soft speed limit (can get faster with rjs and on ramps)"};
cvar_t sv_warsowbunny_airforwardaccel = {CF_SERVER, "sv_warsowbunny_airforwardaccel", "1.00001", "how fast you accelerate until you reach sv_maxspeed"};
cvar_t sv_warsowbunny_accel = {CF_SERVER, "sv_warsowbunny_accel", "0.1585", "how fast you accelerate until after reaching sv_maxspeed (it gets harder as you near sv_warsowbunny_topspeed)"};
cvar_t sv_warsowbunny_topspeed = {CF_SERVER, "sv_warsowbunny_topspeed", "925", "soft speed limit (can get faster with rjs and on ramps)"};
cvar_t sv_mapformat_is_quake2 = {CF_SERVER, "sv_mapformat_is_quake2", "0", "indicates the current map is q2bsp format (useful to know because of different entity behaviors, .frame on submodels and other things)"};
cvar_t sv_mapformat_is_quake3 = {CF_SERVER, "sv_mapformat_is_quake3", "0", "indicates the current map is q2bsp format (useful to know because of different entity behaviors)"};
cvar_t sv_mapformat_is_quake2 = {CF_SERVER, "sv_mapformat_is_quake2", "0", "indicates the current map is q2bsp format (useful to know because of different entity behaviors, .frame on submodels and other things)"};
cvar_t sv_mapformat_is_quake3 = {CF_SERVER, "sv_mapformat_is_quake3", "0", "indicates the current map is q2bsp format (useful to know because of different entity behaviors)"};
-static qbool SV_CanSave(void)
-{
- prvm_prog_t *prog = SVVM_prog;
- if(SV_IsLocalServer() == 1)
- {
- // singleplayer checks
- if ((svs.clients[0].active && PRVM_serveredictfloat(svs.clients[0].edict, deadflag)))
- {
- Con_Print("Can't savegame with a dead player\n");
- return false;
- }
-
- if(host.hook.CL_Intermission && host.hook.CL_Intermission())
- {
- Con_Print("Can't save in intermission.\n");
- return false;
- }
- }
- else
- Con_Print(CON_WARN "Warning: saving a multiplayer game may have strange results when restored (to properly resume, all players must join in the same player slots and then the game can be reloaded).\n");
- return true;
-
-}
-
Cvar_RegisterVariable (&pr_checkextension);
Cvar_RegisterVariable (&samelevel);
Cvar_RegisterVariable (&skill);
Cvar_RegisterVariable (&pr_checkextension);
Cvar_RegisterVariable (&samelevel);
Cvar_RegisterVariable (&skill);
Cvar_RegisterVariable (&host_timescale);
Cvar_RegisterCallback (&host_timescale, Host_Timescale_c);
Cvar_RegisterVariable (&host_timescale);
Cvar_RegisterCallback (&host_timescale, Host_Timescale_c);
- Cvar_RegisterAlias (&host_timescale, "slowmo");
- Cvar_RegisterAlias (&host_timescale, "timescale");
+ Cvar_RegisterVirtual (&host_timescale, "slowmo");
+ Cvar_RegisterVirtual (&host_timescale, "timescale");
Cvar_RegisterVariable (&sv_accelerate);
Cvar_RegisterVariable (&sv_aim);
Cvar_RegisterVariable (&sv_airaccel_qw);
Cvar_RegisterVariable (&sv_accelerate);
Cvar_RegisterVariable (&sv_aim);
Cvar_RegisterVariable (&sv_airaccel_qw);
Cvar_RegisterVariable (&sv_protocolname);
Cvar_RegisterVariable (&sv_random_seed);
Cvar_RegisterVariable (&host_limitlocal);
Cvar_RegisterVariable (&sv_protocolname);
Cvar_RegisterVariable (&sv_random_seed);
Cvar_RegisterVariable (&host_limitlocal);
Cvar_RegisterVariable (&sv_sound_land);
Cvar_RegisterVariable (&sv_sound_watersplash);
Cvar_RegisterVariable (&sv_stepheight);
Cvar_RegisterVariable (&sv_sound_land);
Cvar_RegisterVariable (&sv_sound_watersplash);
Cvar_RegisterVariable (&sv_stepheight);
client->movesequence = 0;
client->movement_highestsequence_seen = 0;
memset(&client->movement_count, 0, sizeof(client->movement_count));
client->movesequence = 0;
client->movement_highestsequence_seen = 0;
memset(&client->movement_count, 0, sizeof(client->movement_count));
- Con_Printf("Client \"%s\" dropped\n", host_client->name);
+
+ va_list argptr;
+ char reason[512] = "";
+
+ Con_Printf("Client \"%s\" dropped", host_client->name);
+
+ if(fmt)
+ {
+ va_start(argptr, fmt);
+ dpvsnprintf(reason, sizeof(reason), fmt, argptr);
+ va_end(argptr);
+
+ Con_Printf(" (%s)\n", reason);
+ }
+ else
+ {
+ Con_Printf(" \n");
+ }
sizebuf_t buf;
memset(&buf, 0, sizeof(buf));
buf.data = bufdata;
buf.maxsize = sizeof(bufdata);
MSG_WriteByte(&buf, svc_disconnect);
sizebuf_t buf;
memset(&buf, 0, sizeof(buf));
buf.data = bufdata;
buf.maxsize = sizeof(bufdata);
MSG_WriteByte(&buf, svc_disconnect);
NetConn_SendUnreliableMessage(host_client->netconnection, &buf, sv.protocol, 10000, 0, false);
NetConn_SendUnreliableMessage(host_client->netconnection, &buf, sv.protocol, 10000, 0, false);
NetConn_SendUnreliableMessage(host_client->netconnection, &buf, sv.protocol, 10000, 0, false);
NetConn_SendUnreliableMessage(host_client->netconnection, &buf, sv.protocol, 10000, 0, false);
NetConn_SendUnreliableMessage(host_client->netconnection, &buf, sv.protocol, 10000, 0, false);
NetConn_SendUnreliableMessage(host_client->netconnection, &buf, sv.protocol, 10000, 0, false);
// if a download is active, close it
if (host_client->download_file)
// if a download is active, close it
if (host_client->download_file)
- if (!strcasecmp(extension, "pak") || !strcasecmp(extension, "pk3"))
+ if (!strcasecmp(extension, "pak") || !strcasecmp(extension, "pk3") || !strcasecmp(extension, "dpk"))
{
SV_ClientPrintf("Download rejected: file \"%s\" is an archive\nYou must separately download or purchase the data archives for this game/mod to get this file\n", host_client->download_name);
SV_ClientCommands("\nstopdownload\n");
{
SV_ClientPrintf("Download rejected: file \"%s\" is an archive\nYou must separately download or purchase the data archives for this game/mod to get this file\n", host_client->download_name);
SV_ClientCommands("\nstopdownload\n");
return NULL;
modelindex = (int)PRVM_serveredictfloat(ed, modelindex);
return (modelindex > 0 && modelindex < MAX_MODELS) ? sv.models[modelindex] : NULL;
return NULL;
modelindex = (int)PRVM_serveredictfloat(ed, modelindex);
return (modelindex > 0 && modelindex < MAX_MODELS) ? sv.models[modelindex] : NULL;
// LadyHavoc: always clear state values, whether the entity is in use or not
svent->priv.server->baseline = defaultstate;
// LadyHavoc: always clear state values, whether the entity is in use or not
svent->priv.server->baseline = defaultstate;
- client_t *client;
- for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++)
- {
- if (client->netconnection)
- {
- MSG_WriteByte(&client->netconnection->message, svc_stufftext);
- MSG_WriteString(&client->netconnection->message, "reconnect\n");
- }
- }
+ if (sv.active)
+ {
+ client_t *client;
+ for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++)
+ {
+ if (client->netconnection)
+ {
+ MSG_WriteByte(&client->netconnection->message, svc_stufftext);
+ MSG_WriteString(&client->netconnection->message, "reconnect\n");
+ }
+ }
+ }
+ else
+ {
+ // open server port
+ Cvar_SetValueQuick(&campaign, 0);
+ }
+ else if(!deathmatch.integer)
+ Cvar_SetValueQuick(&campaign, 1);
+ else
+ Cvar_SetValueQuick(&campaign, 0);
// LadyHavoc: it can be useful to have skills outside the range 0-3...
//current_skill = bound(0, (int)(skill.value + 0.5), 3);
//Cvar_SetValue ("skill", (float)current_skill);
// LadyHavoc: it can be useful to have skills outside the range 0-3...
//current_skill = bound(0, (int)(skill.value + 0.5), 3);
//Cvar_SetValue ("skill", (float)current_skill);
// AK possible hack since num_edicts is still 0
ent = PRVM_EDICT_NUM(0);
memset (ent->fields.fp, 0, prog->entityfields * sizeof(prvm_vec_t));
// AK possible hack since num_edicts is still 0
ent = PRVM_EDICT_NUM(0);
memset (ent->fields.fp, 0, prog->entityfields * sizeof(prvm_vec_t));
PRVM_serveredictstring(ent, model) = PRVM_SetEngineString(prog, sv.worldname);
PRVM_serveredictfloat(ent, modelindex) = 1; // world model
PRVM_serveredictfloat(ent, solid) = SOLID_BSP;
PRVM_serveredictstring(ent, model) = PRVM_SetEngineString(prog, sv.worldname);
PRVM_serveredictfloat(ent, modelindex) = 1; // world model
PRVM_serveredictfloat(ent, solid) = SOLID_BSP;
//
memset(&sv, 0, sizeof(sv));
memset(svs.clients, 0, svs.maxclients*sizeof(client_t));
//
memset(&sv, 0, sizeof(sv));
memset(svs.clients, 0, svs.maxclients*sizeof(client_t));
// link every entity except world
for (i = 1, ent = prog->edicts;i < prog->num_edicts;i++, ent++)
// link every entity except world
for (i = 1, ent = prog->edicts;i < prog->num_edicts;i++, ent++)
- if (!ent->priv.server->free && !VectorCompare(PRVM_serveredictvector(ent, absmin), PRVM_serveredictvector(ent, absmax)))
+ if (!ent->free && !VectorCompare(PRVM_serveredictvector(ent, absmin), PRVM_serveredictvector(ent, absmax)))
PRVM_serveredictfloat(ed, solid) = 0;
VM_RemoveEdictSkeleton(prog, ed);
PRVM_serveredictfloat(ed, solid) = 0;
VM_RemoveEdictSkeleton(prog, ed);
World_Physics_RemoveFromEntity(&sv.world, ed);
World_Physics_RemoveJointFromEntity(&sv.world, ed);
World_Physics_RemoveFromEntity(&sv.world, ed);
World_Physics_RemoveJointFromEntity(&sv.world, ed);
// make sure csqc networking is aware of the removed entity
e = PRVM_NUM_FOR_EDICT(ed);
sv.csqcentityversion[e] = 0;
// make sure csqc networking is aware of the removed entity
e = PRVM_NUM_FOR_EDICT(ed);
sv.csqcentityversion[e] = 0;
// never timeout loopback connections
for (i = (host_isclient.integer ? 1 : 0), host_client = &svs.clients[i]; i < svs.maxclients; i++, host_client++)
// never timeout loopback connections
for (i = (host_isclient.integer ? 1 : 0), host_client = &svs.clients[i]; i < svs.maxclients; i++, host_client++)
- {
- Con_Printf("Client \"%s\" connection timed out\n", host_client->name);
- SV_DropClient(false);
- }
- }
+ SV_DropClient(false, "Timed out");
+}
+
+/*
+==================
+SV_TimeReport
+
+Returns a time report string, for example for
+==================
+*/
+const char *SV_TimingReport(char *buf, size_t buflen)
+{
+ return va(buf, buflen, "%.1f%% CPU, %.2f%% lost, offset avg %.1fms, max %.1fms, sdev %.1fms", svs.perf_cpuload * 100, svs.perf_lost * 100, svs.perf_offset_avg * 1000, svs.perf_offset_max * 1000, svs.perf_offset_sdev * 1000);