X-Git-Url: http://git.xonotic.org/?a=blobdiff_plain;f=sv_phys.c;h=24b17ef7bd77dfe0423eec84a8967acbb3f0fbc8;hb=49ff21dc9c098ef705535f6d5bc9f67cdf509879;hp=e79f8441e78fe10f293bc9fcf72787f4af3da857;hpb=eefb3cb82ae04982d6193576a93a0d87574834f6;p=xonotic%2Fdarkplaces.git diff --git a/sv_phys.c b/sv_phys.c index e79f8441..24b17ef7 100644 --- a/sv_phys.c +++ b/sv_phys.c @@ -82,15 +82,24 @@ int SV_GenericHitSuperContentsMask(const prvm_edict_t *passedict) SV_Move ================== */ +#ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND +#if COLLISIONPARANOID >= 1 +trace_t SV_Move_(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t pEnd, int type, prvm_edict_t *passedict, int hitsupercontentsmask) +#else +trace_t SV_Move(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t pEnd, int type, prvm_edict_t *passedict, int hitsupercontentsmask) +#endif +#else #if COLLISIONPARANOID >= 1 trace_t SV_Move_(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int type, prvm_edict_t *passedict, int hitsupercontentsmask) #else trace_t SV_Move(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int type, prvm_edict_t *passedict, int hitsupercontentsmask) #endif +#endif { vec3_t hullmins, hullmaxs; int i, bodysupercontents; int passedictprog; + float pitchsign = 1; qboolean pointtrace; prvm_edict_t *traceowner, *touch; trace_t trace; @@ -111,6 +120,20 @@ trace_t SV_Move(const vec3_t start, const vec3_t mins, const vec3_t maxs, const // list of entities to test for collisions int numtouchedicts; prvm_edict_t *touchedicts[MAX_EDICTS]; +#ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND + vec3_t end; + vec_t len = 0; + + if(!VectorCompare(start, pEnd)) + { + // TRICK: make the trace 1 qu longer! + VectorSubtract(pEnd, start, end); + len = VectorNormalizeLength(end); + VectorAdd(pEnd, end, end); + } + else + VectorCopy(pEnd, end); +#endif VectorCopy(start, clipstart); VectorCopy(end, clipend); @@ -128,7 +151,7 @@ trace_t SV_Move(const vec3_t start, const vec3_t mins, const vec3_t maxs, const if (cliptrace.startsolid || cliptrace.fraction < 1) cliptrace.ent = prog->edicts; if (type == MOVE_WORLDONLY) - return cliptrace; + goto finished; if (type == MOVE_MISSILE) { @@ -218,9 +241,22 @@ trace_t SV_Move(const vec3_t start, const vec3_t mins, const vec3_t maxs, const // if the modelindex is 0, it shouldn't be SOLID_BSP! if (modelindex > 0 && modelindex < MAX_MODELS) model = sv.models[(int)touch->fields.server->modelindex]; + //pitchsign = 1; + if ( + ((modelindex = (int)touch->fields.server->modelindex) >= 1 && modelindex < MAX_MODELS && (model = sv.models[(int)touch->fields.server->modelindex])) + ? + model->type == mod_alias + : + ( + (((unsigned char)PRVM_EDICTFIELDVALUE(touch, prog->fieldoffsets.pflags)->_float) & PFLAGS_FULLDYNAMIC) + || + ((gamemode == GAME_TENEBRAE) && ((unsigned int)touch->fields.server->effects & (16 | 32))) + ) + ) + pitchsign = -1; } if (model) - Matrix4x4_CreateFromQuakeEntity(&matrix, touch->fields.server->origin[0], touch->fields.server->origin[1], touch->fields.server->origin[2], touch->fields.server->angles[0], touch->fields.server->angles[1], touch->fields.server->angles[2], 1); + Matrix4x4_CreateFromQuakeEntity(&matrix, touch->fields.server->origin[0], touch->fields.server->origin[1], touch->fields.server->origin[2], pitchsign * touch->fields.server->angles[0], touch->fields.server->angles[1], touch->fields.server->angles[2], 1); else Matrix4x4_CreateTranslate(&matrix, touch->fields.server->origin[0], touch->fields.server->origin[1], touch->fields.server->origin[2]); Matrix4x4_Invert_Simple(&imatrix, &matrix); @@ -232,6 +268,11 @@ trace_t SV_Move(const vec3_t start, const vec3_t mins, const vec3_t maxs, const Collision_CombineTraces(&cliptrace, &trace, (void *)touch, touch->fields.server->solid == SOLID_BSP); } +finished: +#ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND + if(!VectorCompare(start, pEnd)) + Collision_ShortenTrace(&cliptrace, len / (len + 1), pEnd); +#endif return cliptrace; } @@ -484,11 +525,13 @@ returns true if the entity is in solid currently */ static int SV_TestEntityPosition (prvm_edict_t *ent, vec3_t offset) { + int contents; vec3_t org; trace_t trace; + contents = SV_GenericHitSuperContentsMask(ent); VectorAdd(ent->fields.server->origin, offset, org); - trace = SV_Move (org, ent->fields.server->mins, ent->fields.server->maxs, ent->fields.server->origin, MOVE_NOMONSTERS, ent, SUPERCONTENTS_SOLID); - if (trace.startsupercontents & SUPERCONTENTS_SOLID) + trace = SV_Move (org, ent->fields.server->mins, ent->fields.server->maxs, ent->fields.server->origin, MOVE_NOMONSTERS, ent, contents); + if (trace.startsupercontents & contents) return true; else { @@ -512,7 +555,7 @@ static int SV_TestEntityPosition (prvm_edict_t *ent, vec3_t offset) v[0] = (i & 1) ? m2[0] : m1[0]; v[1] = (i & 2) ? m2[1] : m1[1]; v[2] = (i & 4) ? m2[2] : m1[2]; - if (SV_PointSuperContents(v) & SUPERCONTENTS_SOLID) + if (SV_PointSuperContents(v) & contents) return true; } } @@ -526,7 +569,7 @@ static int SV_TestEntityPosition (prvm_edict_t *ent, vec3_t offset) #else // verify if the endpos is REALLY outside solid VectorCopy(trace.endpos, org); - trace = SV_Move (org, ent->fields.server->mins, ent->fields.server->maxs, org, MOVE_NOMONSTERS, ent, SUPERCONTENTS_SOLID); + trace = SV_Move (org, ent->fields.server->mins, ent->fields.server->maxs, org, MOVE_NOMONSTERS, ent, contents); if(trace.startsolid) Con_Printf("SV_TestEntityPosition: trace.endpos detected to be in solid. NOT using it.\n"); else @@ -684,14 +727,16 @@ qboolean SV_RunThink (prvm_edict_t *ent) SV_Impact Two entities have touched, so run their touch functions +returns true if the impact kept the origin of the touching entity intact ================== */ extern void VM_SetTraceGlobals(const trace_t *trace); extern sizebuf_t vm_tempstringsbuf; -void SV_Impact (prvm_edict_t *e1, trace_t *trace) +qboolean SV_Impact (prvm_edict_t *e1, trace_t *trace) { int restorevm_tempstringsbuf_cursize; int old_self, old_other; + vec3_t org; prvm_edict_t *e2 = (prvm_edict_t *)trace->ent; prvm_eval_t *val; @@ -699,6 +744,8 @@ void SV_Impact (prvm_edict_t *e1, trace_t *trace) old_other = prog->globals.server->other; restorevm_tempstringsbuf_cursize = vm_tempstringsbuf.cursize; + VectorCopy(e1->fields.server->origin, org); + VM_SetTraceGlobals(trace); prog->globals.server->time = sv.time; @@ -731,6 +778,8 @@ 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; + + return VectorCompare(e1->fields.server->origin, org); } @@ -766,11 +815,12 @@ Returns the clipflags if the velocity was modified (hit something solid) 1 = floor 2 = wall / step 4 = dead stop +8 = teleported by touch method If stepnormal is not NULL, the plane normal of any vertical wall hit will be stored ============ */ static float SV_Gravity (prvm_edict_t *ent); -static trace_t SV_PushEntity (prvm_edict_t *ent, vec3_t push, qboolean failonbmodelstartsolid, qboolean dolink); +static qboolean SV_PushEntity (trace_t *trace, prvm_edict_t *ent, vec3_t push, qboolean failonbmodelstartsolid, qboolean dolink); // LordHavoc: increased from 5 to 32 #define MAX_CLIP_PLANES 32 static int SV_FlyMove (prvm_edict_t *ent, float time, qboolean applygravity, float *stepnormal, int hitsupercontentsmask) @@ -813,13 +863,11 @@ static int SV_FlyMove (prvm_edict_t *ent, float time, qboolean applygravity, flo #if 0 VectorAdd(ent->fields.server->origin, push, end); #endif - trace = SV_PushEntity(ent, push, false, false); // the caller calls SV_LinkEntity on the own later - - if(!VectorCompare(trace.endpos, ent->fields.server->origin)) + if(!SV_PushEntity(&trace, ent, push, false, false)) { // we got teleported by a touch function // let's abort the move - Con_DPrintf("we got teleported\n"); + blocked |= 8; break; } @@ -1004,7 +1052,7 @@ static int SV_FlyMove (prvm_edict_t *ent, float time, qboolean applygravity, flo */ // LordHavoc: this came from QW and allows you to get out of water more easily - if (sv_gameplayfix_easierwaterjump.integer && ((int)ent->fields.server->flags & FL_WATERJUMP)) + if (sv_gameplayfix_easierwaterjump.integer && ((int)ent->fields.server->flags & FL_WATERJUMP) && !(blocked & 8)) VectorCopy(primal_velocity, ent->fields.server->velocity); if (applygravity && !((int)ent->fields.server->flags & FL_ONGROUND)) ent->fields.server->velocity[2] -= gravity; @@ -1044,12 +1092,13 @@ PUSHMOVE SV_PushEntity Does not change the entities velocity at all +The trace struct is filled with the trace that has been done. +Returns true if the push did not result in the entity being teleported by QC code. ============ */ -static trace_t SV_PushEntity (prvm_edict_t *ent, vec3_t push, qboolean failonbmodelstartsolid, qboolean dolink) +static qboolean SV_PushEntity (trace_t *trace, prvm_edict_t *ent, vec3_t push, qboolean failonbmodelstartsolid, qboolean dolink) { int type; - trace_t trace; vec3_t end; qboolean impact; @@ -1062,23 +1111,31 @@ static trace_t SV_PushEntity (prvm_edict_t *ent, vec3_t push, qboolean failonbmo else type = MOVE_NORMAL; - trace = SV_Move (ent->fields.server->origin, ent->fields.server->mins, ent->fields.server->maxs, end, type, ent, SV_GenericHitSuperContentsMask(ent)); - if (trace.bmodelstartsolid && failonbmodelstartsolid) - return trace; + *trace = SV_Move (ent->fields.server->origin, ent->fields.server->mins, ent->fields.server->maxs, end, type, ent, SV_GenericHitSuperContentsMask(ent)); + if (trace->bmodelstartsolid && failonbmodelstartsolid) + return true; + + VectorCopy (trace->endpos, ent->fields.server->origin); - VectorCopy (trace.endpos, ent->fields.server->origin); +#if 0 + if(!trace->startsolid) + if(SV_Move (ent->fields.server->origin, ent->fields.server->mins, ent->fields.server->maxs, ent->fields.server->origin, type, ent, SV_GenericHitSuperContentsMask(ent)).startsolid) + { + Con_Printf("something eeeeevil happened\n"); + } +#endif - impact = (ent->fields.server->solid >= SOLID_TRIGGER && trace.ent && (!((int)ent->fields.server->flags & FL_ONGROUND) || ent->fields.server->groundentity != PRVM_EDICT_TO_PROG(trace.ent))); + impact = (ent->fields.server->solid >= SOLID_TRIGGER && trace->ent && (!((int)ent->fields.server->flags & FL_ONGROUND) || ent->fields.server->groundentity != PRVM_EDICT_TO_PROG(trace->ent))); if(impact) { SV_LinkEdict (ent, dolink); - SV_Impact (ent, &trace); + return SV_Impact (ent, trace); } else if(dolink) SV_LinkEdict (ent, true); - return trace; + return true; } @@ -1100,7 +1157,7 @@ void SV_PushMove (prvm_edict_t *pusher, float movetime) int numcheckentities; static prvm_edict_t *checkentities[MAX_EDICTS]; dp_model_t *pushermodel; - trace_t trace; + trace_t trace, trace2; matrix4x4_t pusherfinalmatrix, pusherfinalimatrix; unsigned short moved_edicts[MAX_EDICTS]; @@ -1281,7 +1338,13 @@ void SV_PushMove (prvm_edict_t *pusher, float movetime) // try moving the contacted entity pusher->fields.server->solid = SOLID_NOT; - trace = SV_PushEntity (check, move, true, true); + if(!SV_PushEntity (&trace, check, move, true, true)) + { + // entity "check" got teleported + check->fields.server->angles[1] += trace.fraction * moveangle[1]; + pusher->fields.server->solid = savesolid; // was SOLID_BSP + continue; // pushed enough + } // FIXME: turn players specially check->fields.server->angles[1] += trace.fraction * moveangle[1]; pusher->fields.server->solid = savesolid; // was SOLID_BSP @@ -1303,7 +1366,11 @@ void SV_PushMove (prvm_edict_t *pusher, float movetime) VectorScale(move, 1.1, move2); VectorCopy (check->priv.server->moved_from, check->fields.server->origin); VectorCopy (check->priv.server->moved_fromangles, check->fields.server->angles); - SV_PushEntity (check, move2, true, true); + if(!SV_PushEntity (&trace2, check, move2, true, true)) + { + // entity "check" got teleported + continue; + } pusher->fields.server->solid = savesolid; Collision_ClipToGenericEntity(&trace, pushermodel, (int) 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) @@ -1313,7 +1380,11 @@ void SV_PushMove (prvm_edict_t *pusher, float movetime) VectorScale(move, 0.9, move2); VectorCopy (check->priv.server->moved_from, check->fields.server->origin); VectorCopy (check->priv.server->moved_fromangles, check->fields.server->angles); - SV_PushEntity (check, move2, true, true); + if(!SV_PushEntity (&trace2, check, move2, true, true)) + { + // entity "check" got teleported + continue; + } pusher->fields.server->solid = savesolid; Collision_ClipToGenericEntity(&trace, pushermodel, (int) 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) @@ -1638,7 +1709,7 @@ int SV_TryUnstick (prvm_edict_t *ent, vec3_t oldvel) case 7: dir[0] = -2; dir[1] = -2; break; } - SV_PushEntity (ent, dir, false, true); + SV_PushEntity (&trace, ent, dir, false, true); // retry the original move ent->fields.server->velocity[0] = oldvel[0]; @@ -1675,7 +1746,7 @@ void SV_WalkMove (prvm_edict_t *ent) { int clip, oldonground, originalmove_clip, originalmove_flags, originalmove_groundentity, hitsupercontentsmask; vec3_t upmove, downmove, start_origin, start_velocity, stepnormal, originalmove_origin, originalmove_velocity; - trace_t downtrace; + trace_t downtrace, trace; qboolean applygravity; // if frametime is 0 (due to client sending the same timestamp twice), @@ -1706,11 +1777,8 @@ void SV_WalkMove (prvm_edict_t *ent) SV_CheckVelocity(ent); SV_LinkEdict (ent, true); - VectorCopy(ent->fields.server->origin, originalmove_origin); - VectorCopy(ent->fields.server->velocity, originalmove_velocity); - originalmove_clip = clip; - originalmove_flags = (int)ent->fields.server->flags; - originalmove_groundentity = ent->fields.server->groundentity; + if(clip & 8) // teleport + return; if ((int)ent->fields.server->flags & FL_WATERJUMP) return; @@ -1718,6 +1786,12 @@ void SV_WalkMove (prvm_edict_t *ent) if (sv_nostep.integer) return; + VectorCopy(ent->fields.server->origin, originalmove_origin); + VectorCopy(ent->fields.server->velocity, originalmove_velocity); + originalmove_clip = clip; + originalmove_flags = (int)ent->fields.server->flags; + originalmove_groundentity = ent->fields.server->groundentity; + // if move didn't block on a step, return if (clip & 2) { @@ -1745,12 +1819,22 @@ void SV_WalkMove (prvm_edict_t *ent) // move up VectorClear (upmove); upmove[2] = sv_stepheight.value; - SV_PushEntity(ent, upmove, false, false); + if(!SV_PushEntity(&trace, ent, upmove, false, true)) + { + // we got teleported when upstepping... must abort the move + return; + } // move forward ent->fields.server->velocity[2] = 0; clip = SV_FlyMove (ent, sv.frametime, applygravity, stepnormal, hitsupercontentsmask); ent->fields.server->velocity[2] += start_velocity[2]; + if(clip & 8) + { + // we got teleported when upstepping... must abort the move + // note that z velocity handling may not be what QC expects here, but we cannot help it + return; + } SV_CheckVelocity(ent); SV_LinkEdict (ent, true); @@ -1786,7 +1870,11 @@ void SV_WalkMove (prvm_edict_t *ent) // move down VectorClear (downmove); downmove[2] = -sv_stepheight.value + start_velocity[2]*sv.frametime; - downtrace = SV_PushEntity (ent, downmove, false, false); + if(!SV_PushEntity (&downtrace, ent, downmove, false, true)) + { + // we got teleported when downstepping... must abort the move + return; + } if (downtrace.fraction < 1 && downtrace.plane.normal[2] > 0.7) { @@ -1947,7 +2035,8 @@ void SV_Physics_Toss (prvm_edict_t *ent) // and groundentity is now freed, set groundentity to 0 (world) // which leaves it suspended in the air ent->fields.server->groundentity = 0; - return; + if (sv_gameplayfix_noairborncorpse_allowsuspendeditems.integer) + return; } } ent->priv.server->suspendedinairflag = false; @@ -1966,14 +2055,16 @@ void SV_Physics_Toss (prvm_edict_t *ent) { // move origin VectorScale (ent->fields.server->velocity, movetime, move); - trace = SV_PushEntity (ent, move, true, true); + if(!SV_PushEntity (&trace, ent, move, true, true)) + return; // teleported if (ent->priv.server->free) return; if (trace.bmodelstartsolid) { // try to unstick the entity SV_UnstickEntity(ent); - trace = SV_PushEntity (ent, move, false, true); + if(!SV_PushEntity (&trace, ent, move, false, true)) + return; // teleported if (ent->priv.server->free) return; } @@ -2161,7 +2252,7 @@ static void SV_Physics_Entity (prvm_edict_t *ent) // ents in the first frame regardless) qboolean runmove = ent->priv.server->move; ent->priv.server->move = true; - if (!runmove && sv_gameplayfix_delayprojectiles.integer) + if (!runmove && sv_gameplayfix_delayprojectiles.integer > 0) return; switch ((int) ent->fields.server->movetype) { @@ -2397,9 +2488,17 @@ void SV_Physics (void) // run physics on all the non-client entities if (!sv_freezenonclients.integer) + { for (;i < prog->num_edicts;i++, ent = PRVM_NEXT_EDICT(ent)) if (!ent->priv.server->free) SV_Physics_Entity(ent); + // make a second pass to see if any ents spawned this frame and make + // sure they run their move/think + if (sv_gameplayfix_delayprojectiles.integer < 0) + for (i = svs.maxclients + 1, ent = PRVM_EDICT_NUM(i);i < prog->num_edicts;i++, ent = PRVM_NEXT_EDICT(ent)) + if (!ent->priv.server->move && !ent->priv.server->free) + SV_Physics_Entity(ent); + } if (prog->globals.server->force_retouch > 0) prog->globals.server->force_retouch = max(0, prog->globals.server->force_retouch - 1);