diff --git a/Quake/cl_main.c b/Quake/cl_main.c index 46e4c989..3bc44a71 100644 --- a/Quake/cl_main.c +++ b/Quake/cl_main.c @@ -41,6 +41,7 @@ cvar_t cl_bottomcolor = {"bottomcolor", "", CVAR_ARCHIVE | CVAR_USERINFO}; cvar_t cl_shownet = {"cl_shownet","0",CVAR_NONE}; // can be 0, 1, or 2 cvar_t cl_nolerp = {"cl_nolerp","0",CVAR_NONE}; +cvar_t cl_nopred = {"cl_nopred", "0", CVAR_ARCHIVE}; //name comes from quakeworld. cvar_t cfg_unbindall = {"cfg_unbindall", "1", CVAR_ARCHIVE}; @@ -493,6 +494,108 @@ static qboolean CL_LerpEntity(entity_t *ent, vec3_t org, vec3_t ang, float frac) int j; vec3_t delta; qboolean teleported = false; + + if (ent->netstate.pmovetype && ent-cl.entities==cl.viewentity && qcvm->worldmodel && !cl_nopred.value) + { //note: V_CalcRefdef will copy from cl.entities[viewent] to get its origin, so doing it here is the proper place anyway. + static struct + { + int seq; + float waterjumptime; + } propagate[countof(cl.movecmds)]; + vec3_t bounds[2]; + +// memset(&pmove, 0xff, sizeof(pmove)); +#ifdef VALGRIND_MAKE_MEM_UNDEFINED + VALGRIND_MAKE_MEM_UNDEFINED(&pmove, sizeof(pmove)); +#endif + PMCL_SetMoveVars(); + + if (ent->netstate.solidsize) + { + pmove.player_maxs[0] = pmove.player_maxs[1] = ent->netstate.solidsize & 255; + pmove.player_mins[0] = pmove.player_mins[1] = -pmove.player_maxs[0]; + pmove.player_mins[2] = -(int)((ent->netstate.solidsize >>8) & 255); + pmove.player_maxs[2] = (int)((ent->netstate.solidsize>>16) & 65535) - 32768; + } + else + { + VectorClear(pmove.player_mins); + VectorClear(pmove.player_maxs); + } + pmove.safeorigin_known = false; + VectorCopy(ent->msg_origins[0], pmove.origin); + for (j = 0; j < 3; j++) + { + pmove.velocity[j] = ent->netstate.velocity[j]*1.0/8; + bounds[0][j] = pmove.origin[j] + pmove.player_mins[j] - 256; + bounds[1][j] = pmove.origin[j] + pmove.player_maxs[j] + 256; + } + VectorClear(pmove.gravitydir); + + pmove.waterjumptime = 0;//FIXME: needs propagation. (e->v.teleport_time>qcvm->time)?e->v.teleport_time - qcvm->time:0; + pmove.jump_held = !!(ent->netstate.pmovetype&0x40); + pmove.onladder = false;//!!(fl&PMF_LADDER); + pmove.jump_secs = 0; //has been 0 since Z_EXT_PM_TYPE instead of imposing a delay on rejumps. + pmove.onground = !!(ent->netstate.pmovetype&0x80); //in case we're using pm_pground + + switch(ent->netstate.pmovetype&63) + { + case MOVETYPE_WALK: pmove.pm_type = PM_NORMAL; break; + case MOVETYPE_TOSS: //pmove.pm_type = PM_DEAD; break; + case MOVETYPE_BOUNCE: pmove.pm_type = PM_DEAD; break; + case MOVETYPE_FLY: pmove.pm_type = PM_FLY; break; + case MOVETYPE_NOCLIP: pmove.pm_type = PM_SPECTATOR; break; + + case MOVETYPE_NONE: + case MOVETYPE_STEP: + case MOVETYPE_PUSH: + case MOVETYPE_FLYMISSILE: + case MOVETYPE_EXT_BOUNCEMISSILE: + case MOVETYPE_EXT_FOLLOW: + default: pmove.pm_type = PM_NONE; break; + } + + pmove.skipent = -(int)(ent-cl.entities); + World_AddEntsToPmove(NULL, bounds); + + j = cl.ackedmovemessages+1; + if (j < cl.movemessages-countof(cl.movecmds)) + j = cl.movemessages-countof(cl.movecmds); //don't corrupt things, lost is lost. + + if (propagate[j%countof(cl.movecmds)].seq == j) + { //some things can only be known thanks to propagation. + pmove.waterjumptime = propagate[j%countof(cl.movecmds)].waterjumptime; + } +// else Con_Printf("propagation not available\n"); //just do without + + for (; j < cl.movemessages; j++) + { + pmove.cmd = cl.movecmds[j%countof(cl.movecmds)]; + PM_PlayerMove(1); + + propagate[(j+1)%countof(cl.movecmds)].seq = j+1; + propagate[(j+1)%countof(cl.movecmds)].waterjumptime = pmove.waterjumptime; + } + + //and run the partial too, to keep things smooth + pmove.cmd = cl.pendingcmd; + PM_PlayerMove(1); + + VectorCopy (pmove.origin, org); + VectorCopy (pmove.cmd.viewangles, ang); + ang[0] *= -1.0/3; //FIXME: STUPID STUPID BUG + + //for bob+calcrefdef stuff, mostly. + VectorCopy (pmove.velocity, cl.velocity); + cl.onground = pmove.onground; + cl.inwater = pmove.waterlevel>=2; + + //FIXME: add stair-smoothing support + //FIXME: add error correction + + return true; //if we're predicting, don't let its old position linger as interpolation. should be less laggy that way, or something. + } + //figure out the pos+angles of the parent if (ent->forcelink) { // the entity was not updated in the last message @@ -1145,8 +1248,10 @@ int CL_ReadFromServer (void) if (cl_shownet.value) Con_Printf ("\n"); + PR_SwitchQCVM(&cl.qcvm); CL_RelinkEntities (); CL_UpdateTEnts (); + PR_SwitchQCVM(NULL); //johnfitz -- devstats @@ -1570,6 +1675,7 @@ void CL_Init (void) Cvar_RegisterVariable (&cl_anglespeedkey); Cvar_RegisterVariable (&cl_shownet); Cvar_RegisterVariable (&cl_nolerp); + Cvar_RegisterVariable (&cl_nopred); Cvar_RegisterVariable (&lookspring); Cvar_RegisterVariable (&lookstrafe); Cvar_RegisterVariable (&sensitivity); diff --git a/Quake/host.c b/Quake/host.c index b0ad6d86..d79f7cad 100644 --- a/Quake/host.c +++ b/Quake/host.c @@ -766,13 +766,13 @@ static void CL_LoadCSProgs(void) qboolean fullcsqc = false; int i; PR_ClearProgs(&cl.qcvm); + PR_SwitchQCVM(&cl.qcvm); if (pr_checkextension.value && !cl_nocsqc.value) { //only try to use csqc if qc extensions are enabled. char versionedname[MAX_QPATH]; unsigned int csqchash; size_t csqcsize; const char *val; - PR_SwitchQCVM(&cl.qcvm); val = Info_GetKey(cl.serverinfo, "*csprogs", versionedname, sizeof(versionedname)); csqchash = (unsigned int)strtoul(val, NULL, 0); if (*val) @@ -863,9 +863,18 @@ static void CL_LoadCSProgs(void) } } else + { PR_ClearProgs(qcvm); - PR_SwitchQCVM(NULL); + qcvm->worldmodel = cl.worldmodel; + SV_ClearWorld(); + } } + else + { //always initialsing at least part of it, allowing us to share some state with prediction. + qcvm->worldmodel = cl.worldmodel; + SV_ClearWorld(); + } + PR_SwitchQCVM(NULL); } /* diff --git a/Quake/pmove.h b/Quake/pmove.h index 58201a57..ccd18e13 100644 --- a/Quake/pmove.h +++ b/Quake/pmove.h @@ -163,9 +163,11 @@ int SV_HullPointContents (hull_t *hull, int num, vec3_t p); void SV_Impact (edict_t *e1, edict_t *e2); void World_AddEntsToPmove(edict_t *ignore, vec3_t boxminmax[2]); void PMCL_ServerinfoUpdated(void); +void PMCL_SetMoveVars(void); void PMSV_SetMoveStats(edict_t *plent, float *fstat, int *istat); //so client has the right movevars as stats. void PMSV_UpdateMovevars(void); void PF_sv_pmove(void); +void PMSV_UpdateMovevars(void); void PM_Register(void); #define VectorClear(v) ((v)[0] = (v)[1] = (v)[2] = 0) #define VectorSet(r,x,y,z) do{(r)[0] = x; (r)[1] = y;(r)[2] = z;}while(0) diff --git a/Quake/pr_ext.c b/Quake/pr_ext.c index 3c6f8661..39fba44b 100644 --- a/Quake/pr_ext.c +++ b/Quake/pr_ext.c @@ -1886,7 +1886,10 @@ static void PF_both_pmove(edict_t *e) eval_t *pmflags = GetEdictFieldValue(e, qcvm->extfields.pmove_flags); unsigned int fl = (pmflags && pmflags->_float)?pmflags->_float:0; - memset(&pmove, 0, sizeof(pmove)); +// memset(&pmove, 0xff, sizeof(pmove)); +#ifdef VALGRIND_MAKE_MEM_UNDEFINED + VALGRIND_MAKE_MEM_UNDEFINED(&pmove, sizeof(pmove)); +#endif VectorCopy(e->v.mins, pmove.player_mins); VectorCopy(e->v.maxs, pmove.player_maxs); VectorCopy(e->v.oldorigin, pmove.safeorigin); pmove.safeorigin_known = (qcvm==&sv.qcvm); //where we revert to when stuck. only consider this valid for ssqc. @@ -2066,7 +2069,7 @@ void PMSV_UpdateMovevars(void) svmovevars.maxairspeed = 30; svmovevars.flags = MOVEFLAG_VALID|MOVEFLAG_NOGRAVITYONGROUND|(*pm_edgefriction.string?0:MOVEFLAG_QWEDGEBOX); }; -static void PF_sv_pmove(void) +void PF_sv_pmove(void) { edict_t *e = G_EDICT(OFS_PARM0); movevars = svmovevars; @@ -2136,10 +2139,8 @@ void PMCL_ServerinfoUpdated(void) clmovevars.jumpspeed = 270; clmovevars.maxairspeed = 30; }; -static void PF_cs_pmove(void) +void PMCL_SetMoveVars(void) { - edict_t *e = G_EDICT(OFS_PARM0); - movevars = clmovevars; if (cl.protocol_pext2 & PEXT2_PREDINFO) { //protocol provides movevars as stats... @@ -2161,7 +2162,11 @@ static void PF_cs_pmove(void) movevars.jumpspeed = fstat[STAT_MOVEVARS_JUMPVELOCITY]; movevars.maxairspeed = fstat[STAT_MOVEVARS_MAXAIRSPEED]; } - +} +static void PF_cs_pmove(void) +{ + edict_t *e = G_EDICT(OFS_PARM0); + PMCL_SetMoveVars(); PF_both_pmove(e); } diff --git a/Quake/world.c b/Quake/world.c index f6cf6ba5..fee171d2 100644 --- a/Quake/world.c +++ b/Quake/world.c @@ -286,10 +286,13 @@ World_AreaAddEntsToPmove ( edict_t *ignore, areanode_t *node, vec3_t boxminmax[2 || boxminmax[1][2] < other->v.absmin[2] ) continue; - if (PROG_TO_EDICT(other->v.owner) == ignore) - continue; // don't clip against own missiles - if (PROG_TO_EDICT(ignore->v.owner) == other) - continue; // don't clip against owner + if (ignore) + { + if (PROG_TO_EDICT(other->v.owner) == ignore) + continue; // don't clip against own missiles + if (PROG_TO_EDICT(ignore->v.owner) == other) + continue; // don't clip against owner + } if (pmove.numphysent == countof(pmove.physents)) return; //too many... ooer. @@ -327,8 +330,13 @@ World_AreaAddEntsToPmove ( edict_t *ignore, areanode_t *node, vec3_t boxminmax[2 } void World_AddEntsToPmove(edict_t *ignore, vec3_t boxminmax[2]) { - pmove.skipent = NUM_FOR_EDICT(ignore); + if (ignore) + pmove.skipent = NUM_FOR_EDICT(ignore); pmove.physents[0].model = qcvm->worldmodel; + VectorClear(pmove.physents[0].origin); + VectorClear(pmove.physents[0].angles); + pmove.physents[0].forcecontentsmask = 0; + pmove.physents[0].info = 0; pmove.numphysent = 1; World_AreaAddEntsToPmove (ignore, qcvm->areanodes, boxminmax); diff --git a/Quake/zone.h b/Quake/zone.h index 393e322f..445cbb0f 100644 --- a/Quake/zone.h +++ b/Quake/zone.h @@ -89,6 +89,10 @@ Zone block */ +#ifdef __linux__ +//#include +#endif + void Memory_Init (void *buf, int size); void Z_Free (void *ptr);