void Movetype_Physics_NoMatchTicrate(entity this, float movedt, bool isclient) // to be run every move frame
{
+ bool didmove = (this.move_time != 0);
this.move_time = time;
if(isclient)
_Movetype_Physics_ClientFrame(this, movedt);
else
+ {
+ // this doesn't apply to clients, and only applies to unmatched entities
+ // don't run think/move on newly spawned projectiles as it messes up
+ // movement interpolation and rocket trails, and is inconsistent with
+ // respect to entities spawned in the same frame
+ // (if an ent spawns a higher numbered ent, it moves in the same frame,
+ // but if it spawns a lower numbered ent, it doesn't - this never moves
+ // ents in the first frame regardless)
+ if(!didmove && GAMEPLAYFIX_DELAYPROJECTILES(this) > 0)
+ return;
_Movetype_Physics_Frame(this, movedt);
+ }
if(wasfreed(this))
return;
#define GAMEPLAYFIX_NOAIRBORNCORPSE(s) STAT(GAMEPLAYFIX_NOAIRBORNCORPSE)
#define NOAIRBORNCORPSE_ALLOWSUSPENDED(s) STAT(NOAIRBORNCORPSE_ALLOWSUSPENDED)
#define UPWARD_VELOCITY_CLEARS_ONGROUND(s) STAT(GAMEPLAYFIX_UPVELOCITYCLEARSONGROUND)
+#define GAMEPLAYFIX_DELAYPROJECTILES(s) STAT(GAMEPLAYFIX_DELAYPROJECTILES)
#define PHYS_STEPHEIGHT(s) STAT(MOVEVARS_STEPHEIGHT)
int autocvar_sv_gameplayfix_grenadebouncedownslopes = 1;
int autocvar_sv_gameplayfix_noairborncorpse = 1;
int autocvar_sv_gameplayfix_noairborncorpse_allowsuspendeditems = 1;
+int autocvar_sv_gameplayfix_delayprojectiles = 0;
#endif
REGISTER_STAT(GAMEPLAYFIX_DOWNTRACEONGROUND, int, autocvar_sv_gameplayfix_downtracesupportsongroundflag)
REGISTER_STAT(GAMEPLAYFIX_EASIERWATERJUMP, int, autocvar_sv_gameplayfix_easierwaterjump)
REGISTER_STAT(GAMEPLAYFIX_GRENADEBOUNCESLOPES, int, autocvar_sv_gameplayfix_grenadebouncedownslopes)
REGISTER_STAT(GAMEPLAYFIX_NOAIRBORNCORPSE, int, autocvar_sv_gameplayfix_noairborncorpse)
REGISTER_STAT(NOAIRBORNCORPSE_ALLOWSUSPENDED, int, autocvar_sv_gameplayfix_noairborncorpse_allowsuspendeditems)
+REGISTER_STAT(GAMEPLAYFIX_DELAYPROJECTILES, int, autocvar_sv_gameplayfix_delayprojectiles)
REGISTER_STAT(MOVEVARS_JUMPSTEP, int, cvar("sv_jumpstep"))
REGISTER_STAT(NOSTEP, int, cvar("sv_nostep"))
}
bool autocvar_sv_freezenonclients;
-bool autocvar_sv_gameplayfix_delayprojectiles = false;
void Physics_Frame()
{
if(autocvar_sv_freezenonclients)
IL_EACH(g_moveables, true,
{
- if(IS_CLIENT(it) || it.classname == "" || it.move_movetype == MOVETYPE_PHYSICS)
+ if(IS_CLIENT(it) || it.move_movetype == MOVETYPE_PHYSICS)
continue;
//set_movetype(it, it.move_movetype);
if(autocvar_sv_gameplayfix_delayprojectiles >= 0)
return;
+ // make a second pass to see if any ents spawned this frame and make
+ // sure they run their move/think. this is verified by checking .move_time, which will never be 0 if the entity has moved
IL_EACH(g_moveables, it.move_qcphysics,
{
- if(IS_CLIENT(it) || it.classname == "" || it.move_movetype == MOVETYPE_NONE)
+ if(IS_CLIENT(it) || it.move_time || it.move_movetype == MOVETYPE_NONE || it.move_movetype == MOVETYPE_PHYSICS)
continue;
Movetype_Physics_NoMatchTicrate(it, PHYS_INPUT_TIMELENGTH, false);
});