/* ================== CL_DeltaEntity Parses deltas from the given base and adds the resulting entity to the current frame ================== */ void DeltaEntity(NetBuffer msg, clSnapshot_t frame, int newnum, Common.entityState_t old, bool unchanged) { // save the parsed entity state into the big circular buffer so // it can be used as the source for a later delta Common.entityState_t state = cl.parseEntities[cl.parseEntitiesNum & 2047]; if (unchanged) state = old; else Net.Instance.MSG_ReadDeltaEntity(msg, ref old, ref state, newnum); cl.parseEntities[cl.parseEntitiesNum & 2047] = state; if (state.number == 1023) return; // entity was delta removed cl.parseEntitiesNum++; frame.numEntities++; }
public clientActive() { gamestate = new gameState_t(); gamestate.data = new Dictionary<int, string>(); for (int i = 0; i < parseEntities.Length; i++) { parseEntities[i] = new Common.entityState_t(); } for (int i = 0; i < entityBaselines.Length; i++) { entityBaselines[i] = new Common.entityState_t(); } for (int i = 0; i < snapshots.Length; i++) { snapshots[i] = new clSnapshot_t(); } }
/* ================ CL_ParseSnapshot If the snapshot is parsed properly, it will be copied to cl.snap and saved in cl.snapshots[]. If the snapshot is invalid for any reason, no changes to the state will be made at all. ================ */ void ParseSnapshot(NetBuffer msg) { // read in the new snapshot to a temporary buffer // we will only copy to cl.snap if it is valid clSnapshot_t newsnap = new clSnapshot_t(); clSnapshot_t old; // we will have read any new server commands in this // message before we got to svc_snapshot newsnap.ServerCommandNum = clc.serverCommandSequence; newsnap.serverTime = msg.ReadInt32(); newsnap.messageNum = clc.serverMessageSequence; int deltaNum = msg.ReadByte(); if (deltaNum <= 0) { newsnap.deltaNum = -1; } else newsnap.deltaNum = newsnap.messageNum - deltaNum; newsnap.snapFlags = msg.ReadByte(); // If the frame is delta compressed from data that we // no longer have available, we must suck up the rest of // the frame, but not use it, then ask for a non-compressed // message if (newsnap.deltaNum <= 0) { newsnap.valid = true; // uncompressed frame old = null; } else { old = cl.snapshots[newsnap.deltaNum & 31]; if (!old.valid) { // should never happen Common.Instance.WriteLine("ParseSnapshot: Delta from invalid frame (not supposed to happen!)."); } else if (old.messageNum != newsnap.deltaNum) { // The frame that the server did the delta from // is too old, so we can't reconstruct it properly. Common.Instance.WriteLine("ParseSnapshot: Delta frame too old."); } else if (cl.parseEntitiesNum - old.parseEntitiesNum > 2048 - 128) { Common.Instance.WriteLine("ParseSnapshot: Delta parseEntitiesNum too old"); } else newsnap.valid = true; // valid delta parse } // read areamask int len = msg.ReadByte(); newsnap.areamask = msg.ReadBytes(32); // read playerinfo if (old != null) { Net.ReadDeltaPlayerstate(msg, old.ps, newsnap.ps); } else Net.ReadDeltaPlayerstate(msg, null, newsnap.ps); // read packet entities ParsePacketEntities(msg, old, newsnap); // if not valid, dump the entire thing now that it has // been properly read if (!newsnap.valid) return; // clear the valid flags of any snapshots between the last // received and this one, so if there was a dropped packet // it won't look like something valid to delta from next // time we wrap around in the buffer int oldMessageNum = cl.snap.messageNum + 1; if (newsnap.messageNum - oldMessageNum >= 32) { oldMessageNum = newsnap.messageNum - 31; } for (; oldMessageNum < newsnap.messageNum; oldMessageNum++ ) { cl.snapshots[oldMessageNum & 31].valid = false; } // copy to the current good spot cl.snap = newsnap; cl.snap.ping = 999; // calculate ping time for (int i = 0; i < 32; i++) { int packetNum = (clc.netchan.outgoingSequence - 1 - i) & 31; if (cl.snap.ps.commandTime >= cl.outPackets[packetNum].p_serverTime) { cl.snap.ping = realtime - cl.outPackets[packetNum].p_realtime; break; } } // save the frame off in the backup array for later delta comparisons cl.snapshots[cl.snap.messageNum & 31] = cl.snap; //Common.Instance.WriteLine(" Snapshot:{0} delta:{1} ping:{2}", cl.snap.messageNum, cl.snap.deltaNum, cl.snap.ping); cl.newSnapshots = true; }
void ParsePacketEntities(NetBuffer msg, clSnapshot_t oldframe, clSnapshot_t newframe) { newframe.parseEntitiesNum = cl.parseEntitiesNum; newframe.numEntities = 0; // delta from the entities present in oldframe int oldindex = 0, oldnum = 0; Common.entityState_t oldstate = null; if (oldframe == null) oldnum = 99999; else { if (oldnum >= oldframe.numEntities) oldnum = 99999; else { oldstate = cl.parseEntities[(oldframe.parseEntitiesNum + oldindex) & 2047]; oldnum = oldstate.number; } } while (true) { // read the entity index number int newnum = msg.ReadInt32(); if (newnum == 1023) break; while (oldnum < newnum) { // one or more entities from the old packet are unchanged DeltaEntity(msg, newframe, oldnum, oldstate, true); oldindex++; if (oldindex >= oldframe.numEntities) oldnum = 99999; else { oldstate = cl.parseEntities[(oldframe.parseEntitiesNum + oldindex) & 2047]; oldnum = oldstate.number; } } if (oldnum == newnum) { // delta from previous state DeltaEntity(msg, newframe, newnum, oldstate, false); oldindex++; if (oldindex >= oldframe.numEntities) oldnum = 99999; else { oldstate = cl.parseEntities[(oldframe.parseEntitiesNum + oldindex) & 2047]; oldnum = oldstate.number; } continue; } if (oldnum > newnum) { // delta from baseline DeltaEntity(msg, newframe, newnum, cl.entityBaselines[newnum], false); continue; } } // any remaining entities in the old frame are copied over while (oldnum != 99999) { // one or more entities from the old packet are unchanged DeltaEntity(msg, newframe, oldnum, oldstate, true); oldindex++; if (oldindex >= oldframe.numEntities) oldnum = 99999; else { oldstate = cl.parseEntities[(oldframe.parseEntitiesNum + oldindex) & 2047]; oldnum = oldstate.number; } } }