From: havoc Date: Sat, 30 Apr 2005 07:14:37 +0000 (+0000) Subject: relocated the CL_SendMove call to put it at the end of network parsing (and only... X-Git-Tag: xonotic-v0.1.0preview~4968 X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fdarkplaces.git;a=commitdiff_plain;h=d3cbe906d0eedcff735096a08340d8ca90457fa9;hp=30cf91679a3f0d8de407a01ea6c669c9ae134e70 relocated the CL_SendMove call to put it at the end of network parsing (and only called if there was an svc_time message in this packet), this should greatly improve consistency of ping times and input sending (which was sometimes falling way behind with lag), no longer uses sys_ticrate to control input frequency changed CL_TraceLine to CL_TraceBox and made it return a trace_t worked on CL_ClientMovement function for clientside movement simulation (not working yet), this has many cl_movement* cvars associated with it which will be updated by the server at some point in the future added (currently unused and not updated) cl_gravity and cl_slowmo cvars, which the server will be setting at some point in the future git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@5211 d7cf8633-e32d-0410-b094-e92efae38249 --- diff --git a/cgamevm.c b/cgamevm.c index e2b33f4d..3af510f0 100644 --- a/cgamevm.c +++ b/cgamevm.c @@ -194,19 +194,13 @@ float CGVM_RandomRange(const float r1, const float r2) float CGVM_TracePhysics(const float *start, const float *end, const float *worldmins, const float *worldmaxs, const float *entitymins, const float *entitymaxs, const cgphysentity_t *physentities, const int numphysentities, float *impactpos, float *impactnormal, int *impactentnum) { - float frac; - vec3_t start2, end2, middle; + trace_t trace; // FIXME: do tracing agains network entities and physentities here - // placeholder world only code assuming 0 size - middle[0] = (worldmins[0] + worldmaxs[0]) * 0.5f; - middle[1] = (worldmins[1] + worldmaxs[1]) * 0.5f; - middle[2] = (worldmins[2] + worldmaxs[2]) * 0.5f; - VectorAdd(start, middle, start2); - VectorAdd(end, middle, end2); - frac = CL_TraceLine((float *)start2, (float *)end2, impactpos, impactnormal, true, NULL, SUPERCONTENTS_SOLID); - VectorSubtract(impactpos, middle, impactpos); + trace = CL_TraceBox(start, vec3_origin, vec3_origin, end, true, NULL, SUPERCONTENTS_SOLID, false); + VectorCopy(trace.endpos, impactpos); + VectorCopy(trace.plane.normal, impactnormal); *impactentnum = -1; - return frac; + return trace.fraction; } char *CGVM_GetCvarString(const char *name) diff --git a/cl_collision.c b/cl_collision.c index 41734b30..8920a5ed 100644 --- a/cl_collision.c +++ b/cl_collision.c @@ -29,42 +29,40 @@ typedef struct physentity_s physentity_t; */ -int cl_traceline_startsupercontents; - -float CL_TraceLine(const vec3_t start, const vec3_t end, vec3_t impact, vec3_t normal, int hitbmodels, int *hitent, int hitsupercontentsmask) +trace_t CL_TraceBox(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int hitbmodels, int *hitent, int hitsupercontentsmask, qboolean hitplayers) { - float maxfrac, maxrealfrac; int n; entity_render_t *ent; - float tracemins[3], tracemaxs[3]; - trace_t trace; - float tempnormal[3], starttransformed[3], endtransformed[3]; + vec3_t tracemins, tracemaxs; + trace_t cliptrace, trace; + vec3_t starttransformed, endtransformed, starttransformedmins, endtransformedmins, starttransformedmaxs, endtransformedmaxs; + vec3_t startmins, startmaxs, endmins, endmaxs, entmins, entmaxs; + vec_t *playermins, *playermaxs; - memset (&trace, 0 , sizeof(trace_t)); - trace.fraction = 1; - trace.realfraction = 1; - VectorCopy (end, trace.endpos); + VectorAdd(start, mins, startmins); + VectorAdd(start, maxs, startmaxs); + VectorAdd(end, mins, endmins); + VectorAdd(end, maxs, endmaxs); + + memset (&cliptrace, 0 , sizeof(trace_t)); + cliptrace.fraction = 1; + cliptrace.realfraction = 1; - if (hitent) - *hitent = 0; Mod_CheckLoaded(cl.worldmodel); if (cl.worldmodel && cl.worldmodel->TraceBox) - cl.worldmodel->TraceBox(cl.worldmodel, 0, &trace, start, start, end, end, hitsupercontentsmask); + cl.worldmodel->TraceBox(cl.worldmodel, 0, &cliptrace, startmins, startmaxs, endmins, endmaxs, hitsupercontentsmask); - if (normal) - VectorCopy(trace.plane.normal, normal); - cl_traceline_startsupercontents = trace.startsupercontents; - maxfrac = trace.fraction; - maxrealfrac = trace.realfraction; + if (hitent) + *hitent = 0; if (hitbmodels && cl_num_brushmodel_entities) { - tracemins[0] = min(start[0], end[0]); - tracemaxs[0] = max(start[0], end[0]); - tracemins[1] = min(start[1], end[1]); - tracemaxs[1] = max(start[1], end[1]); - tracemins[2] = min(start[2], end[2]); - tracemaxs[2] = max(start[2], end[2]); + tracemins[0] = min(start[0], end[0]) + mins[0]; + tracemaxs[0] = max(start[0], end[0]) + maxs[0]; + tracemins[1] = min(start[1], end[1]) + mins[1]; + tracemaxs[1] = max(start[1], end[1]) + maxs[1]; + tracemins[2] = min(start[2], end[2]) + mins[2]; + tracemaxs[2] = max(start[2], end[2]) + maxs[2]; // look for embedded bmodels for (n = 0;n < cl_num_brushmodel_entities;n++) @@ -75,31 +73,111 @@ float CL_TraceLine(const vec3_t start, const vec3_t end, vec3_t impact, vec3_t n Matrix4x4_Transform(&ent->inversematrix, start, starttransformed); Matrix4x4_Transform(&ent->inversematrix, end, endtransformed); + VectorAdd(starttransformed, mins, starttransformedmins); + VectorAdd(starttransformed, maxs, starttransformedmaxs); + VectorAdd(endtransformed, mins, endtransformedmins); + VectorAdd(endtransformed, maxs, endtransformedmaxs); + + memset (&trace, 0 , sizeof(trace_t)); + trace.fraction = 1; + trace.realfraction = 1; if (ent->model && ent->model->TraceBox) - ent->model->TraceBox(ent->model, 0, &trace, starttransformed, starttransformed, endtransformed, endtransformed, hitsupercontentsmask); + ent->model->TraceBox(ent->model, 0, &trace, starttransformedmins, starttransformedmaxs, endtransformedmins, endtransformedmaxs, hitsupercontentsmask); - cl_traceline_startsupercontents |= trace.startsupercontents; - if (maxrealfrac > trace.realfraction) + // LordHavoc: take the 'best' answers from the new trace and combine with existing data + if (trace.allsolid) + cliptrace.allsolid = true; + if (trace.startsolid) { + cliptrace.startsolid = true; + if (cliptrace.realfraction == 1) + if (hitent) + *hitent = cl_brushmodel_entities[n]; + } + // don't set this except on the world, because it can easily confuse + // monsters underwater if there's a bmodel involved in the trace + // (inopen && inwater is how they check water visibility) + //if (trace.inopen) + // cliptrace.inopen = true; + if (trace.inwater) + cliptrace.inwater = true; + if (trace.realfraction < cliptrace.realfraction) + { + cliptrace.fraction = trace.fraction; + cliptrace.realfraction = trace.realfraction; + cliptrace.plane = trace.plane; if (hitent) *hitent = cl_brushmodel_entities[n]; - maxfrac = trace.fraction; - maxrealfrac = trace.realfraction; - if (normal) + Matrix4x4_Transform3x3(&ent->matrix, trace.plane.normal, cliptrace.plane.normal); + } + cliptrace.startsupercontents |= trace.startsupercontents; + } + } + if (hitplayers) + { + tracemins[0] = min(start[0], end[0]) + mins[0]; + tracemaxs[0] = max(start[0], end[0]) + maxs[0]; + tracemins[1] = min(start[1], end[1]) + mins[1]; + tracemaxs[1] = max(start[1], end[1]) + maxs[1]; + tracemins[2] = min(start[2], end[2]) + mins[2]; + tracemaxs[2] = max(start[2], end[2]) + maxs[2]; + + for (n = 1;n < cl.maxclients+1;n++) + { + if (n != cl.playerentity) + { + ent = &cl_entities[n].render; + // FIXME: crouch + playermins = cl_playerstandmins; + playermaxs = cl_playerstandmaxs; + VectorAdd(ent->origin, playermins, entmins); + VectorAdd(ent->origin, playermaxs, entmaxs); + if (!BoxesOverlap(tracemins, tracemaxs, entmins, entmaxs)) + continue; + + memset (&trace, 0 , sizeof(trace_t)); + trace.fraction = 1; + trace.realfraction = 1; + + Matrix4x4_Transform(&ent->inversematrix, start, starttransformed); + Matrix4x4_Transform(&ent->inversematrix, end, endtransformed); + Collision_ClipTrace_Box(&trace, playermins, playermaxs, starttransformed, mins, maxs, endtransformed, hitsupercontentsmask, SUPERCONTENTS_SOLID); + + // LordHavoc: take the 'best' answers from the new trace and combine with existing data + if (trace.allsolid) + cliptrace.allsolid = true; + if (trace.startsolid) + { + cliptrace.startsolid = true; + if (cliptrace.realfraction == 1) + if (hitent) + *hitent = n; + } + // don't set this except on the world, because it can easily confuse + // monsters underwater if there's a bmodel involved in the trace + // (inopen && inwater is how they check water visibility) + //if (trace.inopen) + // cliptrace.inopen = true; + if (trace.inwater) + cliptrace.inwater = true; + if (trace.realfraction < cliptrace.realfraction) { - VectorCopy(trace.plane.normal, tempnormal); - Matrix4x4_Transform3x3(&ent->matrix, tempnormal, normal); + cliptrace.fraction = trace.fraction; + cliptrace.realfraction = trace.realfraction; + cliptrace.plane = trace.plane; + if (hitent) + *hitent = n; + Matrix4x4_Transform3x3(&ent->matrix, trace.plane.normal, cliptrace.plane.normal); } + cliptrace.startsupercontents |= trace.startsupercontents; } } } - maxfrac = bound(0, maxfrac, 1); - maxrealfrac = bound(0, maxrealfrac, 1); - //if (maxfrac < 0 || maxfrac > 1) Con_Printf("fraction out of bounds %f %s:%d\n", maxfrac, __FILE__, __LINE__); - if (impact) - VectorLerp(start, maxfrac, end, impact); - return maxfrac; + cliptrace.fraction = bound(0, cliptrace.fraction, 1); + cliptrace.realfraction = bound(0, cliptrace.realfraction, 1); + VectorLerp(start, cliptrace.fraction, end, cliptrace.endpos); + return cliptrace; } float CL_SelectTraceLine(const vec3_t start, const vec3_t end, vec3_t impact, vec3_t normal, int *hitent, entity_render_t *ignoreent) @@ -124,7 +202,7 @@ float CL_SelectTraceLine(const vec3_t start, const vec3_t end, vec3_t impact, ve if (normal) VectorCopy(trace.plane.normal, normal); - cl_traceline_startsupercontents = trace.startsupercontents; + //cl_traceline_startsupercontents = trace.startsupercontents; maxfrac = trace.fraction; maxrealfrac = trace.realfraction; @@ -156,7 +234,7 @@ float CL_SelectTraceLine(const vec3_t start, const vec3_t end, vec3_t impact, ve if (ent->model && ent->model->TraceBox) ent->model->TraceBox(ent->model, ent->frameblend[0].frame, &trace, starttransformed, starttransformed, endtransformed, endtransformed, SUPERCONTENTS_SOLID); - cl_traceline_startsupercontents |= trace.startsupercontents; + //cl_traceline_startsupercontents |= trace.startsupercontents; if (maxrealfrac > trace.realfraction) { if (hitent) @@ -187,8 +265,7 @@ void CL_FindNonSolidLocation(const vec3_t in, vec3_t out, vec_t radius) int CL_PointQ1Contents(const vec3_t p) { - CL_TraceLine(p, p, NULL, NULL, true, NULL, 0); - return Mod_Q1BSP_NativeContentsFromSuperContents(NULL, cl_traceline_startsupercontents); + return Mod_Q1BSP_NativeContentsFromSuperContents(NULL, CL_TraceBox(p, vec3_origin, vec3_origin, p, true, NULL, 0, false).startsupercontents); /* // FIXME: check multiple brush models if (cl.worldmodel && cl.worldmodel->brush.PointContentsQ1) @@ -199,8 +276,7 @@ int CL_PointQ1Contents(const vec3_t p) int CL_PointSuperContents(const vec3_t p) { - CL_TraceLine(p, p, NULL, NULL, true, NULL, 0); - return cl_traceline_startsupercontents; + return CL_TraceBox(p, vec3_origin, vec3_origin, p, true, NULL, 0, false).startsupercontents; /* // FIXME: check multiple brush models if (cl.worldmodel && cl.worldmodel->brush.PointContentsQ1) diff --git a/cl_collision.h b/cl_collision.h index bf5390af..532ad250 100644 --- a/cl_collision.h +++ b/cl_collision.h @@ -2,11 +2,7 @@ #ifndef CL_COLLISION_H #define CL_COLLISION_H -// if contents is not zero, it will impact on content changes -// (leafs matching contents are considered empty, others are solid) -extern int cl_traceline_startcontents; // set by TraceLine - -float CL_TraceLine(const vec3_t start, const vec3_t end, vec3_t impact, vec3_t normal, int hitbmodels, int *hitent, int hitsupercontentsmask); +trace_t CL_TraceBox(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int hitbmodels, int *hitent, int hitsupercontentsmask, qboolean hitplayers); float CL_SelectTraceLine(const vec3_t start, const vec3_t end, vec3_t impact, vec3_t normal, int *hitent, entity_render_t *ignoreent); void CL_FindNonSolidLocation(const vec3_t in, vec3_t out, vec_t radius); int CL_PointQ1Contents(const vec3_t p); diff --git a/cl_input.c b/cl_input.c index f4bb34f5..d0bccf01 100644 --- a/cl_input.c +++ b/cl_input.c @@ -249,6 +249,19 @@ cvar_t cl_pitchspeed = {CVAR_SAVE, "cl_pitchspeed","150"}; cvar_t cl_anglespeedkey = {CVAR_SAVE, "cl_anglespeedkey","1.5"}; +cvar_t cl_movement = {CVAR_SAVE, "cl_movement", "0"}; +cvar_t cl_movement_latency = {0, "cl_movement_latency", "0"}; +cvar_t cl_movement_maxspeed = {0, "cl_movement_maxspeed", "320"}; +cvar_t cl_movement_maxairspeed = {0, "cl_movement_maxairspeed", "30"}; +cvar_t cl_movement_stopspeed = {0, "cl_movement_stopspeed", "100"}; +cvar_t cl_movement_friction = {0, "cl_movement_friction", "4"}; +cvar_t cl_movement_edgefriction = {0, "cl_movement_edgefriction", "2"}; +cvar_t cl_movement_stepheight = {0, "cl_movement_stepheight", "18"}; +cvar_t cl_movement_accelerate = {0, "cl_movement_accelerate", "10"}; +cvar_t cl_gravity = {0, "cl_gravity", "800"}; +cvar_t cl_slowmo = {0, "cl_slowmo", "1"}; + + /* ================ CL_AdjustAngles @@ -403,6 +416,219 @@ void CL_UpdatePrydonCursor(void) //CL_SparkShower(cl.cmd.cursor_impact, cl.cmd.cursor_normal, 5, 0); } +void CL_ClientMovement(qboolean buttonjump, qboolean buttoncrouch) +{ + int i, n, bump, contents, crouch; + //double simulatedtime; + double currenttime; + double newtime; + double frametime; + double t; + vec_t wishspeed, addspeed, accelspeed, f, *playermins, *playermaxs; + client_movementqueue_t *q; + vec3_t currentorigin, currentvelocity, forward, right, up, wishvel, wishdir, neworigin, currentorigin2, neworigin2, yawangles; + trace_t trace, trace2, trace3; + // remove stale queue items + n = cl.movement_numqueue; + cl.movement_numqueue = 0; + for (i = 0;i < n;i++) + if (cl.movement_queue[i].time >= cl.mtime[0]) + cl.movement_queue[cl.movement_numqueue++] = cl.movement_queue[i]; + // add to input queue if there is room + if (cl.movement_numqueue < sizeof(cl.movement_queue)/sizeof(cl.movement_queue[0])) + { + // add to input queue + cl.movement_queue[cl.movement_numqueue].time = cl.mtime[0] + cl_movement_latency.value; + VectorCopy(cl.viewangles, cl.movement_queue[cl.movement_numqueue].viewangles); + cl.movement_queue[cl.movement_numqueue].move[0] = cl.cmd.forwardmove; + cl.movement_queue[cl.movement_numqueue].move[1] = cl.cmd.sidemove; + cl.movement_queue[cl.movement_numqueue].move[2] = cl.cmd.upmove; + cl.movement_queue[cl.movement_numqueue].jump = buttonjump; + cl.movement_queue[cl.movement_numqueue].crouch = buttoncrouch; + cl.movement_numqueue++; + } + cl.movement = false; + // abort if client movement is disabled + if (!cl_movement.integer || cl.stats[STAT_HEALTH] <= 0) + return; + // fetch current starting values + currenttime = cl.mtime[0]; + VectorCopy(cl_entities[cl.playerentity].state_current.origin, currentorigin); + VectorCopy(cl.mvelocity[0], currentvelocity); + // calculate time to execute for + //simulatedtime = currenttime + cl_movement_latency.value; + // FIXME: try minor nudges in various directions if startsolid to find a + // safe place to start the walk (due to network compression in some + // protocols this starts in solid) + //currentorigin[2] += (1.0 / 32.0); // slight nudge to get out of the floor + crouch = false; // this will be updated on first move + //Con_Printf("%f: ", currenttime); + // replay input queue, and remove any stale queue items + // note: this relies on the fact there's always one queue item at the end + for (i = 0, q = cl.movement_queue;i < cl.movement_numqueue;i++, q++) + { + //newtime = (i == cl.movement_numqueue) ? simulatedtime : q->time; + newtime = q->time; + frametime = newtime - currenttime; + if (frametime < 0) + continue; + //Con_Printf(" %f", frametime); + currenttime = newtime; + if (crouch) + { + playermins = cl_playercrouchmins; + playermaxs = cl_playercrouchmaxs; + } + else + { + playermins = cl_playerstandmins; + playermaxs = cl_playerstandmaxs; + } + for (bump = 0, t = frametime;bump < 8 && VectorLength2(currentvelocity) > 0;bump++) + { + VectorMA(currentorigin, t, currentvelocity, neworigin); + trace = CL_TraceBox(currentorigin, playermins, playermaxs, neworigin, true, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_PLAYERCLIP, true); + if (trace.fraction < 1 && trace.plane.normal[2] == 0) + { + // may be a step or wall, try stepping up + // first move forward at a higher level + VectorSet(currentorigin2, currentorigin[0], currentorigin[1], currentorigin[2] + cl_movement_stepheight.value); + VectorSet(neworigin2, neworigin[0], neworigin[1], currentorigin[2] + cl_movement_stepheight.value); + trace2 = CL_TraceBox(currentorigin2, playermins, playermaxs, neworigin2, true, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_PLAYERCLIP, true); + // then move down from there + VectorCopy(trace2.endpos, currentorigin2); + VectorSet(neworigin2, trace2.endpos[0], trace2.endpos[1], currentorigin[2]); + trace3 = CL_TraceBox(currentorigin2, playermins, playermaxs, neworigin2, true, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_PLAYERCLIP, true); + //Con_Printf("%f %f %f %f : %f %f %f %f : %f %f %f %f\n", trace.fraction, trace.endpos[0], trace.endpos[1], trace.endpos[2], trace2.fraction, trace2.endpos[0], trace2.endpos[1], trace2.endpos[2], trace3.fraction, trace3.endpos[0], trace3.endpos[1], trace3.endpos[2]); + // accept the new trace if it made some progress + if (fabs(trace3.endpos[0] - trace.endpos[0]) >= 0.03125 || fabs(trace3.endpos[1] - trace.endpos[1]) >= 0.03125) + { + trace = trace2; + VectorCopy(trace3.endpos, trace.endpos); + } + } + if (trace.fraction == 1) + { + VectorCopy(trace.endpos, currentorigin); + break; + } + t *= 1 - trace.fraction; + if (trace.fraction >= 0.001) + VectorCopy(trace.endpos, currentorigin); + f = DotProduct(currentvelocity, trace.plane.normal); + VectorMA(currentvelocity, -f, trace.plane.normal, currentvelocity); + } + if (i < cl.movement_numqueue) + { + if (q->crouch) + { + // wants to crouch, this always works... + if (!crouch) + crouch = true; + } + else + { + // wants to stand, if currently crouching we need to check for a + // low ceiling first + if (crouch) + { + trace = CL_TraceBox(currentorigin, cl_playerstandmins, cl_playerstandmaxs, currentorigin, true, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_PLAYERCLIP, true); + if (!trace.startsolid) + crouch = false; + } + } + // change velocity according to q->viewangles and q->move + contents = CL_PointSuperContents(currentorigin); + if (contents & SUPERCONTENTS_LIQUIDSMASK) + { + // swim + AngleVectors(q->viewangles, forward, right, up); + VectorSet(up, 0, 0, 1); + VectorMAMAM(q->move[0], forward, q->move[1], right, q->move[2], up, wishvel); + wishspeed = VectorLength(wishvel); + if (wishspeed) + VectorScale(wishvel, 1 / wishspeed, wishdir); + wishspeed = min(wishspeed, cl_movement_maxspeed.value); + if (crouch) + wishspeed *= 0.5; + wishspeed *= 0.6; + VectorScale(currentvelocity, (1 - frametime * cl_movement_friction.value), currentvelocity); + f = wishspeed - DotProduct(currentvelocity, wishdir); + if (f > 0) + { + f = min(f, cl_movement_accelerate.value * frametime * wishspeed); + VectorMA(currentvelocity, f, wishdir, currentvelocity); + } + if (q->jump) + { + if (contents & SUPERCONTENTS_LAVA) + currentvelocity[2] = 50; + else if (contents & SUPERCONTENTS_SLIME) + currentvelocity[2] = 80; + else + { + if (gamemode == GAME_NEXUIZ) + currentvelocity[2] = 200; + else + currentvelocity[2] = 100; + } + } + } + else + { + // walk + VectorSet(yawangles, 0, cl.viewangles[1], 0); + AngleVectors(yawangles, forward, right, up); + VectorMAM(q->move[0], forward, q->move[1], right, wishvel); + wishspeed = VectorLength(wishvel); + if (wishspeed) + VectorScale(wishvel, 1 / wishspeed, wishdir); + wishspeed = min(wishspeed, cl_movement_maxspeed.value); + if (crouch) + wishspeed *= 0.5; + // check if onground + VectorSet(currentorigin2, currentorigin[0], currentorigin[1], currentorigin[2] + 1); + VectorSet(neworigin2, currentorigin[0], currentorigin[1], currentorigin[2] - 1); + trace = CL_TraceBox(currentorigin2, playermins, playermaxs, neworigin2, true, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_PLAYERCLIP, true); + if (trace.fraction < 1 && trace.plane.normal[2] > 0.7) + { + // apply ground friction + f = sqrt(currentvelocity[0] * currentvelocity[0] + currentvelocity[1] * currentvelocity[1]); + VectorSet(currentorigin2, currentorigin[0] + currentvelocity[0]*(16/f), currentorigin[1] + currentvelocity[1]*(16/f), currentorigin[2] + playermins[2]); + VectorSet(neworigin2, currentorigin2[0], currentorigin2[1], currentorigin2[2] - 34); + trace = CL_TraceBox(currentorigin2, vec3_origin, vec3_origin, neworigin2, true, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_PLAYERCLIP, true); + // apply friction + f = 1 - frametime * (trace.fraction == 1 ? cl_movement_edgefriction.value : 1) * ((f < cl_movement_stopspeed.value) ? (cl_movement_stopspeed.value / f) : 1) * cl_movement_friction.value; + f = max(f, 0); + VectorScale(currentvelocity, f, currentvelocity); + } + else + { + // apply air speed limit + wishspeed = min(wishspeed, cl_movement_maxairspeed.value); + } + if (gamemode == GAME_NEXUIZ) + addspeed = wishspeed; + else + addspeed = wishspeed - DotProduct(currentvelocity, wishdir); + if (addspeed > 0) + { + accelspeed = min(cl_movement_accelerate.value * frametime * wishspeed, addspeed); + VectorMA(currentvelocity, accelspeed, wishdir, currentvelocity); + } + currentvelocity[2] -= cl_gravity.value * frametime; + } + } + } + //Con_Printf(" :%f\n", currenttime); + // store replay location + cl.movement = true; + VectorCopy(cl.movement_origin, cl.movement_oldorigin); + VectorCopy(currentorigin, cl.movement_origin); + //VectorCopy(currentorigin, cl_entities[cl.playerentity].state_current.origin); + //VectorSet(cl_entities[cl.playerentity].state_current.angles, 0, cl.viewangles[1], 0); +} + /* ============== CL_SendMove @@ -414,7 +640,6 @@ void CL_SendMove(void) int bits; sizebuf_t buf; qbyte data[128]; - static double nextmovetime = 0; #define MOVEAVERAGING 0 #if MOVEAVERAGING static float forwardmove, sidemove, upmove, total; // accumulation @@ -422,8 +647,6 @@ void CL_SendMove(void) float forwardmove, sidemove, upmove; #endif - CL_UpdatePrydonCursor(); - #if MOVEAVERAGING // accumulate changes between messages forwardmove += cl.cmd.forwardmove; @@ -431,11 +654,8 @@ void CL_SendMove(void) upmove += cl.cmd.upmove; total++; #endif - // LordHavoc: cap outgoing movement messages to sys_ticrate - nextmovetime = bound(realtime - sys_ticrate.value, nextmovetime, realtime + sys_ticrate.value); - if (!cl.islocalgame && realtime < nextmovetime) + if (cls.signon != SIGNONS) return; - nextmovetime += sys_ticrate.value; #if MOVEAVERAGING // average the accumulated changes total = 1.0f / total; @@ -573,6 +793,9 @@ void CL_SendMove(void) if (!buf.cursize) return; + // FIXME: bits & 64 is +button5, Nexuiz specific + CL_ClientMovement((bits & 2) != 0, (bits & 64) != 0); + if (NetConn_SendUnreliableMessage(cls.netcon, &buf) == -1) { Con_Print("CL_SendMove: lost server connection\n"); @@ -639,5 +862,17 @@ void CL_InitInput (void) Cmd_AddCommand ("-button7", IN_Button7Up); Cmd_AddCommand ("+button8", IN_Button8Down); Cmd_AddCommand ("-button8", IN_Button8Up); + + Cvar_RegisterVariable(&cl_movement); + Cvar_RegisterVariable(&cl_movement_latency); + Cvar_RegisterVariable(&cl_movement_maxspeed); + Cvar_RegisterVariable(&cl_movement_maxairspeed); + Cvar_RegisterVariable(&cl_movement_stopspeed); + Cvar_RegisterVariable(&cl_movement_friction); + Cvar_RegisterVariable(&cl_movement_edgefriction); + Cvar_RegisterVariable(&cl_movement_stepheight); + Cvar_RegisterVariable(&cl_movement_accelerate); + Cvar_RegisterVariable(&cl_gravity); + Cvar_RegisterVariable(&cl_slowmo); } diff --git a/cl_main.c b/cl_main.c index afb593ab..e8760d27 100644 --- a/cl_main.c +++ b/cl_main.c @@ -63,6 +63,11 @@ cvar_t cl_noplayershadow = {CVAR_SAVE, "cl_noplayershadow", "0"}; cvar_t cl_prydoncursor = {0, "cl_prydoncursor", "0"}; +vec3_t cl_playerstandmins; +vec3_t cl_playerstandmaxs; +vec3_t cl_playercrouchmins; +vec3_t cl_playercrouchmaxs; + mempool_t *cl_mempool; client_static_t cls; @@ -158,6 +163,21 @@ void CL_ClearState(void) cl_entities[i].state_current = defaultstate; } + if (gamemode == GAME_NEXUIZ) + { + VectorSet(cl_playerstandmins, -16, -16, -24); + VectorSet(cl_playerstandmaxs, 16, 16, 45); + VectorSet(cl_playercrouchmins, -16, -16, -24); + VectorSet(cl_playercrouchmaxs, 16, 16, 25); + } + else + { + VectorSet(cl_playerstandmins, -16, -16, -24); + VectorSet(cl_playerstandmaxs, 16, 16, 24); + VectorSet(cl_playercrouchmins, -16, -16, -24); + VectorSet(cl_playercrouchmaxs, 16, 16, 24); + } + CL_Screen_NewMap(); CL_Particles_Clear(); CL_CGVM_Clear(); @@ -543,9 +563,10 @@ void CL_LinkNetworkEntity(entity_t *e) matrix4x4_t *matrix, blendmatrix, tempmatrix, matrix2; //matrix4x4_t dlightmatrix; int j, k, l, trailtype, temp; - float origin[3], angles[3], delta[3], lerp, dlightcolor[3], dlightradius, mins[3], maxs[3], v[3], v2[3], d; + float origin[3], angles[3], delta[3], lerp, dlightcolor[3], dlightradius, mins[3], maxs[3], v2[3], d; entity_t *t; model_t *model; + trace_t trace; //entity_persistent_t *p = &e->persistent; //entity_render_t *r = &e->render; if (e->persistent.linkframe != entitylinkframenumber) @@ -617,7 +638,15 @@ void CL_LinkNetworkEntity(entity_t *e) } // movement lerp - if (e->persistent.lerpdeltatime > 0 && (lerp = (cl.time - e->persistent.lerpstarttime) / e->persistent.lerpdeltatime) < 1) + // if it's the player entity, update according to client movement + if (e == cl_entities + cl.playerentity && cl.movement) + { + lerp = (cl.time - cl.mtime[0]) / (cl.mtime[0] - cl.mtime[1]); + lerp = bound(0, lerp, 1); + VectorLerp(cl.movement_oldorigin, lerp, cl.movement_origin, origin); + VectorSet(angles, 0, cl.viewangles[1], 0); + } + else if (e->persistent.lerpdeltatime > 0 && (lerp = (cl.time - e->persistent.lerpstarttime) / e->persistent.lerpdeltatime) < 1) { // interpolate the origin and angles VectorLerp(e->persistent.oldorigin, lerp, e->persistent.neworigin, origin); @@ -782,11 +811,11 @@ void CL_LinkNetworkEntity(entity_t *e) if (e->persistent.muzzleflash > 0) { Matrix4x4_Transform(&e->render.matrix, muzzleflashorigin, v2); - CL_TraceLine(origin, v2, v, NULL, true, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_SKY); + trace = CL_TraceBox(origin, vec3_origin, vec3_origin, v2, true, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_SKY, false); tempmatrix = e->render.matrix; - tempmatrix.m[0][3] = v[0]; - tempmatrix.m[1][3] = v[1]; - tempmatrix.m[2][3] = v[2]; + tempmatrix.m[0][3] = trace.endpos[0]; + tempmatrix.m[1][3] = trace.endpos[1]; + tempmatrix.m[2][3] = trace.endpos[2]; CL_AllocDlight(NULL, &tempmatrix, 100, e->persistent.muzzleflash, e->persistent.muzzleflash, e->persistent.muzzleflash, 0, 0, 0, -1, true, 0, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE); e->persistent.muzzleflash -= cl.frametime * 10; } @@ -1254,10 +1283,11 @@ int CL_ReadFromServer(void) CL_SendCmd ================= */ +void CL_UpdatePrydonCursor(void); void CL_SendCmd(void) { if (cls.signon == SIGNONS) - CL_SendMove(); + CL_UpdatePrydonCursor(); if (cls.demoplayback) { diff --git a/cl_parse.c b/cl_parse.c index 3edb16ab..e600f7cb 100644 --- a/cl_parse.c +++ b/cl_parse.c @@ -1340,6 +1340,7 @@ void CL_ParseServerMessage(void) qbyte cmdlog[32]; char *cmdlogname[32], *temp; int cmdindex, cmdcount = 0; + qboolean sendmove = false; if (cls.demorecording) CL_WriteDemoMessage (); @@ -1440,6 +1441,7 @@ void CL_ParseServerMessage(void) case svc_time: cl.mtime[1] = cl.mtime[0]; cl.mtime[0] = MSG_ReadFloat (); + sendmove = true; break; case svc_clientdata: @@ -1758,6 +1760,12 @@ void CL_ParseServerMessage(void) EntityFrameQuake_ISeeDeadEntities(); + if (sendmove) + { + // send one move per server frame + CL_SendMove(); + } + parsingerror = false; } diff --git a/cl_particles.c b/cl_particles.c index 2ac1966e..8683c08a 100644 --- a/cl_particles.c +++ b/cl_particles.c @@ -152,7 +152,7 @@ void VectorVectors(const vec3_t forward, vec3_t right, vec3_t up) #include "pmove.h" extern qboolean PM_RecursiveHullCheck (hull_t *hull, int num, float p1f, float p2f, vec3_t p1, vec3_t p2, pmtrace_t *trace); #endif -float CL_TraceLine (vec3_t start, vec3_t end, vec3_t impact, vec3_t normal, int hitbmodels, int *hitent, int hitsupercontentsmask) +trace_t CL_TraceBox (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int hitbmodels, int *hitent, int hitsupercontentsmask, qboolean hitplayers) { #if QW pmtrace_t trace; @@ -167,9 +167,7 @@ float CL_TraceLine (vec3_t start, vec3_t end, vec3_t impact, vec3_t normal, int #else RecursiveHullCheck (cl.worldmodel->hulls, 0, 0, 1, start, end, &trace); #endif - VectorCopy(trace.endpos, impact); - VectorCopy(trace.plane.normal, normal); - return trace.fraction; + return trace; } #else #include "cl_collision.h" @@ -476,20 +474,21 @@ void CL_SpawnDecalParticleForPoint(const vec3_t org, float maxdist, float size, { int i; float bestfrac, bestorg[3], bestnormal[3]; - float frac, v[3], normal[3], org2[3]; + float org2[3]; int besthitent = 0, hitent; + trace_t trace; bestfrac = 10; for (i = 0;i < 32;i++) { VectorRandom(org2); VectorMA(org, maxdist, org2, org2); - frac = CL_TraceLine(org, org2, v, normal, true, &hitent, SUPERCONTENTS_SOLID); - if (bestfrac > frac) + trace = CL_TraceBox(org, vec3_origin, vec3_origin, org2, true, &hitent, SUPERCONTENTS_SOLID, false); + if (bestfrac > trace.fraction) { - bestfrac = frac; + bestfrac = trace.fraction; besthitent = hitent; - VectorCopy(v, bestorg); - VectorCopy(normal, bestnormal); + VectorCopy(trace.endpos, bestorg); + VectorCopy(trace.plane.normal, bestnormal); } } if (bestfrac < 1) @@ -655,6 +654,7 @@ CL_ParticleExplosion void CL_ParticleExplosion (vec3_t org) { int i; + trace_t trace; //vec3_t v; //vec3_t v2; if (cl_stainmaps.integer) @@ -688,10 +688,11 @@ void CL_ParticleExplosion (vec3_t org) v[0] = org[0] + lhrandom(-48, 48); v[1] = org[1] + lhrandom(-48, 48); v[2] = org[2] + lhrandom(-48, 48); - if (CL_TraceLine(org, v, v2, NULL, true, NULL, SUPERCONTENTS_SOLID) >= 0.1) + trace = CL_TraceBox(org, vec3_origin, vec3_origin, v, true, NULL, SUPERCONTENTS_SOLID, false); + if (trace.fraction >= 0.1) break; } - VectorSubtract(v2, org, v2); + VectorSubtract(trace.endpos, org, v2); #endif VectorScale(v2, 2.0f, v2); particle(particletype + pt_smoke, 0x202020, 0x404040, tex_smoke[rand()&7], 12, 32, 64, 0, 0, org[0], org[1], org[2], v2[0], v2[1], v2[2], 0); @@ -796,8 +797,9 @@ void CL_SparkShower (vec3_t org, vec3_t dir, int count, vec_t gravityscale) void CL_Smoke (vec3_t org, vec3_t dir, int count) { - vec3_t org2, org3; + vec3_t org2; int k; + trace_t trace; if (!cl_particles.integer) return; @@ -810,8 +812,8 @@ void CL_Smoke (vec3_t org, vec3_t dir, int count) org2[0] = org[0] + 0.125f * lhrandom(-count, count); org2[1] = org[1] + 0.125f * lhrandom(-count, count); org2[2] = org[2] + 0.125f * lhrandom(-count, count); - CL_TraceLine(org, org2, org3, NULL, true, NULL, SUPERCONTENTS_SOLID); - particle(particletype + pt_smoke, 0x101010, 0x202020, tex_smoke[rand()&7], 3, (1.0f / cl_particles_quality.value) * 255, (1.0f / cl_particles_quality.value) * 1024, 0, 0, org3[0], org3[1], org3[2], lhrandom(-8, 8), lhrandom(-8, 8), lhrandom(-8, 8), 0); + trace = CL_TraceBox(org, vec3_origin, vec3_origin, org2, true, NULL, SUPERCONTENTS_SOLID, false); + particle(particletype + pt_smoke, 0x101010, 0x202020, tex_smoke[rand()&7], 3, (1.0f / cl_particles_quality.value) * 255, (1.0f / cl_particles_quality.value) * 1024, 0, 0, trace.endpos[0], trace.endpos[1], trace.endpos[2], lhrandom(-8, 8), lhrandom(-8, 8), lhrandom(-8, 8), 0); } } } @@ -834,7 +836,8 @@ static float bloodcount = 0; void CL_BloodPuff (vec3_t org, vec3_t vel, int count) { float s; - vec3_t org2, org3; + vec3_t org2; + trace_t trace; // bloodcount is used to accumulate counts too small to cause a blood particle if (!cl_particles.integer) return; if (!cl_particles_blood.integer) return; @@ -849,8 +852,8 @@ void CL_BloodPuff (vec3_t org, vec3_t vel, int count) org2[0] = org[0] + 0.125f * lhrandom(-bloodcount, bloodcount); org2[1] = org[1] + 0.125f * lhrandom(-bloodcount, bloodcount); org2[2] = org[2] + 0.125f * lhrandom(-bloodcount, bloodcount); - CL_TraceLine(org, org2, org3, NULL, true, NULL, SUPERCONTENTS_SOLID); - particle(particletype + pt_blood, 0xFFFFFF, 0xFFFFFF, tex_bloodparticle[rand()&7], 8, cl_particles_blood_alpha.value * 768 / cl_particles_quality.value, cl_particles_blood_alpha.value * 384 / cl_particles_quality.value, 0, -1, org3[0], org3[1], org3[2], vel[0] + lhrandom(-s, s), vel[1] + lhrandom(-s, s), vel[2] + lhrandom(-s, s), 1); + trace = CL_TraceBox(org, vec3_origin, vec3_origin, org2, true, NULL, SUPERCONTENTS_SOLID, false); + particle(particletype + pt_blood, 0xFFFFFF, 0xFFFFFF, tex_bloodparticle[rand()&7], 8, cl_particles_blood_alpha.value * 768 / cl_particles_quality.value, cl_particles_blood_alpha.value * 384 / cl_particles_quality.value, 0, -1, trace.endpos[0], trace.endpos[1], trace.endpos[2], vel[0] + lhrandom(-s, s), vel[1] + lhrandom(-s, s), vel[2] + lhrandom(-s, s), 1); bloodcount -= 16 / cl_particles_quality.value; } } @@ -1266,8 +1269,9 @@ void CL_MoveParticles (void) { particle_t *p; int i, maxparticle, j, a, content; - float gravity, dvel, bloodwaterfade, frametime, f, dist, normal[3], v[3], org[3], oldorg[3]; + float gravity, dvel, bloodwaterfade, frametime, f, dist, org[3], oldorg[3]; int hitent; + trace_t trace; // LordHavoc: early out condition if (!cl_numparticles) @@ -1312,17 +1316,17 @@ void CL_MoveParticles (void) if (p->type == particletype + pt_rain) { // raindrop - splash on solid/water/slime/lava - if (CL_TraceLine(oldorg, p->org, v, normal, true, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_LIQUIDSMASK) < 1) + trace = CL_TraceBox(oldorg, vec3_origin, vec3_origin, p->org, true, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_LIQUIDSMASK, false); + if (trace.fraction < 1) { - VectorCopy(v, p->org); - // splash - p->type = particletype + pt_raindecal; // convert from a raindrop particle to a rainsplash decal + VectorCopy(trace.endpos, p->org); + VectorCopy(trace.plane.normal, p->vel); + VectorAdd(p->org, p->vel, p->org); + p->type = particletype + pt_raindecal; p->texnum = tex_rainsplash[0]; p->time2 = cl.time; p->alphafade = p->alpha / 0.4; - VectorCopy(normal, p->vel); - VectorAdd(p->org, normal, p->org); p->bounce = 0; p->friction = 0; p->gravity = 0; @@ -1332,12 +1336,16 @@ void CL_MoveParticles (void) else if (p->type == particletype + pt_blood) { // blood - splash on solid - if (CL_TraceLine(oldorg, p->org, v, normal, true, &hitent, SUPERCONTENTS_SOLID) < 1) + trace = CL_TraceBox(oldorg, vec3_origin, vec3_origin, p->org, true, &hitent, SUPERCONTENTS_SOLID, false); + if (trace.fraction < 1) { - VectorCopy(v, p->org); + // convert from a blood particle to a blood decal + VectorCopy(trace.endpos, p->org); + VectorCopy(trace.plane.normal, p->vel); + VectorAdd(p->org, p->vel, p->org); #ifndef WORKINGLQUAKE if (cl_stainmaps.integer) - R_Stain(v, 32, 32, 16, 16, p->alpha * p->size * (1.0f / 40.0f), 192, 48, 48, p->alpha * p->size * (1.0f / 40.0f)); + R_Stain(p->org, 32, 32, 16, 16, p->alpha * p->size * (1.0f / 40.0f), 192, 48, 48, p->alpha * p->size * (1.0f / 40.0f)); #endif if (!cl_decals.integer) { @@ -1346,19 +1354,15 @@ void CL_MoveParticles (void) } p->type = particletype + pt_decal; - // convert from a blood particle to a blood decal p->texnum = tex_blooddecal[rand()&7]; #ifndef WORKINGLQUAKE p->owner = hitent; p->ownermodel = cl_entities[hitent].render.model; - Matrix4x4_Transform(&cl_entities[hitent].render.inversematrix, v, p->relativeorigin); - Matrix4x4_Transform3x3(&cl_entities[hitent].render.inversematrix, normal, p->relativedirection); - VectorAdd(p->relativeorigin, p->relativedirection, p->relativeorigin); + Matrix4x4_Transform(&cl_entities[hitent].render.inversematrix, p->org, p->relativeorigin); + Matrix4x4_Transform3x3(&cl_entities[hitent].render.inversematrix, p->vel, p->relativedirection); #endif p->time2 = cl.time; p->alphafade = 0; - VectorCopy(normal, p->vel); - VectorAdd(p->org, normal, p->org); p->bounce = 0; p->friction = 0; p->gravity = 0; @@ -1367,9 +1371,10 @@ void CL_MoveParticles (void) } else { - if (CL_TraceLine(oldorg, p->org, v, normal, true, NULL, SUPERCONTENTS_SOLID) < 1) + trace = CL_TraceBox(oldorg, vec3_origin, vec3_origin, p->org, true, NULL, SUPERCONTENTS_SOLID, false); + if (trace.fraction < 1) { - VectorCopy(v, p->org); + VectorCopy(trace.endpos, p->org); if (p->bounce < 0) { p->type = NULL; @@ -1377,8 +1382,8 @@ void CL_MoveParticles (void) } else { - dist = DotProduct(p->vel, normal) * -p->bounce; - VectorMA(p->vel, dist, normal, p->vel); + dist = DotProduct(p->vel, trace.plane.normal) * -p->bounce; + VectorMA(p->vel, dist, trace.plane.normal, p->vel); if (DotProduct(p->vel, p->vel) < 0.03) VectorClear(p->vel); } diff --git a/client.h b/client.h index 51645167..425f4a83 100644 --- a/client.h +++ b/client.h @@ -455,6 +455,16 @@ client_static_t; extern client_static_t cls; +typedef struct client_movementqueue_s +{ + double time; + float viewangles[3]; + float move[3]; + qboolean jump; + qboolean crouch; +} +client_movementqueue_t; + // // the client_state_t structure is wiped completely at every // server signon @@ -510,6 +520,16 @@ typedef struct // update by server, can be used by mods for zooming vec_t mviewzoom[2], viewzoom; + // client movement simulation + // these fields are only updated by CL_ClientMovement (called by CL_SendMove after parsing each network packet) + qboolean movement; + // simulated origin + vec3_t movement_origin; + vec3_t movement_oldorigin; + // queue of proposed moves + int movement_numqueue; + client_movementqueue_t movement_queue[256]; + // pitch drifting vars float idealpitch; float pitchvel; @@ -636,6 +656,11 @@ extern cvar_t cl_stainmaps_clearonload; extern cvar_t cl_prydoncursor; +extern vec3_t cl_playerstandmins; +extern vec3_t cl_playerstandmaxs; +extern vec3_t cl_playercrouchmins; +extern vec3_t cl_playercrouchmaxs; + // these are updated by CL_ClearState extern int cl_num_entities; extern int cl_num_static_entities; diff --git a/model_shared.c b/model_shared.c index 9e8200fa..368c1c3a 100644 --- a/model_shared.c +++ b/model_shared.c @@ -30,8 +30,8 @@ cvar_t r_mipskins = {CVAR_SAVE, "r_mipskins", "0"}; model_t *loadmodel; -// LordHavoc: increased from 512 to 2048 -#define MAX_MOD_KNOWN 2048 +// LordHavoc: was 512 +#define MAX_MOD_KNOWN (MAX_MODELS + 256) static model_t mod_known[MAX_MOD_KNOWN]; rtexturepool_t *mod_shared_texturepool; diff --git a/netconn.c b/netconn.c index b1f69921..5f64acd2 100755 --- a/netconn.c +++ b/netconn.c @@ -1167,13 +1167,15 @@ void NetConn_ClientFrame(void) if (cls.connect_trying && cls.connect_nextsendtime < realtime) { if (cls.connect_remainingtries == 0) + M_Update_Return_Reason("Connect: Waiting 10 seconds for reply"); + cls.connect_nextsendtime = realtime + 1; + cls.connect_remainingtries--; + if (cls.connect_remainingtries <= -10) { cls.connect_trying = false; M_Update_Return_Reason("Connect: Failed"); return; } - cls.connect_nextsendtime = realtime + 1; - cls.connect_remainingtries--; // try challenge first (newer server) NetConn_WriteString(cls.connect_mysocket, "\377\377\377\377getchallenge", &cls.connect_address); // then try netquake as a fallback (old server, or netquake) diff --git a/protocol.c b/protocol.c index 20e5d631..0f736110 100644 --- a/protocol.c +++ b/protocol.c @@ -1480,7 +1480,7 @@ void EntityState5_WriteUpdate(int number, const entity_state_t *s, int changedbi else { bits = changedbits; - if ((bits & E5_ORIGIN) && (s->origin[0] < -4096 || s->origin[0] >= 4096 || s->origin[1] < -4096 || s->origin[1] >= 4096 || s->origin[2] < -4096 || s->origin[2] >= 4096)) + if ((bits & E5_ORIGIN) && (!(s->flags & RENDER_LOWPRECISION) || s->origin[0] < -4096 || s->origin[0] >= 4096 || s->origin[1] < -4096 || s->origin[1] >= 4096 || s->origin[2] < -4096 || s->origin[2] >= 4096)) bits |= E5_ORIGIN32; if ((bits & E5_ANGLES) && !(s->flags & RENDER_LOWPRECISION)) bits |= E5_ANGLES16; diff --git a/r_crosshairs.c b/r_crosshairs.c index 8bb73b4d..1af46272 100644 --- a/r_crosshairs.c +++ b/r_crosshairs.c @@ -62,6 +62,7 @@ void R_DrawWorldCrosshair(void) vec3_t v1, v2, spriteorigin; vec_t spritescale; vec4_t color; + trace_t trace; if (r_letterbox.value) return; if (crosshair_static.integer) @@ -84,7 +85,9 @@ void R_DrawWorldCrosshair(void) AngleVectors(cl.viewangles, v2, NULL, NULL); //VectorCopy(r_vieworigin, v1); VectorMA(v1, 8192, v2, v2); - spritescale = CL_TraceLine(v1, v2, spriteorigin, NULL, true, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_SKY) * (8192.0f / 40.0f) * crosshair_size.value; + trace = CL_TraceBox(v1, vec3_origin, vec3_origin, v2, true, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_SKY, false); + spritescale = trace.fraction * (8192.0f / 40.0f) * crosshair_size.value; + VectorCopy(trace.endpos, spriteorigin); // draw the sprite R_DrawSprite(GL_SRC_ALPHA, GL_ONE, pic->tex, true, spriteorigin, r_viewright, r_viewup, spritescale, -spritescale, -spritescale, spritescale, color[0], color[1], color[2], color[3]); diff --git a/r_explosion.c b/r_explosion.c index 800c9106..74d63bfb 100644 --- a/r_explosion.c +++ b/r_explosion.c @@ -145,8 +145,8 @@ void R_NewExplosion(vec3_t org) { int i, j; float dist, n; - vec3_t impact; explosion_t *e; + trace_t trace; qbyte noise[EXPLOSIONGRID*EXPLOSIONGRID]; fractalnoisequick(noise, EXPLOSIONGRID, 4); // adjust noise grid size according to explosion for (i = 0, e = explosion;i < MAX_EXPLOSIONS;i++, e++) @@ -171,8 +171,8 @@ void R_NewExplosion(vec3_t org) // clip start origin if (e->clipping) { - CL_TraceLine(e->origin, e->vert[j], impact, NULL, true, NULL, SUPERCONTENTS_SOLID); - VectorCopy(impact, e->vert[i]); + trace = CL_TraceBox(e->origin, vec3_origin, vec3_origin, e->vert[j], true, NULL, SUPERCONTENTS_SOLID, false); + VectorCopy(trace.endpos, e->vert[i]); } } break; @@ -213,7 +213,8 @@ void R_DrawExplosionCallback(const void *calldata1, int calldata2) void R_MoveExplosion(explosion_t *e) { int i; - float dot, end[3], impact[3], normal[3], frametime; + float dot, end[3], frametime; + trace_t trace; frametime = cl.time - e->time; e->time = cl.time; @@ -225,13 +226,14 @@ void R_MoveExplosion(explosion_t *e) VectorMA(e->vert[i], frametime, e->vertvel[i], end); if (e->clipping) { - if (CL_TraceLine(e->vert[i], end, impact, normal, true, NULL, SUPERCONTENTS_SOLID) < 1) + trace = CL_TraceBox(e->vert[i], vec3_origin, vec3_origin, end, true, NULL, SUPERCONTENTS_SOLID, false); + if (trace.fraction < 1) { // clip velocity against the wall - dot = -DotProduct(e->vertvel[i], normal); - VectorMA(e->vertvel[i], dot, normal, e->vertvel[i]); + dot = -DotProduct(e->vertvel[i], trace.plane.normal); + VectorMA(e->vertvel[i], dot, trace.plane.normal, e->vertvel[i]); } - VectorCopy(impact, e->vert[i]); + VectorCopy(trace.endpos, e->vert[i]); } else VectorCopy(end, e->vert[i]); diff --git a/r_light.c b/r_light.c index cebe80b3..83d96303 100644 --- a/r_light.c +++ b/r_light.c @@ -138,7 +138,7 @@ void R_DrawCoronas(void) flag = r_rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE; for (lnum = 0, light = r_shadow_worldlightchain;light;light = light->next, lnum++) { - if ((light->flags & flag) && light->corona * r_coronas.value > 0 && (r_shadow_debuglight.integer < 0 || r_shadow_debuglight.integer == lnum) && (dist = (DotProduct(light->rtlight.shadoworigin, r_viewforward) - viewdist)) >= 24.0f && CL_TraceLine(light->rtlight.shadoworigin, r_vieworigin, NULL, NULL, true, NULL, SUPERCONTENTS_SOLID) == 1) + if ((light->flags & flag) && light->corona * r_coronas.value > 0 && (r_shadow_debuglight.integer < 0 || r_shadow_debuglight.integer == lnum) && (dist = (DotProduct(light->rtlight.shadoworigin, r_viewforward) - viewdist)) >= 24.0f && CL_TraceBox(light->rtlight.shadoworigin, vec3_origin, vec3_origin, r_vieworigin, true, NULL, SUPERCONTENTS_SOLID, false).fraction == 1) { cscale = light->rtlight.corona * r_coronas.value * 0.25f; scale = light->rtlight.radius * light->rtlight.coronasizescale; @@ -147,7 +147,7 @@ void R_DrawCoronas(void) } for (i = 0, light = r_dlight;i < r_numdlights;i++, light++) { - if ((light->flags & flag) && light->corona * r_coronas.value > 0 && (dist = (DotProduct(light->origin, r_viewforward) - viewdist)) >= 24.0f && CL_TraceLine(light->origin, r_vieworigin, NULL, NULL, true, NULL, SUPERCONTENTS_SOLID) == 1) + if ((light->flags & flag) && light->corona * r_coronas.value > 0 && (dist = (DotProduct(light->origin, r_viewforward) - viewdist)) >= 24.0f && CL_TraceBox(light->origin, vec3_origin, vec3_origin, r_vieworigin, true, NULL, SUPERCONTENTS_SOLID, false).fraction == 1) { cscale = light->corona * r_coronas.value * 0.25f; scale = light->rtlight.radius * light->rtlight.coronasizescale; @@ -196,7 +196,7 @@ void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffu { VectorSubtract (p, sl->origin, v); f = ((1.0f / (DotProduct(v, v) * sl->falloff + sl->distbias)) - sl->subtract); - if (f > 0 && CL_TraceLine(p, sl->origin, NULL, NULL, false, NULL, SUPERCONTENTS_SOLID) == 1) + if (f > 0 && CL_TraceBox(p, vec3_origin, vec3_origin, sl->origin, false, NULL, SUPERCONTENTS_SOLID, false).fraction == 1) { f *= d_lightstylevalue[sl->style] * (1.0f / 65536.0f); VectorMA(ambientcolor, f, sl->light, ambientcolor); @@ -216,7 +216,7 @@ void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffu light = r_dlight + i; VectorSubtract(p, light->origin, v); f = DotProduct(v, v); - if (f < light->rtlight.lightmap_cullradius2 && CL_TraceLine(p, light->origin, NULL, NULL, false, NULL, SUPERCONTENTS_SOLID) == 1) + if (f < light->rtlight.lightmap_cullradius2 && CL_TraceBox(p, vec3_origin, vec3_origin, light->origin, false, NULL, SUPERCONTENTS_SOLID, false).fraction == 1) { f = (1.0f / (f + LIGHTOFFSET)) - light->rtlight.lightmap_subtract; VectorMA(ambientcolor, f, light->rtlight.lightmap_light, ambientcolor); @@ -344,7 +344,7 @@ int R_LightModel(float *ambient4f, float *diffusecolor, float *diffusenormal, co VectorSubtract (v, light->origin, v); if (DotProduct(v, v) < light->rtlight.lightmap_cullradius2) { - if (CL_TraceLine(ent->origin, light->origin, NULL, NULL, false, NULL, SUPERCONTENTS_SOLID) != 1) + if (CL_TraceBox(ent->origin, vec3_origin, vec3_origin, light->origin, false, NULL, SUPERCONTENTS_SOLID, false).fraction != 1) continue; VectorSubtract (ent->origin, light->origin, v); f = ((1.0f / (DotProduct(v, v) + LIGHTOFFSET)) - light->rtlight.lightmap_subtract); @@ -483,7 +483,7 @@ void R_UpdateEntLights(entity_render_t *ent) ent->numentlights = 0; if (r_refdef.worldmodel) for (i = 0, sl = r_refdef.worldmodel->brushq1.lights;i < r_refdef.worldmodel->brushq1.numlights && ent->numentlights < MAXENTLIGHTS;i++, sl++) - if (CL_TraceLine(ent->origin, sl->origin, NULL, NULL, false, NULL, SUPERCONTENTS_SOLID) == 1) + if (CL_TraceBox(ent->origin, vec3_origin, vec3_origin, sl->origin, false, NULL, SUPERCONTENTS_SOLID, false).fraction == 1) ent->entlights[ent->numentlights++] = i; } ent->entlightsframe = r_framecount; diff --git a/r_shadow.c b/r_shadow.c index 08e2dc84..b8127bd0 100644 --- a/r_shadow.c +++ b/r_shadow.c @@ -3297,7 +3297,7 @@ void R_Shadow_SelectLightInView(void) if (rating >= 0.95) { rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp))); - if (bestrating < rating && CL_TraceLine(light->origin, r_vieworigin, NULL, NULL, true, NULL, SUPERCONTENTS_SOLID) == 1.0f) + if (bestrating < rating && CL_TraceBox(light->origin, vec3_origin, vec3_origin, r_vieworigin, true, NULL, SUPERCONTENTS_SOLID, false).fraction == 1.0f) { bestrating = rating; best = light; @@ -3722,19 +3722,20 @@ void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void) void R_Shadow_SetCursorLocationForView(void) { - vec_t dist, push, frac; - vec3_t dest, endpos, normal; + vec_t dist, push; + vec3_t dest, endpos; + trace_t trace; VectorMA(r_vieworigin, r_editlights_cursordistance.value, r_viewforward, dest); - frac = CL_TraceLine(r_vieworigin, dest, endpos, normal, true, NULL, SUPERCONTENTS_SOLID); - if (frac < 1) + trace = CL_TraceBox(r_vieworigin, vec3_origin, vec3_origin, dest, true, NULL, SUPERCONTENTS_SOLID, false); + if (trace.fraction < 1) { - dist = frac * r_editlights_cursordistance.value; + dist = trace.fraction * r_editlights_cursordistance.value; push = r_editlights_cursorpushback.value; if (push > dist) push = dist; push = -push; - VectorMA(endpos, push, r_viewforward, endpos); - VectorMA(endpos, r_editlights_cursorpushoff.value, normal, endpos); + VectorMA(trace.endpos, push, r_viewforward, endpos); + VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos); } r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value; r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value; diff --git a/view.c b/view.c index 36176d6d..b1e2a98d 100644 --- a/view.c +++ b/view.c @@ -313,6 +313,7 @@ void V_CalcRefdef (void) static float oldz; entity_t *ent; float vieworg[3], viewangles[3]; + trace_t trace; Matrix4x4_CreateIdentity(&viewmodelmatrix); Matrix4x4_CreateIdentity(&r_refdef.viewentitymatrix); if (cls.state == ca_connected && cls.signon == SIGNONS) @@ -352,7 +353,7 @@ void V_CalcRefdef (void) if (chase_active.value) { // observing entity from third person - vec_t camback, camup, dist, forward[3], stop[3], chase_dest[3], normal[3]; + vec_t camback, camup, dist, forward[3], chase_dest[3]; camback = bound(0, chase_back.value, 128); if (chase_back.value != camback) @@ -377,10 +378,8 @@ void V_CalcRefdef (void) chase_dest[0] = vieworg[0] + forward[0] * dist; chase_dest[1] = vieworg[1] + forward[1] * dist; chase_dest[2] = vieworg[2] + forward[2] * dist + camup; - CL_TraceLine(vieworg, chase_dest, stop, normal, true, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_SKY); - vieworg[0] = stop[0] + forward[0] * 8 + normal[0] * 4; - vieworg[1] = stop[1] + forward[1] * 8 + normal[1] * 4; - vieworg[2] = stop[2] + forward[2] * 8 + normal[2] * 4; + trace = CL_TraceBox(vieworg, vec3_origin, vec3_origin, chase_dest, true, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_SKY, false); + VectorMAMAM(1, trace.endpos, 8, forward, 4, trace.plane.normal, vieworg); } else {