]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - sv_phys.c
final speedhack fixes
[xonotic/darkplaces.git] / sv_phys.c
index 6c2d933b6660540ac84a916dc09a8abb2ccea8bb..362689f8795fa954e69421a4e8c524e75bf331e5 100644 (file)
--- a/sv_phys.c
+++ b/sv_phys.c
@@ -39,44 +39,10 @@ solid_edge items only clip against bsp models.
 
 */
 
-cvar_t sv_friction = {CVAR_NOTIFY, "sv_friction","4", "how fast you slow down"};
-cvar_t sv_waterfriction = {CVAR_NOTIFY, "sv_waterfriction","-1", "how fast you slow down, if less than 0 the sv_friction variable is used instead"};
-cvar_t sv_stopspeed = {CVAR_NOTIFY, "sv_stopspeed","100", "how fast you come to a complete stop"};
-cvar_t sv_gravity = {CVAR_NOTIFY, "sv_gravity","800", "how fast you fall (512 = roughly earth gravity)"};
-cvar_t sv_maxvelocity = {CVAR_NOTIFY, "sv_maxvelocity","2000", "universal speed limit on all entities"};
-cvar_t sv_nostep = {CVAR_NOTIFY, "sv_nostep","0", "prevents MOVETYPE_STEP entities (monsters) from moving"};
-cvar_t sv_stepheight = {CVAR_NOTIFY, "sv_stepheight", "18", "how high you can step up (TW_SV_STEPCONTROL extension)"};
-cvar_t sv_jumpstep = {CVAR_NOTIFY, "sv_jumpstep", "0", "whether you can step up while jumping (sv_gameplayfix_stepwhilejumping must also be 1)"};
-cvar_t sv_wallfriction = {CVAR_NOTIFY, "sv_wallfriction", "1", "how much you slow down when sliding along a wall"};
-cvar_t sv_newflymove = {CVAR_NOTIFY, "sv_newflymove", "0", "enables simpler/buggier player physics (not recommended)"};
-cvar_t sv_freezenonclients = {CVAR_NOTIFY, "sv_freezenonclients", "0", "freezes time, except for players, allowing you to walk around and take screenshots of explosions"};
-cvar_t sv_playerphysicsqc = {CVAR_NOTIFY, "sv_playerphysicsqc", "1", "enables QuakeC function to override player physics"};
-cvar_t sv_debugmove = {CVAR_NOTIFY, "sv_debugmove", "0", "disables collision detection optimizations for debugging purposes"};
-
-cvar_t sv_sound_watersplash = {0, "sv_sound_watersplash", "misc/h2ohit1.wav", "sound to play when MOVETYPE_FLY/TOSS/BOUNCE/STEP entity enters or leaves water (empty cvar disables the sound)"};
-cvar_t sv_sound_land = {0, "sv_sound_land", "demon/dland2.wav", "sound to play when MOVETYPE_STEP entity hits the ground at high speed (empty cvar disables the sound)"};
-
-// TODO: move this extern to server.h
-extern cvar_t sv_clmovement_waitforinput;
-
 #define        MOVE_EPSILON    0.01
 
 void SV_Physics_Toss (prvm_edict_t *ent);
 
