// decide the simulation time
if (cls.capturevideo.active)
{
+ //***
if (cls.capturevideo.realtime)
clframetime = cl.realframetime = max(cl_timer, 1.0 / cls.capturevideo.framerate);
else
cl.oldtime = cl.time;
cl.time += clframetime;
+ // update video
+ if (host_speeds.integer)
+ time1 = Sys_DoubleTime();
+
// Collect input into cmd
CL_Input();
// update client world (interpolate entities, create trails, etc)
CL_UpdateWorld();
- // update video
- if (host_speeds.integer)
- time1 = Sys_DoubleTime();
-
CL_Video_Frame();
CL_Gecko_Frame();
}
-void EntityFrameQuake_WriteFrame(sizebuf_t *msg, int maxsize, int numstates, const entity_state_t *states)
+qboolean EntityFrameQuake_WriteFrame(sizebuf_t *msg, int maxsize, int numstates, const entity_state_t *states)
{
const entity_state_t *s;
entity_state_t baseline;
sizebuf_t buf;
unsigned char data[128];
prvm_eval_t *val;
+ qboolean success = false;
// prepare the buffer
memset(&buf, 0, sizeof(buf));
}
// write the message to the packet
SZ_Write(msg, buf.data, buf.cursize);
+ success = true;
ENTITYSIZEPROFILING_END(msg, s->number);
}
+ return success;
}
int EntityState_DeltaBits(const entity_state_t *o, const entity_state_t *n)
}
// (server) writes a frame to network stream
-void EntityFrame_WriteFrame(sizebuf_t *msg, int maxsize, entityframe_database_t *d, int numstates, const entity_state_t *states, int viewentnum)
+qboolean EntityFrame_WriteFrame(sizebuf_t *msg, int maxsize, entityframe_database_t *d, int numstates, const entity_state_t *states, int viewentnum)
{
int i, onum, number;
entity_frame_t *o = &d->deltaframe;
val = PRVM_EDICTFIELDVALUE((&prog->edicts[number]), prog->fieldoffsets.SendEntity);
if(val && val->function)
- continue;
+ continue;
for (;onum < o->numentities && o->entitydata[onum].number < number;onum++)
{
// write remove message
MSG_WriteShort(msg, o->entitydata[onum].number | 0x8000);
}
MSG_WriteShort(msg, 0xFFFF);
+
+ return true;
}
// (client) reads a frame from network stream
EntityFrame4_ResetDatabase(d);
}
-void EntityFrame4_WriteFrame(sizebuf_t *msg, int maxsize, entityframe4_database_t *d, int numstates, const entity_state_t *states)
+qboolean EntityFrame4_WriteFrame(sizebuf_t *msg, int maxsize, entityframe4_database_t *d, int numstates, const entity_state_t *states)
{
const entity_state_t *e, *s;
entity_state_t inactiveentitystate;
// if there isn't enough space to accomplish anything, skip it
if (msg->cursize + 24 > maxsize)
- return;
+ return false;
// prepare the buffer
memset(&buf, 0, sizeof(buf));
break;
// if commit buffer full, just don't bother writing an update this frame
if (i == MAX_ENTITY_HISTORY)
- return;
+ return false;
d->currentcommit = d->commit + i;
// this state's number gets played around with later
MSG_WriteShort(msg, d->currententitynumber);
// just to be sure
d->currentcommit = NULL;
+
+ return true;
}
d->packetlog[i].packetnumber = 0;
}
-void EntityFrame5_WriteFrame(sizebuf_t *msg, int maxsize, entityframe5_database_t *d, int numstates, const entity_state_t *states, int viewentnum, int movesequence, qboolean need_empty)
+qboolean EntityFrame5_WriteFrame(sizebuf_t *msg, int maxsize, entityframe5_database_t *d, int numstates, const entity_state_t *states, int viewentnum, int movesequence, qboolean need_empty)
{
const entity_state_t *n;
int i, num, l, framenum, packetlognumber, priority;
// if there isn't at least enough room for an empty svc_entities,
// don't bother trying...
if (buf.cursize + 11 > buf.maxsize)
- return;
+ return false;
// build lists of entities by priority level
memset(d->prioritychaincounts, 0, sizeof(d->prioritychaincounts));
// only send empty svc_entities frame if needed
if(!l && !need_empty)
- return;
+ return false;
// add packetlog entry now that we have something for it
if (!packetlog)
}
}
MSG_WriteShort(msg, 0x8000);
+
+ return true;
}
void Protocol_WriteStatsReliable(void);
// writes a list of quake entities to the network stream
// (or as many will fit)
-void EntityFrameQuake_WriteFrame(sizebuf_t *msg, int maxsize, int numstates, const entity_state_t *states);
+qboolean EntityFrameQuake_WriteFrame(sizebuf_t *msg, int maxsize, int numstates, const entity_state_t *states);
// cleans up dead entities each frame after ReadEntity (which doesn't clear unused entities)
void EntityFrameQuake_ISeeDeadEntities(void);
// reference
void EntityFrame_AddFrame(entityframe_database_t *d, vec3_t eye, int framenum, int numentities, const entity_state_t *entitydata);
// (server) writes a frame to network stream
-void EntityFrame_WriteFrame(sizebuf_t *msg, int maxsize, entityframe_database_t *d, int numstates, const entity_state_t *states, int viewentnum);
+qboolean EntityFrame_WriteFrame(sizebuf_t *msg, int maxsize, entityframe_database_t *d, int numstates, const entity_state_t *states, int viewentnum);
// (client) reads a frame from network stream
void EntityFrame_CL_ReadFrame(void);
// (client) returns the frame number of the most recent frame recieved
// updates database to account for a frame-received acknowledgment
int EntityFrame4_AckFrame(entityframe4_database_t *d, int framenum, int servermode);
// writes a frame to the network stream
-void EntityFrame4_WriteFrame(sizebuf_t *msg, int maxsize, entityframe4_database_t *d, int numstates, const entity_state_t *states);
+qboolean EntityFrame4_WriteFrame(sizebuf_t *msg, int maxsize, entityframe4_database_t *d, int numstates, const entity_state_t *states);
// reads a frame from the network stream
void EntityFrame4_CL_ReadFrame(void);
void EntityFrame5_CL_ReadFrame(void);
void EntityFrame5_LostFrame(entityframe5_database_t *d, int framenum);
void EntityFrame5_AckFrame(entityframe5_database_t *d, int framenum);
-void EntityFrame5_WriteFrame(sizebuf_t *msg, int maxsize, entityframe5_database_t *d, int numstates, const entity_state_t *states, int viewentnum, int movesequence, qboolean need_empty);
+qboolean EntityFrame5_WriteFrame(sizebuf_t *msg, int maxsize, entityframe5_database_t *d, int numstates, const entity_state_t *states, int viewentnum, int movesequence, qboolean need_empty);
extern cvar_t developer_networkentities;
/// demo recording
qfile_t *sv_demo_file;
+
+ // number of skipped entity frames
+ // if it exceeds a limit, an empty entity frame is sent
+ int num_skippedentityframes;
} client_t;
int i, numsendstates;
entity_state_t *s;
prvm_edict_t *camera;
+ qboolean success;
// if there isn't enough space to accomplish anything, skip it
if (msg->cursize + 25 > maxsize)
else
EntityFrameCSQC_WriteFrame(msg, maxsize, numsendstates, sv.writeentitiestoclient_sendstates, 0);
+ if(client->num_skippedentityframes >= 5)
+ need_empty = true; // force every 5th frame to be not empty (or cl_movement replay takes too long)
+
if (client->entitydatabase5)
- EntityFrame5_WriteFrame(msg, maxsize, client->entitydatabase5, numsendstates, sv.writeentitiestoclient_sendstates, client - svs.clients + 1, client->movesequence, need_empty);
+ success = EntityFrame5_WriteFrame(msg, maxsize, client->entitydatabase5, numsendstates, sv.writeentitiestoclient_sendstates, client - svs.clients + 1, client->movesequence, need_empty);
else if (client->entitydatabase4)
{
- EntityFrame4_WriteFrame(msg, maxsize, client->entitydatabase4, numsendstates, sv.writeentitiestoclient_sendstates);
+ success = EntityFrame4_WriteFrame(msg, maxsize, client->entitydatabase4, numsendstates, sv.writeentitiestoclient_sendstates);
Protocol_WriteStatsReliable();
}
else if (client->entitydatabase)
{
- EntityFrame_WriteFrame(msg, maxsize, client->entitydatabase, numsendstates, sv.writeentitiestoclient_sendstates, client - svs.clients + 1);
+ success = EntityFrame_WriteFrame(msg, maxsize, client->entitydatabase, numsendstates, sv.writeentitiestoclient_sendstates, client - svs.clients + 1);
Protocol_WriteStatsReliable();
}
else
{
- EntityFrameQuake_WriteFrame(msg, maxsize, numsendstates, sv.writeentitiestoclient_sendstates);
+ success = EntityFrameQuake_WriteFrame(msg, maxsize, numsendstates, sv.writeentitiestoclient_sendstates);
Protocol_WriteStatsReliable();
}
+
+ if(success)
+ client->num_skippedentityframes = 0;
+ else
+ ++client->num_skippedentityframes;
}
/*