Skip to content
This repository was archived by the owner on Sep 22, 2021. It is now read-only.

Commit 448ce15

Browse files
committed
Parser can now attempt to fix corrupted headers
1 parent 0880b11 commit 448ce15

File tree

3 files changed

+162
-11
lines changed

3 files changed

+162
-11
lines changed

DemoInfo/DP/FastNetmessages/ServerInfo.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ public void Parse(IBitStream bitstream, DemoParser parser)
3939
if (wireType == 5) {
4040
if (fieldnum == 14){
4141
TickInterval = bitstream.ReadFloat();
42+
parser.TickInterval = TickInterval;
4243
}
4344
else {
4445
var val = bitstream.ReadInt(32);

DemoInfo/DemoParser.cs

Lines changed: 157 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -272,9 +272,12 @@ public IEnumerable<Player> PlayingParticipants {
272272
/// <summary>
273273
/// The stream of the demo - all the information go here
274274
/// </summary>
275-
private readonly IBitStream BitStream;
276-
275+
private IBitStream BitStream;
277276

277+
/// <summary>
278+
/// The file stream read by BitStream
279+
/// </summary>
280+
private Stream Input;
278281

279282
/// <summary>
280283
/// A parser for DataTables. This contains the ServerClasses and DataTables.
@@ -432,15 +435,21 @@ public string TFlag
432435
/// </summary>
433436
/// <value>The tick rate.</value>
434437
public float TickRate {
435-
get { return 1 / ServerInfo.TickInterval; }
438+
get { return this.Header.PlaybackFrames / this.Header.PlaybackTime; }
436439
}
437440

441+
/// <summary>
442+
/// Used to impute header time values when they're corrupted
443+
/// TickInterval = 1/TickRate
444+
/// </summary>
445+
internal float TickInterval;
446+
438447
/// <summary>
439448
/// How long a tick of the demo is in s^-1
440449
/// </summary>
441450
/// <value>The tick time.</value>
442451
public float TickTime {
443-
get { return ServerInfo.TickInterval; }
452+
get { return this.Header.PlaybackTime / this.Header.PlaybackFrames;}
444453
}
445454

446455
/// <summary>
@@ -463,6 +472,11 @@ public float ParsingProgess {
463472
/// <value>The current tick.</value>
464473
public int CurrentTick { get; private set; }
465474

475+
/// <summary>
476+
/// The CurrentTick for the last tick where IngameTick == 0
477+
/// </summary>
478+
private int TickAtStart;
479+
466480
/// <summary>
467481
/// The current ingame-tick as reported by the demo-file.
468482
/// </summary>
@@ -488,6 +502,8 @@ public float ParsingProgess {
488502
/// <param name="input">An input-stream.</param>
489503
public DemoParser(Stream input)
490504
{
505+
Input = input;
506+
491507
BitStream = BitStreamUtil.Create(input);
492508

493509
for (int i = 0; i < MAXPLAYERS; i++) {
@@ -512,10 +528,143 @@ public void ParseHeader()
512528

513529
Header = header;
514530

515-
516531
if (HeaderParsed != null)
517532
HeaderParsed(this, new HeaderParsedEventArgs(Header));
518-
}
533+
534+
if (header.PlaybackTime == 0) //header is corrupted
535+
FixHeader();
536+
}
537+
538+
void FixHeader()
539+
{
540+
ExpressParseToEnd();
541+
Header.PlaybackTicks = IngameTick;
542+
Header.PlaybackFrames = CurrentTick - (TickAtStart + 1);
543+
Header.PlaybackTime = TickInterval * IngameTick;
544+
545+
CurrentTick = 0;
546+
547+
//the ol' switcheroo
548+
//It's probably safest and easiest to
549+
//swap out for a fresh bitstream.
550+
Input.Seek(0, System.IO.SeekOrigin.Begin);
551+
BitStream = BitStreamUtil.Create(Input);
552+
//Put the new stream back at the end of the header
553+
ExpressParseHeader(BitStream);
554+
}
555+
556+
//These express functions mirror functions without the express prefix,
557+
//but all they do is read ticks and get ServerInfo. They do not parse
558+
//data from any other packets.
559+
void ExpressParseToEnd()
560+
{
561+
while (true)
562+
{
563+
try
564+
{
565+
if (!ExpressParseTick())
566+
break;
567+
}
568+
catch (System.IO.EndOfStreamException)
569+
{
570+
break;
571+
}
572+
}
573+
}
574+
575+
576+
bool ExpressParseTick()
577+
{
578+
DemoCommand command = (DemoCommand)BitStream.ReadByte();
579+
580+
IngameTick = (int)BitStream.ReadInt(32); // tick number
581+
582+
if (IngameTick == 0)
583+
TickAtStart = CurrentTick;
584+
585+
BitStream.ReadByte(); // player slot
586+
587+
this.CurrentTick++; // = TickNum;
588+
589+
switch (command)
590+
{
591+
case DemoCommand.Synctick:
592+
break;
593+
case DemoCommand.Stop:
594+
return false;
595+
case DemoCommand.ConsoleCommand:
596+
BitStream.BeginChunk(BitStream.ReadSignedInt(32) * 8);
597+
BitStream.EndChunk();
598+
break;
599+
case DemoCommand.DataTables:
600+
BitStream.BeginChunk(BitStream.ReadSignedInt(32) * 8);
601+
BitStream.EndChunk();
602+
break;
603+
case DemoCommand.StringTables:
604+
BitStream.BeginChunk(BitStream.ReadSignedInt(32) * 8);
605+
BitStream.EndChunk();
606+
break;
607+
case DemoCommand.UserCommand:
608+
BitStream.ReadInt(32);
609+
BitStream.BeginChunk(BitStream.ReadSignedInt(32) * 8);
610+
BitStream.EndChunk();
611+
break;
612+
case DemoCommand.Signon:
613+
case DemoCommand.Packet:
614+
ExpressParseDemoPacket();
615+
break;
616+
default:
617+
throw new Exception("Can't handle Demo-Command " + command);
618+
}
619+
620+
return true;
621+
}
622+
623+
void ExpressParseDemoPacket()
624+
{
625+
//Read a command-info. Contains no really useful information afaik.
626+
CommandInfo.Parse(BitStream);
627+
BitStream.ReadInt(32); // SeqNrIn
628+
BitStream.ReadInt(32); // SeqNrOut
629+
630+
BitStream.BeginChunk(BitStream.ReadSignedInt(32) * 8);
631+
ExpressParsePacket(BitStream, this);
632+
BitStream.EndChunk();
633+
}
634+
635+
void ExpressParsePacket(IBitStream bitstream, DemoParser demo)
636+
{
637+
while (!bitstream.ChunkFinished)
638+
{
639+
int cmd = bitstream.ReadProtobufVarInt(); //What type of packet is this?
640+
int length = bitstream.ReadProtobufVarInt(); //And how long is it?
641+
bitstream.BeginChunk(length * 8); //read length bytes
642+
if (cmd == (int)SVC_Messages.svc_ServerInfo)
643+
{
644+
new ServerInfo().Parse(bitstream, demo);
645+
}
646+
bitstream.EndChunk();
647+
}
648+
}
649+
650+
void ExpressParseHeader(IBitStream reader)
651+
{
652+
var MAX_OSPATH = DemoHeader.MAX_OSPATH;
653+
654+
reader.ReadCString(8);
655+
reader.ReadSignedInt(32);
656+
reader.ReadSignedInt(32);
657+
reader.ReadCString(MAX_OSPATH);
658+
659+
reader.ReadCString(MAX_OSPATH);
660+
reader.ReadCString(MAX_OSPATH);
661+
reader.ReadCString(MAX_OSPATH);
662+
reader.ReadFloat();
663+
664+
reader.ReadSignedInt(32);
665+
reader.ReadSignedInt(32);
666+
reader.ReadSignedInt(32);
667+
}
519668

520669
/// <summary>
521670
/// Parses this file until the end of the demo is reached.
@@ -599,6 +748,7 @@ private bool ParseTick()
599748
DemoCommand command = (DemoCommand)BitStream.ReadByte();
600749

601750
IngameTick = (int)BitStream.ReadInt(32); // tick number
751+
602752
BitStream.ReadByte(); // player slot
603753

604754
this.CurrentTick++; // = TickNum;
@@ -652,7 +802,7 @@ private void ParseDemoPacket()
652802
{
653803
//Read a command-info. Contains no really useful information afaik.
654804
CommandInfo.Parse(BitStream);
655-
BitStream.ReadInt(32); // SeqNrIn
805+
uint seqin = BitStream.ReadInt(32); // SeqNrIn
656806
BitStream.ReadInt(32); // SeqNrOut
657807

658808
BitStream.BeginChunk(BitStream.ReadSignedInt(32) * 8);

DemoInfo/Structs.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ namespace DemoInfo
1212
/// </summary>
1313
public class DemoHeader
1414
{
15-
const int MAX_OSPATH = 260;
15+
internal const int MAX_OSPATH = 260;
1616

1717
public string Filestamp { get; private set; } // Should be HL2DEMO
1818
public int Protocol { get; private set; } // Should be DEMO_PROTOCOL (4)
@@ -30,9 +30,9 @@ public int NetworkProtocal {
3030
public string ClientName { get; private set; } // Name of client who recorded the game
3131
public string MapName { get; private set; } // Name of map
3232
public string GameDirectory { get; private set; } // Name of game directory (com_gamedir)
33-
public float PlaybackTime { get; private set; } // Time of track
34-
public int PlaybackTicks { get; private set; } // # of ticks in track
35-
public int PlaybackFrames { get; private set; } // # of frames in track
33+
public float PlaybackTime { get; set; } // Time of track
34+
public int PlaybackTicks { get; set; } // # of ticks in track
35+
public int PlaybackFrames { get; set; } // # of frames in track
3636
public int SignonLength { get; private set; } // length of sigondata in bytes
3737

3838
public static DemoHeader ParseFrom(IBitStream reader)

0 commit comments

Comments
 (0)