]> git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - sv_main.c
physics: fix and refactor unsticking
[xonotic/darkplaces.git] / sv_main.c
index fed375eb8bfd2e4da21d116c6757d0c1a1970613..1ba1b34e3a591fe9f40e631fef57d3be63064429 100644 (file)
--- a/sv_main.c
+++ b/sv_main.c
@@ -113,7 +113,7 @@ cvar_t sv_gameplayfix_grenadebouncedownslopes = {CF_SERVER, "sv_gameplayfix_gren
 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)"};
@@ -126,8 +126,8 @@ cvar_t sv_gameplayfix_swiminbmodels = {CF_SERVER, "sv_gameplayfix_swiminbmodels"
 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_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"};
@@ -265,12 +265,11 @@ static const char *standardeffectnames[EFFECT_TOTAL] =
        "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))
 
@@ -1773,6 +1772,21 @@ int SV_IsLocalServer(void)
        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
@@ -1789,21 +1803,26 @@ void SV_SpawnServer (const char *map)
        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();
 
@@ -1816,7 +1835,7 @@ void SV_SpawnServer (const char *map)
        }
 
        if(sv.active)
-               PRVM_Prog_Reset(prog); // calls graceful SVQC shutdown in SVVM_reset_cmd
+               SV_VM_Shutdown(false);
 
        // free q3 shaders so that any newly downloaded shaders will be active
        Mod_FreeQ3Shaders();
@@ -1824,7 +1843,7 @@ void SV_SpawnServer (const char *map)
        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();
@@ -1913,10 +1932,10 @@ void SV_SpawnServer (const char *map)
        sv.active = true;
 
        // set level base name variables for later use
-       dp_strlcpy (sv.name, map, sizeof (sv.name));
        dp_strlcpy(sv.worldname, modelname, sizeof(sv.worldname));
        FS_StripExtension(sv.worldname, sv.worldnamenoextension, sizeof(sv.worldnamenoextension));
-       dp_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);
@@ -1977,7 +1996,7 @@ void SV_SpawnServer (const char *map)
                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
@@ -2000,7 +2019,7 @@ void SV_SpawnServer (const char *map)
        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;
@@ -2103,7 +2122,6 @@ This only happens at the end of a game, not between levels
 */
 void SV_Shutdown(void)
 {
-       prvm_prog_t *prog = SVVM_prog;
        int i;
 
        SV_LockThreadMutex();
@@ -2121,7 +2139,7 @@ void SV_Shutdown(void)
                if (host_client->active)
                        SV_DropClient(false, "Server shutting down"); // server shutdown
 
-       PRVM_Prog_Reset(prog); // calls graceful SVQC shutdown in SVVM_reset_cmd
+       SV_VM_Shutdown(true);
 
        NetConn_CloseServerPorts();
 
@@ -2327,7 +2345,7 @@ static void SV_VM_Setup(void)
        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"