-void SV_Phys_Init (void)
-{
-       Cvar_RegisterVariable(&sv_stepheight);
-       Cvar_RegisterVariable(&sv_jumpstep);
-       Cvar_RegisterVariable(&sv_wallfriction);
-       Cvar_RegisterVariable(&sv_newflymove);
-       Cvar_RegisterVariable(&sv_freezenonclients);
-       Cvar_RegisterVariable(&sv_playerphysicsqc);
-       Cvar_RegisterVariable(&sv_debugmove);
-
-       Cvar_RegisterVariable(&sv_sound_watersplash);
-       Cvar_RegisterVariable(&sv_sound_land);
-}
-
 /*
 ===============================================================================
 
@@ -146,9 +112,6 @@ trace_t SV_Move(const vec3_t start, const vec3_t mins, const vec3_t maxs, const
        int numtouchedicts;
        prvm_edict_t *touchedicts[MAX_EDICTS];
 
-       // Get Allow Touch with Owner
-       int nAllowTouchWithOwner = PRVM_EDICTFIELDVALUE(passedict, prog->fieldoffsets.allowtouchwithowner)->_int;
-
        VectorCopy(start, clipstart);
        VectorCopy(end, clipend);
        VectorCopy(mins, clipmins);
@@ -235,10 +198,10 @@ trace_t SV_Move(const vec3_t start, const vec3_t mins, const vec3_t maxs, const
                        if (passedict == touch)
                                continue;
                        // don't clip owned entities against owner
-                       if (!nAllowTouchWithOwner && traceowner == touch)
+                       if (traceowner == touch)
                                continue;
                        // don't clip owner against owned entities
-                       if (!nAllowTouchWithOwner && passedictprog == touch->fields.server->owner)
+                       if (passedictprog == touch->fields.server->owner)
                                continue;
                        // don't clip points against points (they can't collide)
                        if (pointtrace && VectorCompare(touch->fields.server->mins, touch->fields.server->maxs) && (type != MOVE_MISSILE || !((int)touch->fields.server->flags & FL_MONSTER)))
@@ -306,7 +269,7 @@ void SV_LinkEdict_TouchAreaGrid(prvm_edict_t *ent)
        prvm_edict_t *touch, *touchedicts[MAX_EDICTS];
 
        // build a list of edicts to touch, because the link loop can be corrupted
-       // by SV_IncreaseEdicts called during touch functions
+       // by IncreaseEdicts called during touch functions
        numtouchedicts = World_EntitiesInBox(&sv.world, ent->priv.server->areamins, ent->priv.server->areamaxs, MAX_EDICTS, touchedicts);
        if (numtouchedicts > MAX_EDICTS)
        {
@@ -380,7 +343,7 @@ void SV_LinkEdict (prvm_edict_t *ent, qboolean touch_triggers)
                model = sv.models[modelindex];
                if (model != NULL)
                {
-                       if (!model->TraceBox)
+                       if (!model->TraceBox && developer.integer >= 1)
                                Con_Printf("edict %i: SOLID_BSP with non-collidable model\n", PRVM_NUM_FOR_EDICT(ent));
 
                        if (ent->fields.server->angles[0] || ent->fields.server->angles[2] || ent->fields.server->avelocity[0] || ent->fields.server->avelocity[2])
@@ -560,6 +523,8 @@ int SV_CheckContentsTransition(prvm_edict_t *ent, const int nContents)
                                PRVM_G_FLOAT(OFS_PARM0) = ent->fields.server->watertype;
                                // New Contents
                                PRVM_G_FLOAT(OFS_PARM1) = nContents;
+                               // Assign Self
+                               prog->globals.server->self = PRVM_EDICT_TO_PROG(ent);
                        // Execute VM Function
                        PRVM_ExecuteProgram(contentstransition->function, "contentstransition: NULL function");
                }
@@ -620,22 +585,27 @@ Returns false if the entity removed itself.
 */
 qboolean SV_RunThink (prvm_edict_t *ent)
 {
-       float thinktime;
-
-       thinktime = ent->fields.server->nextthink;
-       if (thinktime <= 0 || thinktime > sv.time + sv.frametime)
-               return true;
+       int iterations;
 
        // don't let things stay in the past.
        // it is possible to start that way by a trigger with a local time.
-       if (thinktime < sv.time)
-               thinktime = sv.time;
+       if (ent->fields.server->nextthink <= 0 || ent->fields.server->nextthink > sv.time + sv.frametime)
+               return true;
 
-       ent->fields.server->nextthink = 0;
-       prog->globals.server->time = thinktime;
-       prog->globals.server->self = PRVM_EDICT_TO_PROG(ent);
-       prog->globals.server->other = PRVM_EDICT_TO_PROG(prog->edicts);
-       PRVM_ExecuteProgram (ent->fields.server->think, "QC function self.think is missing");
+       for (iterations = 0;iterations < 128  && !ent->priv.server->free;iterations++)
+       {
+               prog->globals.server->time = max(sv.time, ent->fields.server->nextthink);
+               ent->fields.server->nextthink = 0;
+               prog->globals.server->self = PRVM_EDICT_TO_PROG(ent);
+               prog->globals.server->other = PRVM_EDICT_TO_PROG(prog->edicts);
+               PRVM_ExecuteProgram (ent->fields.server->think, "QC function self.think is missing");
+               // mods often set nextthink to time to cause a think every frame,
+               // we don't want to loop in that case, so exit if the new nextthink is
+               // <= the time the qc was told, also exit if it is past the end of the
+               // frame
+               if (ent->fields.server->nextthink <= prog->globals.server->time || ent->fields.server->nextthink > sv.time + sv.frametime || !sv_gameplayfix_multiplethinksperframe.integer)
+                       break;
+       }
        return !ent->priv.server->free;
 }
 
