As many of you probably already know, MW3 no longer supports the lagometer. Simply setting "cg_drawlagometer 1" in your configuration file will do nothing. That's because they actually removed the entire code used to render the lagometer. Since I'm bored, I'll show you how I recreated the lagometer in MW3.
First off, I'll briefly explain some terms I'll be using in this tutorial.
- Lagometer - A lagometer is a display of network latency on an Internet connection and of rendering by the client.
- Interpolation - Interpolation is a method used to mathematically determine an approximation of a new set of information within a certain range. In simpler terms, it is used in games to "assume" where a player "will be" based on information received from the server/host. This tends to be more accurate in comparison to extrapolation.
- Extrapolation - Extrapolation, in contrast to interpolation, is a procedure used to approximate information OUTSIDE a specific range. Simplified, extrapolation is "assuming" where a player or entity is without actual "confirmation" from the server/host. The tendencies for a calculation to be wrong when extrapolation occurs is much greater than when interpolation of data is being used.
- Prediction Error - Though not often spoken about, a prediction error, is in simple terms, when the server/host "disagrees" with a client ( You ) about where or when a particular event occurred. This commonly occurs when information sent to the host/server doesn't arrive ( Lost packet ) or arrives too late ( Outside the set boundary limit ).
- Snapshot - A snapshot is a set of information or rather an "image" of the game's state ( I.E. Where players are, what they were doing, etc. ) at a particular time. This is of great importance in real-time multiplayer games due to events constantly occurring at a given time. Your game uses the snapshots to either interpolate or extrapolate your game's screen based on when the snapshot was generated. Extrapolation generally occurs if the host/server goes an extended period of time without successfully delivering a snapshot to a client. ( I.E Packet loss, ping latency etc. )
- Latency - Also known as ping, is the time it takes for your game to synchronize with the server. Generally speaking, it is the time it takes for you to send commands to the server and receive a response. The lower your latency, the smoother your gameplay will be.
The lagometer is broken up into two parts:
- Upper Graph - This indicates the client's rendering speed based on interpolation or extrapolation of game frames ( Your screen ). Commonly, blue is used to indicate interpolation is occurring while yellow is used to indicate extrapolation. The depth of the graph ( Seen below ) is how long it takes for you to render a frame. Shorter lines indicate a faster rendering speed.
- Lower Graph - This indicates your latency with the server as well as packet drop/loss ratios. Commonly green is used to indicate proper syncing with the server, yellow indicates a rate delay ( A snapshot has been held back by the server to avoid flooding your network ) and red indicates a packet has not been received by the server. ( Packet loss ) The height of the lower graph is directly proportional to your ping.
To properly construct this lagometer, you need to first understand how the game determines latency and interpolation/extrapolation of game frames.
- Upper Graph - The values in the upper graph are determined by calculating the current time the game is using to render its animation against the time a snapshot was last received from the server while taking into account prediction errors during rendering of the frame.
- Lower Graph - The values in the lower graph are determined by reading information from a given snapshot, determining if it valid and the time it took from sending your last command to the server against the time the snapshot arrived.
Using Quake 3 as a reference, I was able to add the lagometer to MW3 a few years ago. Here's how the structure which kept all the samples ( used to draw the lagometer ) looked:
So how are these values updated? Two functions are responsible. According to Quake, they are:Code:// This is the maximum number of samples the lagometer can collect before resetting. I used 128 for this. Quake uses 64. #define LAG_SAMPLES 64 typedef struct { // This contains the delta values ( Time difference ) between the current rendering time versus the last snapshot received time int frameSamples[LAG_SAMPLES]; // Holds the flag indicating the last frameSample active int frameCount; // Contains various snapshot flags from read snapshots used to determine if the server held back a snapshot due to rate boundaries ( Yellow Lines ) int snapshotFlags[LAG_SAMPLES]; // This holds the current ping calculated from the snapshot int snapshotSamples[LAG_SAMPLES]; int snapshotCount; } lagometer_t;
They are quite easy to read, in fact:
Where are these two functions called?Code:void CG_AddLagometerSnapshotInfo( snapshot_t *snap ) { // dropped packet -- I.E. An invalid snapshot was parsed. This means the server never received a message from the client. if ( !snap ) { lagometer.snapshotSamples[ lagometer.snapshotCount & ( LAG_SAMPLES - 1) ] = -1; lagometer.snapshotCount++; // Increment the current snapshot count. return; } // Based on cl_maxpackets, your lagometer MIGHT become inaccurate and simply have your snapshot's ping displayed as 999 // This is due to you sending more packets per second than you have slots in outPacket_t // To fix this, you must either reallocate the structure to fit the number of outgoing packets per second or apply a RATE_DELAYED flag to your snapshot // add this snapshot's info lagometer.snapshotSamples[ lagometer.snapshotCount & ( LAG_SAMPLES - 1) ] = snap->ping; lagometer.snapshotFlags[ lagometer.snapshotCount & ( LAG_SAMPLES - 1) ] = snap->snapFlags; lagometer.snapshotCount++; } void CG_AddLagometerFrameInfo( void ) { int offset; offset = cg.time - cg.latestSnapshotTime; lagometer.frameSamples[ lagometer.frameCount & ( LAG_SAMPLES - 1) ] = offset; lagometer.frameCount++; }
1.) CG_DrawActiveFrame() - This is easily found by looking at references to the quake3 source. Optionally, any scene rendering hook will work. ( Eg. Direct3D's EndScene() )
2.) CG_ReadNextSnapshot(). - Simply cross-reference the string "CG_ProcessSnapshots" to find where snapshots are processed. Referencing the quake source, you'll see CG_ReadNextSnapshot is the very next function called after Com_Error()
Finally, simply copy the CG_DrawLagometer() function from the Quake SDK and throw it in any rendering function you have. Voila.
P.S. MW3 still has the lagometer's shader so you can simply use that instead of drawing your own.
Here's mine:
Nice Tutorial Im Sure this will Help Many People
**DONT BOTHER TRYING**