cvar_t sv_gameplayfix_multiplethinksperframe = {CF_SERVER, "sv_gameplayfix_multiplethinksperframe", "1", "allows entities to think more often than the server framerate, primarily useful for very high fire rate weapons"};
cvar_t sv_gameplayfix_noairborncorpse = {CF_SERVER, "sv_gameplayfix_noairborncorpse", "1", "causes entities (corpses, items, etc) sitting ontop of moving entities (players) to fall when the moving entity (player) is no longer supporting them"};
cvar_t sv_gameplayfix_noairborncorpse_allowsuspendeditems = {CF_SERVER, "sv_gameplayfix_noairborncorpse_allowsuspendeditems", "1", "causes entities sitting ontop of objects that are instantaneously remove to float in midair (special hack to allow a common level design trick for floating items)"};
-cvar_t sv_gameplayfix_nudgeoutofsolid = {CF_SERVER, "sv_gameplayfix_nudgeoutofsolid", "1", "attempts to fix physics errors where an object ended up in solid for some reason, supersedes sv_gameplayfix_unstickentities"};
+cvar_t sv_gameplayfix_nudgeoutofsolid = {CF_SERVER, "sv_gameplayfix_nudgeoutofsolid", "0", "attempts to fix physics errors where an object ended up in solid for some reason, better than sv_gameplayfix_unstick* but currently has no effect on Q1BSP (unless mod_q1bsp_polygoncollisions is enabled)"};
cvar_t sv_gameplayfix_nudgeoutofsolid_separation = {CF_SERVER, "sv_gameplayfix_nudgeoutofsolid_separation", "0.03125", "keep objects this distance apart to prevent collision issues on seams"};
cvar_t sv_gameplayfix_q2airaccelerate = {CF_SERVER, "sv_gameplayfix_q2airaccelerate", "0", "Quake2-style air acceleration"};
cvar_t sv_gameplayfix_nogravityonground = {CF_SERVER, "sv_gameplayfix_nogravityonground", "0", "turn off gravity when on ground (to get rid of sliding)"};
cvar_t sv_gameplayfix_upwardvelocityclearsongroundflag = {CF_SERVER, "sv_gameplayfix_upwardvelocityclearsongroundflag", "1", "prevents monsters, items, and most other objects from being stuck to the floor when pushed around by damage, and other situations in mods"};
cvar_t sv_gameplayfix_downtracesupportsongroundflag = {CF_SERVER, "sv_gameplayfix_downtracesupportsongroundflag", "1", "prevents very short moves from clearing onground (which may make the player stick to the floor at high netfps), fixes groundentity not being set when walking onto a mover with sv_gameplayfix_nogravityonground"};
cvar_t sv_gameplayfix_q1bsptracelinereportstexture = {CF_SERVER, "sv_gameplayfix_q1bsptracelinereportstexture", "1", "enables mods to get accurate trace_texture results on q1bsp by using a surface-hitting traceline implementation rather than the standard solidbsp method, q3bsp always reports texture accurately"};
-cvar_t sv_gameplayfix_unstickplayers = {CF_SERVER, "sv_gameplayfix_unstickplayers", "0", "big hack to try and fix the rare case of MOVETYPE_WALK entities getting stuck in the world clipping hull."};
-cvar_t sv_gameplayfix_unstickentities = {CF_SERVER, "sv_gameplayfix_unstickentities", "1", "hack to check if entities are crossing world collision hull and try to move them to the right position, superseded by sv_gameplayfix_nudgeoutofsolid"};
+cvar_t sv_gameplayfix_unstickplayers = {CF_SERVER, "sv_gameplayfix_unstickplayers", "1", "big hack to try and fix the rare case of MOVETYPE_WALK entities getting stuck in the world clipping hull. Quake did something similar."};
+cvar_t sv_gameplayfix_unstickentities = {CF_SERVER, "sv_gameplayfix_unstickentities", "0", "hack to check if entities are crossing world collision hull and try to move them to the right position. Quake didn't do this so maps shouldn't depend on it."};
cvar_t sv_gameplayfix_fixedcheckwatertransition = {CF_SERVER, "sv_gameplayfix_fixedcheckwatertransition", "1", "fix two very stupid bugs in SV_CheckWaterTransition when watertype is CONTENTS_EMPTY (the bugs causes waterlevel to be 1 on first frame, -1 on second frame - the fix makes it 0 on both frames)"};
-cvar_t sv_gameplayfix_customstats = {CF_SERVER, "sv_gameplayfix_customstats", "0", "Disable stats higher than 220, for use by certain games such as Xonotic"};
cvar_t sv_gravity = {CF_SERVER | CF_NOTIFY, "sv_gravity","800", "how fast you fall (512 = roughly earth gravity)"};
cvar_t sv_init_frame_count = {CF_SERVER, "sv_init_frame_count", "2", "number of frames to run to allow everything to settle before letting clients connect"};
cvar_t sv_idealpitchscale = {CF_SERVER, "sv_idealpitchscale","0.8", "how much to look up/down slopes and stairs when not using freelook"};
cvar_t sv_playerphysicsqc = {CF_SERVER | CF_NOTIFY, "sv_playerphysicsqc", "1", "enables QuakeC function to override player physics"};
cvar_t sv_progs = {CF_SERVER, "sv_progs", "progs.dat", "selects which quakec progs.dat file to run" };
cvar_t sv_protocolname = {CF_SERVER, "sv_protocolname", "DP7", "selects network protocol to host for (values include QUAKE, QUAKEDP, NEHAHRAMOVIE, DP1 and up)"};
+cvar_t sv_qcstats = {CF_SERVER, "sv_qcstats", "0", "Disables engine sending of stats 220 and above, for use by certain games such as Xonotic, NOTE: it's strongly recommended that SVQC send correct STAT_MOVEVARS_TICRATE and STAT_MOVEVARS_TIMESCALE"};
cvar_t sv_random_seed = {CF_SERVER, "sv_random_seed", "", "random seed; when set, on every map start this random seed is used to initialize the random number generator. Don't touch it unless for benchmarking or debugging"};
cvar_t host_limitlocal = {CF_SERVER, "host_limitlocal", "0", "whether to apply rate limiting to the local player in a listen server (only useful for testing)"};
cvar_t sv_sound_land = {CF_SERVER, "sv_sound_land", "demon/dland2.wav", "sound to play when MOVETYPE_STEP entity hits the ground at high speed (empty cvar disables the sound)"};
"SVC_PARTICLE"
};
-#define SV_REQFUNCS 0
-#define sv_reqfuncs NULL
-//#define SV_REQFUNCS (sizeof(sv_reqfuncs) / sizeof(const char *))
-//static const char *sv_reqfuncs[] = {
-//};
+static void SV_CheckRequiredFuncs(prvm_prog_t *prog, const char *filename)
+{
+ // no required funcs?!
+}
#define SV_REQFIELDS (sizeof(sv_reqfields) / sizeof(prvm_required_field_t))
Cvar_RegisterVariable (&sv_gameplayfix_unstickplayers);
Cvar_RegisterVariable (&sv_gameplayfix_unstickentities);
Cvar_RegisterVariable (&sv_gameplayfix_fixedcheckwatertransition);
- Cvar_RegisterVariable (&sv_gameplayfix_customstats);
+ Cvar_RegisterVariable (&sv_qcstats);
Cvar_RegisterVariable (&sv_gravity);
Cvar_RegisterVariable (&sv_init_frame_count);
Cvar_RegisterVariable (&sv_idealpitchscale);
SZ_Clear (&client->netconnection->message);
MSG_WriteByte (&client->netconnection->message, svc_print);
- dpsnprintf (message, sizeof (message), "\nServer: %s build %s (progs %i crc)\n", gamename, buildstring, prog->filecrc);
+ dpsnprintf (message, sizeof (message), "\nServer: %s (progs %i crc)\n", engineversion, prog->filecrc);
MSG_WriteString (&client->netconnection->message,message);
SV_StopDemoRecording(client); // to split up demos into different files
);
}
- strlcpy(client->name, "unconnected", sizeof(client->name));
- strlcpy(client->old_name, "unconnected", sizeof(client->old_name));
+ dp_strlcpy(client->name, "unconnected", sizeof(client->name));
+ dp_strlcpy(client->old_name, "unconnected", sizeof(client->old_name));
client->prespawned = false;
client->spawned = false;
client->begun = false;
Download_CheckExtensions(cmd);
- strlcpy(host_client->download_name, Cmd_Argv(cmd, 1), sizeof(host_client->download_name));
+ dp_strlcpy(host_client->download_name, Cmd_Argv(cmd, 1), sizeof(host_client->download_name));
extension = FS_FileExtension(host_client->download_name);
// host_client is asking to download a specified file
extensions[0] = '\0';
if(host_client->download_deflate)
- strlcat(extensions, " deflate", sizeof(extensions));
+ dp_strlcat(extensions, " deflate", sizeof(extensions));
Con_DPrintf("Downloading %s to %s\n", host_client->download_name, host_client->name);
// testing
//if (precachemode == 2)
// return 0;
- strlcpy(filename, s, sizeof(filename));
+ dp_strlcpy(filename, s, sizeof(filename));
for (i = 2;i < limit;i++)
{
if (!sv.model_precache[i][0])
}
if (precachemode == 1)
Con_Printf("SV_ModelIndex(\"%s\"): not precached (fix your code), precaching anyway\n", filename);
- strlcpy(sv.model_precache[i], filename, sizeof(sv.model_precache[i]));
+ dp_strlcpy(sv.model_precache[i], filename, sizeof(sv.model_precache[i]));
if (sv.state == ss_loading)
{
// running from SV_SpawnServer which is launched from the client console command interpreter
// testing
//if (precachemode == 2)
// return 0;
- strlcpy(filename, s, sizeof(filename));
+ dp_strlcpy(filename, s, sizeof(filename));
for (i = 1;i < limit;i++)
{
if (!sv.sound_precache[i][0])
}
if (precachemode == 1)
Con_Printf("SV_SoundIndex(\"%s\"): not precached (fix your code), precaching anyway\n", filename);
- strlcpy(sv.sound_precache[i], filename, sizeof(sv.sound_precache[i]));
+ dp_strlcpy(sv.sound_precache[i], filename, sizeof(sv.sound_precache[i]));
if (sv.state != ss_loading)
{
MSG_WriteByte(&sv.reliable_datagram, svc_precache);
sv.particleeffectnamesloaded = true;
memset(sv.particleeffectname, 0, sizeof(sv.particleeffectname));
for (i = 0;i < EFFECT_TOTAL;i++)
- strlcpy(sv.particleeffectname[i], standardeffectnames[i], sizeof(sv.particleeffectname[i]));
+ dp_strlcpy(sv.particleeffectname[i], standardeffectnames[i], sizeof(sv.particleeffectname[i]));
for (filepass = 0;;filepass++)
{
if (filepass == 0)
break;
if (argc < 16)
{
- strlcpy(argv[argc], com_token, sizeof(argv[argc]));
+ dp_strlcpy(argv[argc], com_token, sizeof(argv[argc]));
argc++;
}
}
}
else
{
- strlcpy(sv.particleeffectname[effectnameindex], argv[1], sizeof(sv.particleeffectname[effectnameindex]));
+ dp_strlcpy(sv.particleeffectname[effectnameindex], argv[1], sizeof(sv.particleeffectname[effectnameindex]));
break;
}
}
sv.csqc_progsize = (int)progsize;
sv.csqc_progcrc = CRC_Block(svs.csqc_progdata, progsize);
- strlcpy(sv.csqc_progname, csqc_progname.string, sizeof(sv.csqc_progname));
+ dp_strlcpy(sv.csqc_progname, csqc_progname.string, sizeof(sv.csqc_progname));
Con_DPrintf("server detected csqc progs file \"%s\" with size %i and crc %i\n", sv.csqc_progname, sv.csqc_progsize, sv.csqc_progcrc);
Con_DPrint("Compressing csprogs.dat\n");
return (host_isclient.integer && sv.active ? svs.maxclients : 0);
}
+static void SV_VM_Shutdown(qbool prog_reset)
+{
+ prvm_prog_t *prog = SVVM_prog;
+
+ if(prog->loaded && PRVM_serverfunction(SV_Shutdown))
+ {
+ func_t s = PRVM_serverfunction(SV_Shutdown);
+ PRVM_serverglobalfloat(time) = sv.time;
+ PRVM_serverfunction(SV_Shutdown) = 0; // prevent it from getting called again
+ prog->ExecuteProgram(prog, s,"SV_Shutdown() required");
+ }
+ if (prog_reset)
+ PRVM_Prog_Reset(prog);
+}
+
/*
================
SV_SpawnServer
char *entities;
model_t *worldmodel;
char modelname[sizeof(sv.worldname)];
+ const char *canonicalname;
char vabuf[1024];
Con_Printf("SpawnServer: %s\n", map);
dpsnprintf (modelname, sizeof(modelname), "maps/%s.bsp", map);
- if (!FS_FileExists(modelname))
+ if (!(canonicalname = FS_FileExists(modelname)))
{
dpsnprintf (modelname, sizeof(modelname), "maps/%s", map);
- if (!FS_FileExists(modelname))
+ if (!(canonicalname = FS_FileExists(modelname)))
{
- Con_Printf("SpawnServer: no map file named %s\n", modelname);
+ Con_Printf(CON_ERROR "SpawnServer: no map file named %s.bsp\n", modelname);
return;
}
}
+ // if it's not in a pak canonicalname will be the same pointer as modelname
+ // if it's in a pak canonicalname may differ by case
+ if (modelname != canonicalname)
+ dp_strlcpy(modelname, canonicalname, sizeof(modelname));
// SV_LockThreadMutex();
}
if(sv.active)
- {
- World_End(&sv.world);
- if(PRVM_serverfunction(SV_Shutdown))
- {
- func_t s = PRVM_serverfunction(SV_Shutdown);
- PRVM_serverglobalfloat(time) = sv.time;
- PRVM_serverfunction(SV_Shutdown) = 0; // prevent it from getting called again
- prog->ExecuteProgram(prog, s,"SV_Shutdown() required");
- }
- }
+ SV_VM_Shutdown(false);
// free q3 shaders so that any newly downloaded shaders will be active
Mod_FreeQ3Shaders();
worldmodel = Mod_ForName(modelname, false, developer.integer > 0, NULL);
if (!worldmodel || !worldmodel->TraceBox)
{
- Con_Printf("Couldn't load map %s\n", modelname);
+ Con_Printf(CON_ERROR "Couldn't load map %s\n", modelname);
if(!host_isclient.integer)
Sys_MakeProcessMean();
sv.active = true;
// set level base name variables for later use
- strlcpy (sv.name, map, sizeof (sv.name));
- strlcpy(sv.worldname, modelname, sizeof(sv.worldname));
+ dp_strlcpy(sv.worldname, modelname, sizeof(sv.worldname));
FS_StripExtension(sv.worldname, sv.worldnamenoextension, sizeof(sv.worldnamenoextension));
- strlcpy(sv.worldbasename, !strncmp(sv.worldnamenoextension, "maps/", 5) ? sv.worldnamenoextension + 5 : sv.worldnamenoextension, sizeof(sv.worldbasename));
+ dp_strlcpy(sv.worldbasename, !strncasecmp(sv.worldnamenoextension, "maps/", 5) ? sv.worldnamenoextension + 5 : sv.worldnamenoextension, sizeof(sv.worldbasename));
+// dp_strlcpy(sv.name, sv.worldbasename, sizeof (sv.name)); // TODO can we just remove this now?
//Cvar_SetQuick(&sv_worldmessage, sv.worldmessage); // set later after QC is spawned
Cvar_SetQuick(&sv_worldname, sv.worldname);
Cvar_SetQuick(&sv_worldnamenoextension, sv.worldnamenoextension);
World_SetSize(&sv.world, sv.worldname, sv.worldmodel->normalmins, sv.worldmodel->normalmaxs, prog);
World_Start(&sv.world);
- strlcpy(sv.sound_precache[0], "", sizeof(sv.sound_precache[0]));
+ dp_strlcpy(sv.sound_precache[0], "", sizeof(sv.sound_precache[0]));
- strlcpy(sv.model_precache[0], "", sizeof(sv.model_precache[0]));
- strlcpy(sv.model_precache[1], sv.worldname, sizeof(sv.model_precache[1]));
+ dp_strlcpy(sv.model_precache[0], "", sizeof(sv.model_precache[0]));
+ dp_strlcpy(sv.model_precache[1], sv.worldname, sizeof(sv.model_precache[1]));
for (i = 1;i < sv.worldmodel->brush.numsubmodels && i+1 < MAX_MODELS;i++)
{
dpsnprintf(sv.model_precache[i+1], sizeof(sv.model_precache[i+1]), "*%i", i);
sv.models[i+1] = Mod_ForName (sv.model_precache[i+1], false, false, sv.worldname);
}
if(i < sv.worldmodel->brush.numsubmodels)
- Con_Printf("Too many submodels (MAX_MODELS is %i)\n", MAX_MODELS);
+ Con_Printf(CON_WARN "Too many submodels (MAX_MODELS is %i)\n", MAX_MODELS);
//
// load the rest of the entities
else
PRVM_serverglobalfloat(deathmatch) = deathmatch.integer;
- PRVM_serverglobalstring(mapname) = PRVM_SetEngineString(prog, sv.name);
+ PRVM_serverglobalstring(mapname) = PRVM_SetEngineString(prog, sv.worldbasename);
// serverflags are for cross level information (sigils)
PRVM_serverglobalfloat(serverflags) = svs.serverflags;
}
}
- // update the map title cvar
- strlcpy(sv.worldmessage, PRVM_GetString(prog, PRVM_serveredictstring(prog->edicts, message)), sizeof(sv.worldmessage)); // map title (not related to filename)
- Cvar_SetQuick(&sv_worldmessage, sv.worldmessage);
+ // update the map title cvar (not related to filename)
+ Cvar_SetQuick(&sv_worldmessage, PRVM_GetString(prog, PRVM_serveredictstring(prog->edicts, message)));
Con_Printf("Server spawned.\n");
NetConn_Heartbeat (2);
*/
void SV_Shutdown(void)
{
- prvm_prog_t *prog = SVVM_prog;
int i;
SV_LockThreadMutex();
NetConn_Heartbeat(2);
NetConn_Heartbeat(2);
-// make sure all the clients know we're disconnecting
- World_End(&sv.world);
- if(prog->loaded)
- {
- if(PRVM_serverfunction(SV_Shutdown))
- {
- func_t s = PRVM_serverfunction(SV_Shutdown);
- PRVM_serverglobalfloat(time) = sv.time;
- PRVM_serverfunction(SV_Shutdown) = 0; // prevent it from getting called again
- prog->ExecuteProgram(prog, s,"SV_Shutdown() required");
- }
- }
+ // make sure all the clients know we're disconnecting
for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
if (host_client->active)
SV_DropClient(false, "Server shutting down"); // server shutdown
+ SV_VM_Shutdown(true);
+
NetConn_CloseServerPorts();
sv.active = false;
prog->error_cmd = Host_Error;
prog->ExecuteProgram = SVVM_ExecuteProgram;
- PRVM_Prog_Load(prog, sv_progs.string, NULL, 0, SV_REQFUNCS, sv_reqfuncs, SV_REQFIELDS, sv_reqfields, SV_REQGLOBALS, sv_reqglobals);
+ PRVM_Prog_Load(prog, sv_progs.string, NULL, 0, SV_CheckRequiredFuncs, SV_REQFIELDS, sv_reqfields, SV_REQGLOBALS, sv_reqglobals);
// some mods compiled with scrambling compilers lack certain critical
// global names and field names such as "self" and "time" and "nextthink"
return va(buf, buflen, "%.1f%% CPU, %.2f%% lost, offset avg %.1fms, max %.1fms, sdev %.1fms", sv.perf_cpuload * 100, sv.perf_lost * 100, sv.perf_offset_avg * 1000, sv.perf_offset_max * 1000, sv.perf_offset_sdev * 1000);
}
-extern cvar_t host_maxwait;
extern cvar_t host_framerate;
double SV_Frame(double time)
{
qbool playing = false;
double sv_timer = 0;
double sv_deltarealtime, sv_oldrealtime, sv_realtime;
- double wait;
int i;
char vabuf[1024];
sv_realtime = Sys_DirtyTime();
}
// if the accumulators haven't become positive yet, wait a while
- wait = sv_timer * -1000000.0;
- if (wait >= 1)
+ if (sv_timer < 0)
{
- double time0, delta;
SV_UnlockThreadMutex(); // don't keep mutex locked while sleeping
- if (host_maxwait.value <= 0)
- wait = min(wait, 1000000.0);
- else
- wait = min(wait, host_maxwait.value * 1000.0);
- if(wait < 1)
- wait = 1; // because we cast to int
- time0 = Sys_DirtyTime();
- Sys_Sleep((int)wait);
- delta = Sys_DirtyTime() - time0;if (delta < 0 || delta >= 1800) delta = 0;
- sv.perf_acc_sleeptime += delta;
+ sv.perf_acc_sleeptime += Sys_Sleep(-sv_timer);
continue;
}