@@ -647,14 +617,17 @@ Two entities have touched, so run their touch functions
 ==================
 */
 extern void VM_SetTraceGlobals(const trace_t *trace);
+extern sizebuf_t vm_tempstringsbuf;
 void SV_Impact (prvm_edict_t *e1, trace_t *trace)
 {
+       int restorevm_tempstringsbuf_cursize;
        int old_self, old_other;
        prvm_edict_t *e2 = (prvm_edict_t *)trace->ent;
        prvm_eval_t *val;
 
        old_self = prog->globals.server->self;
        old_other = prog->globals.server->other;
+       restorevm_tempstringsbuf_cursize = vm_tempstringsbuf.cursize;
 
        VM_SetTraceGlobals(trace);
 
@@ -687,6 +660,7 @@ void SV_Impact (prvm_edict_t *e1, trace_t *trace)
 
        prog->globals.server->self = old_self;
        prog->globals.server->other = old_other;
+       vm_tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize;
 }
 
 
@@ -1032,6 +1006,7 @@ void SV_PushMove (prvm_edict_t *pusher, float movetime)
        model_t *pushermodel;
        trace_t trace;
        matrix4x4_t pusherfinalmatrix, pusherfinalimatrix;
+       unsigned short moved_edicts[MAX_EDICTS];
 
        if (!pusher->fields.server->velocity[0] && !pusher->fields.server->velocity[1] && !pusher->fields.server->velocity[2] && !pusher->fields.server->avelocity[0] && !pusher->fields.server->avelocity[1] && !pusher->fields.server->avelocity[2])
        {
@@ -1151,6 +1126,7 @@ void SV_PushMove (prvm_edict_t *pusher, float movetime)
        for (e = 0;e < numcheckentities;e++)
        {
                prvm_edict_t *check = checkentities[e];
+               int checkcontents = SV_GenericHitSuperContentsMask(check);
                if (check->fields.server->movetype == MOVETYPE_NONE
                 || check->fields.server->movetype == MOVETYPE_PUSH
                 || check->fields.server->movetype == MOVETYPE_FOLLOW
@@ -1163,7 +1139,7 @@ void SV_PushMove (prvm_edict_t *pusher, float movetime)
                // final position, move it
                if (!((int)check->fields.server->flags & FL_ONGROUND) || PRVM_PROG_TO_EDICT(check->fields.server->groundentity) != pusher)
                {
-                       Collision_ClipToGenericEntity(&trace, pushermodel, pusher->fields.server->frame, pusher->fields.server->mins, pusher->fields.server->maxs, SUPERCONTENTS_BODY, &pusherfinalmatrix, &pusherfinalimatrix, check->fields.server->origin, check->fields.server->mins, check->fields.server->maxs, check->fields.server->origin, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY);
+                       Collision_ClipToGenericEntity(&trace, pushermodel, pusher->fields.server->frame, pusher->fields.server->mins, pusher->fields.server->maxs, SUPERCONTENTS_BODY, &pusherfinalmatrix, &pusherfinalimatrix, check->fields.server->origin, check->fields.server->mins, check->fields.server->maxs, check->fields.server->origin, checkcontents);
                        if (!trace.startsolid)
                                continue;
                }
@@ -1184,7 +1160,7 @@ void SV_PushMove (prvm_edict_t *pusher, float movetime)
 
                VectorCopy (check->fields.server->origin, check->priv.server->moved_from);
                VectorCopy (check->fields.server->angles, check->priv.server->moved_fromangles);
-               sv.moved_edicts[num_moved++] = check;
+               moved_edicts[num_moved++] = PRVM_NUM_FOR_EDICT(check);
 
                // try moving the contacted entity
                pusher->fields.server->solid = SOLID_NOT;
@@ -1201,7 +1177,7 @@ void SV_PushMove (prvm_edict_t *pusher, float movetime)
                        check->fields.server->flags = (int)check->fields.server->flags & ~FL_ONGROUND;
 
                // if it is still inside the pusher, block
-               Collision_ClipToGenericEntity(&trace, pushermodel, pusher->fields.server->frame, pusher->fields.server->mins, pusher->fields.server->maxs, SUPERCONTENTS_BODY, &pusherfinalmatrix, &pusherfinalimatrix, check->fields.server->origin, check->fields.server->mins, check->fields.server->maxs, check->fields.server->origin, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY);
+               Collision_ClipToGenericEntity(&trace, pushermodel, pusher->fields.server->frame, pusher->fields.server->mins, pusher->fields.server->maxs, SUPERCONTENTS_BODY, &pusherfinalmatrix, &pusherfinalimatrix, check->fields.server->origin, check->fields.server->mins, check->fields.server->maxs, check->fields.server->origin, checkcontents);
                if (trace.startsolid)
                {
                        // try moving the contacted entity a tiny bit further to account for precision errors
@@ -1212,7 +1188,7 @@ void SV_PushMove (prvm_edict_t *pusher, float movetime)
                        VectorCopy (check->priv.server->moved_fromangles, check->fields.server->angles);
                        SV_PushEntity (check, move2, true);
                        pusher->fields.server->solid = savesolid;
-                       Collision_ClipToGenericEntity(&trace, pushermodel, pusher->fields.server->frame, pusher->fields.server->mins, pusher->fields.server->maxs, SUPERCONTENTS_BODY, &pusherfinalmatrix, &pusherfinalimatrix, check->fields.server->origin, check->fields.server->mins, check->fields.server->maxs, check->fields.server->origin, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY);
+                       Collision_ClipToGenericEntity(&trace, pushermodel, pusher->fields.server->frame, pusher->fields.server->mins, pusher->fields.server->maxs, SUPERCONTENTS_BODY, &pusherfinalmatrix, &pusherfinalimatrix, check->fields.server->origin, check->fields.server->mins, check->fields.server->maxs, check->fields.server->origin, checkcontents);
                        if (trace.startsolid)
                        {
                                // try moving the contacted entity a tiny bit less to account for precision errors
@@ -1222,7 +1198,7 @@ void SV_PushMove (prvm_edict_t *pusher, float movetime)
                                VectorCopy (check->priv.server->moved_fromangles, check->fields.server->angles);
                                SV_PushEntity (check, move2, true);
                                pusher->fields.server->solid = savesolid;
-                               Collision_ClipToGenericEntity(&trace, pushermodel, pusher->fields.server->frame, pusher->fields.server->mins, pusher->fields.server->maxs, SUPERCONTENTS_BODY, &pusherfinalmatrix, &pusherfinalimatrix, check->fields.server->origin, check->fields.server->mins, check->fields.server->maxs, check->fields.server->origin, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY);
+                               Collision_ClipToGenericEntity(&trace, pushermodel, pusher->fields.server->frame, pusher->fields.server->mins, pusher->fields.server->maxs, SUPERCONTENTS_BODY, &pusherfinalmatrix, &pusherfinalimatrix, check->fields.server->origin, check->fields.server->mins, check->fields.server->maxs, check->fields.server->origin, checkcontents);
                                if (trace.startsolid)
                                {
                                        // still inside pusher, so it's really blocked
@@ -1246,7 +1222,7 @@ void SV_PushMove (prvm_edict_t *pusher, float movetime)
                                        // move back any entities we already moved
                                        for (i = 0;i < num_moved;i++)
                                        {
-                                               prvm_edict_t *ed = sv.moved_edicts[i];
+                                               prvm_edict_t *ed = PRVM_EDICT_NUM(moved_edicts[i]);
                                                VectorCopy (ed->priv.server->moved_from, ed->fields.server->origin);
                                                VectorCopy (ed->priv.server->moved_fromangles, ed->fields.server->angles);
                                                SV_LinkEdict (ed, false);
@@ -2014,7 +1990,7 @@ static void SV_Physics_Entity (prvm_edict_t *ent)
        case MOVETYPE_FLYMISSILE:
        case MOVETYPE_FLY:
                // regular thinking
-               if (SV_RunThink (ent) && runmove)
+               if (SV_RunThink (ent) && (runmove || !sv_gameplayfix_delayprojectiles.integer))
                        SV_Physics_Toss (ent);
                break;
        default:
@@ -2139,6 +2115,7 @@ void SV_Physics_ClientEntity(prvm_edict_t *ent)
                                SV_AddGravity (ent);
                        SV_CheckStuck (ent);
                        SV_WalkMove (ent);
+                       host_client->cmd.time = max(host_client->cmd.time, sv.time); // ignore client movement data for anything before NOW
                }
                break;
        case MOVETYPE_TOSS: