extern cvar_t sv_gameplayfix_droptofloorstartsolid;
extern cvar_t sv_gameplayfix_findradiusdistancetobox;
extern cvar_t sv_gameplayfix_grenadebouncedownslopes;
+extern cvar_t sv_gameplayfix_multiplethinksperframe;
extern cvar_t sv_gameplayfix_noairborncorpse;
extern cvar_t sv_gameplayfix_qwplayerphysics;
extern cvar_t sv_gameplayfix_setmodelrealbox;
cvar_t sv_gameplayfix_droptofloorstartsolid = {0, "sv_gameplayfix_droptofloorstartsolid", "1", "prevents items and monsters that start in a solid area from falling out of the level (makes droptofloor treat trace_startsolid as an acceptable outcome)"};
cvar_t sv_gameplayfix_findradiusdistancetobox = {0, "sv_gameplayfix_findradiusdistancetobox", "1", "causes findradius to check the distance to the corner of a box rather than the center of the box, makes findradius detect bmodels such as very large doors that would otherwise be unaffected by splash damage"};
cvar_t sv_gameplayfix_grenadebouncedownslopes = {0, "sv_gameplayfix_grenadebouncedownslopes", "1", "prevents MOVETYPE_BOUNCE (grenades) from getting stuck when fired down a downward sloping surface"};
+cvar_t sv_gameplayfix_multiplethinksperframe = {0, "sv_gameplayfix_multiplethinksperframe", "1", "allows entities to think more often than the server framerate, primarily useful for very high fire rate weapons"};
cvar_t sv_gameplayfix_noairborncorpse = {0, "sv_gameplayfix_noairborncorpse", "1", "causes entities (corpses) sitting ontop of moving entities (players) to fall when the moving entity (player) is no longer supporting them"};
cvar_t sv_gameplayfix_qwplayerphysics = {0, "sv_gameplayfix_qwplayerphysics", "1", "changes water jumping to make it easier to get out of water, and prevents friction on landing when bunnyhopping"};
cvar_t sv_gameplayfix_setmodelrealbox = {0, "sv_gameplayfix_setmodelrealbox", "1", "fixes a bug in Quake that made setmodel always set the entity box to ('-16 -16 -16', '16 16 16') rather than properly checking the model box, breaks some poorly coded mods"};
Cvar_RegisterVariable (&sv_gameplayfix_droptofloorstartsolid);
Cvar_RegisterVariable (&sv_gameplayfix_findradiusdistancetobox);
Cvar_RegisterVariable (&sv_gameplayfix_grenadebouncedownslopes);
+ Cvar_RegisterVariable (&sv_gameplayfix_multiplethinksperframe);
Cvar_RegisterVariable (&sv_gameplayfix_noairborncorpse);
Cvar_RegisterVariable (&sv_gameplayfix_qwplayerphysics);
Cvar_RegisterVariable (&sv_gameplayfix_setmodelrealbox);
*/
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;
}