private void parseGameState(Q3HuffmanReader reader) { reader.readLong(); while (true) { byte cmd = reader.readByte(); if (cmd == Q3_SVC.EOF) { break; } switch (cmd) { case Q3_SVC.CONFIGSTRING: short key = reader.readShort(); if (key < 0 || key > Q3Const.MAX_CONFIGSTRINGS) { return; } clc.configs[key] = reader.readBigString(); break; case Q3_SVC.BASELINE: long newnum = reader.readNumBits(Q3Const.GENTITYNUM_BITS); if (newnum < 0 || newnum >= Q3Const.MAX_GENTITIES) { Q3Utils.PrintDebug(clc.errors, "Baseline number out of range: {0}", newnum); return; } EntityState es = Ext2 <long, EntityState> .GetOrCreate(clc.entityBaselines, newnum); if (!reader.readDeltaEntity(es, (int)newnum)) { Q3Utils.PrintDebug(clc.errors, "unable to parse delta-entity state"); return; } break; default: Q3Utils.PrintDebug(clc.errors, "bad command in parseGameState"); return; } } //clc.clientNum clc.clientNum = reader.readLong(); //clc.checksumFeed clc.checksumFeed = reader.readLong(); }
public bool parse(Q3DemoMessage message) { clc.serverMessageSequence = message.sequence; Q3HuffmanReader reader = new Q3HuffmanReader(message.data); reader.readLong(); while (!reader.isEOD()) { var b = reader.readByte(); switch (b) { case Q3_SVC.BAD: case Q3_SVC.NOP: return(true); case Q3_SVC.EOF: return(true); case Q3_SVC.SERVERCOMMAND: this.parseServerCommand(reader); break; case Q3_SVC.GAMESTATE: this.parseGameState(reader); break; case Q3_SVC.SNAPSHOT: this.parseSnapshot(reader); // snapshots couldn't be mixed with game-state command in a single message break; default: // unknown command / corrupted stream return(true); } } return(true); }
private void parseSnapshot(Q3HuffmanReader decoder) { if (client.clientConfig == null) { client.clientConfig = new Dictionary <string, string>(); if (clc.configs.ContainsKey(Q3Const.Q3_DEMO_CFG_FIELD_GAME)) { var gameConfig = Q3Utils.split_config(clc.configs[Q3Const.Q3_DEMO_CFG_FIELD_GAME]); client.isCheatsOn = Ext.GetOrZero(gameConfig, "sv_cheats") > 0; } if (clc.configs.ContainsKey(Q3Const.Q3_DEMO_CFG_FIELD_CLIENT)) { client.clientConfig = Q3Utils.split_config(clc.configs[Q3Const.Q3_DEMO_CFG_FIELD_CLIENT]); client.dfvers = Ext.GetOrZero(client.clientConfig, "defrag_vers"); client.mapname = Ext.GetOrNull(client.clientConfig, "mapname"); client.mapNameChecksum = getMapNameChecksum(client.mapname); client.isOnline = Ext.GetOrZero(client.clientConfig, "defrag_gametype") > 4; } } CLSnapshot newSnap = new CLSnapshot(); CLSnapshot old = null; newSnap.serverCommandNum = clc.serverCommandSequence; newSnap.serverTime = decoder.readLong(); newSnap.messageNum = clc.serverMessageSequence; int deltaNum = decoder.readByte(); if (deltaNum == 0) { newSnap.deltaNum = -1; } else { newSnap.deltaNum = newSnap.messageNum - deltaNum; } newSnap.snapFlags = decoder.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; clc.demowaiting = false; // we can start recording now } else { old = Ext2 <int, CLSnapshot> .GetOrCreate(client.snapshots, newSnap.deltaNum& Q3Const.PACKET_MASK); if (old == null || !old.valid) { // should never happen Q3Utils.PrintDebug(clc.errors, "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. Q3Utils.PrintDebug(clc.errors, "Delta frame too old."); } else if ((client.parseEntitiesNum - old.parseEntitiesNum) > (Q3Const.MAX_PARSE_ENTITIES - 128)) { Q3Utils.PrintDebug(clc.errors, "Delta parseEntitiesNum too old"); } else { newSnap.valid = true; // valid delta parse } } int len = decoder.readByte(); if (len > newSnap.areamask.Length) { Q3Utils.PrintDebug(clc.errors, "CL_ParseSnapshot: Invalid size {0} for areamask", len); return; } decoder.readData(newSnap.areamask, len); if (old != null) { newSnap.ps.copy(old.ps); } decoder.readDeltaPlayerState(newSnap.ps); parsePacketEntities(decoder, 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 = client.snap.messageNum + 1; if (newSnap.messageNum - oldMessageNum >= Q3Const.PACKET_BACKUP) { oldMessageNum = newSnap.messageNum - (Q3Const.PACKET_BACKUP - 1); } for (; oldMessageNum < newSnap.messageNum; oldMessageNum++) { CLSnapshot s; if (client.snapshots.TryGetValue(oldMessageNum & Q3Const.PACKET_MASK, out s)) { if (s != null) { s.valid = false; } } } // copy to the current good spot client.snap = newSnap; // skip ping calculations client.snap.ping = 0; // save the frame off in the backup array for later delta comparisons client.snapshots[client.snap.messageNum & Q3Const.PACKET_MASK] = client.snap; client.newSnapshots = true; updateClientEvents(newSnap); }
public static void updateEntityState(EntityState state, int number, Q3HuffmanReader reader, bool reset) { switch (number) { case 0: state.pos.trTime = reset ? 0 : reader.readLong(); break; case 1: state.pos.trBase[0] = reset ? 0 : reader.readFloatIntegral(); break; case 2: state.pos.trBase[1] = reset ? 0 : reader.readFloatIntegral(); break; case 3: state.pos.trDelta[0] = reset ? 0 : reader.readFloatIntegral(); break; case 4: state.pos.trDelta[1] = reset ? 0 : reader.readFloatIntegral(); break; case 5: state.pos.trBase[2] = reset ? 0 : reader.readFloatIntegral(); break; case 6: state.apos.trBase[1] = reset ? 0 : reader.readFloatIntegral(); break; case 7: state.pos.trDelta[2] = reset ? 0 : reader.readFloatIntegral(); break; case 8: state.apos.trBase[0] = reset ? 0 : reader.readFloatIntegral(); break; case 9: state.events = reset ? 0 : (int)reader.readNumBits(10); break; case 10: state.angles2[1] = reset ? 0 : reader.readFloatIntegral(); break; case 11: state.eType = reset ? 0 : (int)reader.readNumBits(8); break; case 12: state.torsoAnim = reset ? 0 : (int)reader.readNumBits(8); break; case 13: state.eventParm = reset ? 0 : (int)reader.readNumBits(8); break; case 14: state.legsAnim = reset ? 0 : (int)reader.readNumBits(8); break; case 15: state.groundEntityNum = reset ? 0 : (int)reader.readNumBits(10); break; case 16: state.pos.trType = reset ? 0 : (TrType)reader.readByte(); break; case 17: state.eFlags = reset ? 0 : (int)reader.readNumBits(19); break; case 18: state.otherEntityNum = reset ? 0 : (int)reader.readNumBits(10); break; case 19: state.weapon = reset ? 0 : (int)reader.readNumBits(8); break; case 20: state.clientNum = reset ? 0 : (int)reader.readNumBits(8); break; case 21: state.angles[1] = reset ? 0 : reader.readFloatIntegral(); break; case 22: state.pos.trDuration = reset ? 0 : reader.readLong(); break; case 23: state.apos.trType = reset ? 0 : (TrType)reader.readByte(); break; case 24: state.origin[0] = reset ? 0 : reader.readFloatIntegral(); break; case 25: state.origin[1] = reset ? 0 : reader.readFloatIntegral(); break; case 26: state.origin[2] = reset ? 0 : reader.readFloatIntegral(); break; case 27: state.solid = reset ? 0 : (int)reader.readNumBits(24); break; case 28: state.powerups = reset ? 0 : (int)reader.readNumBits(16); break; case 29: state.modelindex = reset ? 0 : (int)reader.readNumBits(8); break; case 30: state.otherEntityNum2 = reset ? 0 : (int)reader.readNumBits(10); break; case 31: state.loopSound = reset ? 0 : (int)reader.readNumBits(8); break; case 32: state.generic1 = reset ? 0 : (int)reader.readNumBits(8); break; case 33: state.origin2[2] = reset ? 0 : reader.readFloatIntegral(); break; case 34: state.origin2[0] = reset ? 0 : reader.readFloatIntegral(); break; case 35: state.origin2[1] = reset ? 0 : reader.readFloatIntegral(); break; case 36: state.modelindex2 = reset ? 0 : (int)reader.readNumBits(8); break; case 37: state.angles[0] = reset ? 0 : reader.readFloatIntegral(); break; case 38: state.time = reset ? 0 : reader.readLong(); break; case 39: state.apos.trTime = reset ? 0 : reader.readLong(); break; case 40: state.apos.trDuration = reset ? 0 : reader.readLong(); break; case 41: state.apos.trBase[2] = reset ? 0 : reader.readFloatIntegral(); break; case 42: state.apos.trDelta[0] = reset ? 0 : reader.readFloatIntegral(); break; case 43: state.apos.trDelta[1] = reset ? 0 : reader.readFloatIntegral(); break; case 44: state.apos.trDelta[2] = reset ? 0 : reader.readFloatIntegral(); break; case 45: state.time2 = reset ? 0 : reader.readLong(); break; case 46: state.angles[2] = reset ? 0 : reader.readFloatIntegral(); break; case 47: state.angles2[0] = reset ? 0 : reader.readFloatIntegral(); break; case 48: state.angles2[2] = reset ? 0 : reader.readFloatIntegral(); break; case 49: state.constantLight = reset ? 0 : reader.readLong(); break; case 50: state.frame = reset ? 0 : (int)reader.readNumBits(16); break; } }