Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ability to read tick-by-tick with StartReadingAsync and MoveNextAsync #32

Merged
merged 8 commits into from
Dec 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ internal class Program
Console.WriteLine($"{e.Attacker?.PlayerName} [{e.Weapon}] {e.Player?.PlayerName}");
};

await demo.Start(File.OpenRead(path));
await demo.ReadAllAsync(File.OpenRead(path));

Console.WriteLine("\nFinished!");
}
Expand Down
6 changes: 6 additions & 0 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
### 0.8.1 (2023-12-30)

- BREAKING CHANGE: `DemoParser.Start` is now `DemoParser.ReadAllAsync`
- Added ability to read tick-by-tick with `DemoParser.StartReadingAsync` and `DemoParser.MoveNextAsync`
- Added comparison operators to `DemoTick` and `GameTick`

### 0.7.1 (2023-12-23)

- Read CDemoFileInfo in seekable streams (available on complete demo recordings only)
Expand Down
7 changes: 7 additions & 0 deletions demofile-net.sln
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DemoFile.Example.Inventory"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DemoFile.GameStaticGen", "src\DemoFile.GameStaticGen\DemoFile.GameStaticGen.csproj", "{40A1ECD4-3817-4618-906C-8EC0F3E7120A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DemoFile.Example.TickByTick", "examples\DemoFile.Example.TickByTick\DemoFile.Example.TickByTick.csproj", "{2C6DF000-2878-454F-8C4C-0EB68E3C2B3A}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -80,11 +82,16 @@ Global
{40A1ECD4-3817-4618-906C-8EC0F3E7120A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{40A1ECD4-3817-4618-906C-8EC0F3E7120A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{40A1ECD4-3817-4618-906C-8EC0F3E7120A}.Release|Any CPU.Build.0 = Release|Any CPU
{2C6DF000-2878-454F-8C4C-0EB68E3C2B3A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2C6DF000-2878-454F-8C4C-0EB68E3C2B3A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2C6DF000-2878-454F-8C4C-0EB68E3C2B3A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2C6DF000-2878-454F-8C4C-0EB68E3C2B3A}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{C2452138-91E4-4160-B051-A201080C1953} = {20EAA685-6916-4B0C-8D0C-E407B072E28F}
{1A0CF2C7-AE27-4BB7-8BE0-A35DDEF6CBBA} = {20EAA685-6916-4B0C-8D0C-E407B072E28F}
{0FB0D403-E4B2-4073-B8B0-6FB296861DCA} = {20EAA685-6916-4B0C-8D0C-E407B072E28F}
{718DE4D1-54C9-452B-86AC-1647F669D3CD} = {20EAA685-6916-4B0C-8D0C-E407B072E28F}
{2C6DF000-2878-454F-8C4C-0EB68E3C2B3A} = {20EAA685-6916-4B0C-8D0C-E407B072E28F}
EndGlobalSection
EndGlobal
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
Expand Down
2 changes: 1 addition & 1 deletion examples/DemoFile.Example.Basic/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public static async Task Main(string[] args)
Console.WriteLine($"{e.Attacker?.PlayerName} [{e.Weapon}] {e.Player?.PlayerName}");
};

await demo.Start(File.OpenRead(path));
await demo.ReadAllAsync(File.OpenRead(path));

Console.WriteLine("\nFinished!");
}
Expand Down
2 changes: 1 addition & 1 deletion examples/DemoFile.Example.Inventory/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ void DumpGrenadeInventory()
var sw = Stopwatch.StartNew();
try
{
await demo.Start(File.OpenRead(path), cts.Token);
await demo.ReadAllAsync(File.OpenRead(path), cts.Token);
}
catch (OperationCanceledException) when (cts.IsCancellationRequested)
{
Expand Down
2 changes: 1 addition & 1 deletion examples/DemoFile.Example.KillFeed/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public static async Task Main(string[] args)

// Now that we've attached the event listeners, start reading the demo
var sw = Stopwatch.StartNew();
await demo.Start(File.OpenRead(path));
await demo.ReadAllAsync(File.OpenRead(path));
sw.Stop();

var ticks = demo.CurrentDemoTick.Value;
Expand Down
2 changes: 1 addition & 1 deletion examples/DemoFile.Example.Scoreboard/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public static async Task Main(string[] args)
AnsiConsole.Write(table);
};

await demo.Start(File.OpenRead(path));
await demo.ReadAllAsync(File.OpenRead(path));
}

private static void AddTeamRows(DemoParser demo, Table table, CCSTeam team)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\..\src\DemoFile\DemoFile.csproj" />
</ItemGroup>

</Project>
30 changes: 30 additions & 0 deletions examples/DemoFile.Example.TickByTick/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using DemoFile;

internal class Program
{
public static async Task Main(string[] args)
{
var path = args.SingleOrDefault() ?? throw new Exception("Expected a single argument: <path to .dem>");

var demo = new DemoParser();
demo.Source1GameEvents.PlayerDeath += e =>
{
Console.WriteLine($"{e.Attacker?.PlayerName} [{e.Weapon}] {e.Player?.PlayerName}");
};

// Read 20 minutes of gameplay before stopping
var readUntilTicks = DemoTick.Zero + TimeSpan.FromMinutes(20);

await demo.StartReadingAsync(File.OpenRead(path), default(CancellationToken));
while (demo.CurrentDemoTick < readUntilTicks)
{
if (!await demo.MoveNextAsync(default(CancellationToken)))
{
// We've reached the end of the demo file
break;
}
}

Console.WriteLine("\nFinished!");
}
}
2 changes: 1 addition & 1 deletion src/DemoFile.Benchmark/DemoFile.Benchmark.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
Expand Down
7 changes: 6 additions & 1 deletion src/DemoFile.Benchmark/DemoParserBenchmark.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,14 @@
var baseJob = Job.Default;

AddJob(baseJob.WithArguments(new[] { new MsBuildArgument("/p:Baseline=true") }).AsBaseline().WithId("Baseline"));
AddJob(baseJob.WithId("Current"));
AddJob(baseJob);
//AddJob(baseJob.WithArguments(new[] { new MsBuildArgument("/p:ClearBuf=true") }).WithId("ClearBuf"));
}
}

private DemoParser _demoParser;

Check warning on line 25 in src/DemoFile.Benchmark/DemoParserBenchmark.cs

View workflow job for this annotation

GitHub Actions / Build

Non-nullable field '_demoParser' must contain a non-null value when exiting constructor. Consider declaring the field as nullable.
private MemoryStream _fileStream;

Check warning on line 26 in src/DemoFile.Benchmark/DemoParserBenchmark.cs

View workflow job for this annotation

GitHub Actions / Build

Non-nullable field '_fileStream' must contain a non-null value when exiting constructor. Consider declaring the field as nullable.
private byte[] _demoBytes;

Check warning on line 27 in src/DemoFile.Benchmark/DemoParserBenchmark.cs

View workflow job for this annotation

GitHub Actions / Build

Non-nullable field '_demoBytes' must contain a non-null value when exiting constructor. Consider declaring the field as nullable.

[GlobalSetup]
public void GlobalSetup()
Expand All @@ -41,6 +42,10 @@
public async Task ParseDemo()
{
_demoParser = new DemoParser();
#if BASELINE
await _demoParser.Start(_fileStream, default);
#else
await _demoParser.ReadAllAsync(_fileStream, default);
#endif
}
}
2 changes: 1 addition & 1 deletion src/DemoFile.SdkGen/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ public static async Task Main(string[] args)

try
{
await demo.Start(File.OpenRead(demoPath), cts.Token);
await demo.ReadAllAsync(File.OpenRead(demoPath), cts.Token);
}
catch (OperationCanceledException) when (cts.IsCancellationRequested)
{
Expand Down
2 changes: 1 addition & 1 deletion src/DemoFile.Source1EventGen/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public static async Task Main(string[] args)

try
{
await demo.Start(File.OpenRead(demoPath), cts.Token);
await demo.ReadAllAsync(File.OpenRead(demoPath), cts.Token);
}
catch (OperationCanceledException) when (cts.IsCancellationRequested)
{
Expand Down
22 changes: 20 additions & 2 deletions src/DemoFile.Test/Integration/DemoEventsIntegrationTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,17 @@

namespace DemoFile.Test.Integration;

[TestFixture]
[TestFixture(true)]
[TestFixture(false)]
public class DemoEventsIntegrationTest
{
private readonly bool _readAll;

public DemoEventsIntegrationTest(bool readAll)
{
_readAll = readAll;
}

[Test]
public async Task DemoFileInfo()
{
Expand All @@ -25,7 +33,17 @@ public async Task DemoFileInfo()
};

// Act
await demo.Start(GotvCompetitiveProtocol13963, default);
if (_readAll)
{
await demo.ReadAllAsync(GotvCompetitiveProtocol13963, default);
}
else
{
await demo.StartReadingAsync(GotvCompetitiveProtocol13963, default);
while (await demo.MoveNextAsync(default))
{
}
}

// Assert
Snapshot.Assert(snapshot.ToString());
Expand Down
38 changes: 28 additions & 10 deletions src/DemoFile.Test/Integration/DemoParserIntegrationTest.cs
Original file line number Diff line number Diff line change
@@ -1,16 +1,34 @@
using System.Text;
using System.Text.Json;

namespace DemoFile.Test.Integration;
namespace DemoFile.Test.Integration;

[TestFixture]
public class DemoParserIntegrationTest
{
[Test]
public async Task Parse()
public async Task ReadAll()
{
var demo = new DemoParser();
await demo.ReadAllAsync(GotvCompetitiveProtocol13963, default);
Assert.That(demo.CurrentDemoTick.Value, Is.EqualTo(217866));
}

[Test]
public async Task ByTick()
{
// Arrange
var demo = new DemoParser();
await demo.Start(GotvCompetitiveProtocol13963, default);
var tick = demo.CurrentDemoTick;

// Act
await demo.StartReadingAsync(GotvCompetitiveProtocol13963, default);
while (await demo.MoveNextAsync(default))
{
// Tick is monotonic
Assert.That(demo.CurrentDemoTick.Value, Is.GreaterThanOrEqualTo(tick.Value));
tick = demo.CurrentDemoTick;
}

// Assert
Assert.That(demo.CurrentDemoTick.Value, Is.EqualTo(217866));
}

private static readonly KeyValuePair<string, Stream>[] CompatibilityCases =
Expand All @@ -20,16 +38,16 @@ public async Task Parse()
};

[TestCaseSource(nameof(CompatibilityCases))]
public async Task Parse_Compatibility(KeyValuePair<string, Stream> testCase)
public async Task ReadAll_Compatibility(KeyValuePair<string, Stream> testCase)
{
var demo = new DemoParser();
await demo.Start(testCase.Value, default);
await demo.ReadAllAsync(testCase.Value, default);
}

[Test]
public async Task Parse_AlternateBaseline()
public async Task ReadAll_AlternateBaseline()
{
var demo = new DemoParser();
await demo.Start(MatchmakingProtocol13968, default);
await demo.ReadAllAsync(MatchmakingProtocol13968, default);
}
}
22 changes: 20 additions & 2 deletions src/DemoFile.Test/Integration/PlayerPropsIntegrationTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,17 @@

namespace DemoFile.Test.Integration;

[TestFixture]
[TestFixture(true)]
[TestFixture(false)]
public class PlayerPropsIntegrationTest
{
private readonly bool _readAll;

public PlayerPropsIntegrationTest(bool readAll)
{
_readAll = readAll;
}

[Test]
public async Task Position()
{
Expand Down Expand Up @@ -82,7 +90,17 @@ void OnSnapshotTimer()
demo.CreateTimer(DemoTick.Zero + playerSnapshotInterval, OnSnapshotTimer);

// Act
await demo.Start(GotvCompetitiveProtocol13963, default);
if (_readAll)
{
await demo.ReadAllAsync(GotvCompetitiveProtocol13963, default);
}
else
{
await demo.StartReadingAsync(GotvCompetitiveProtocol13963, default);
while (await demo.MoveNextAsync(default))
{
}
}

// Assert
Snapshot.Assert(snapshot.ToString());
Expand Down
34 changes: 31 additions & 3 deletions src/DemoFile.Test/Integration/Source1GameEventIntegrationTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,17 @@

namespace DemoFile.Test.Integration;

[TestFixture]
[TestFixture(true)]
[TestFixture(false)]
public class Source1GameEventIntegrationTest
{
private readonly bool _readAll;

public Source1GameEventIntegrationTest(bool readAll)
{
_readAll = readAll;
}

[Test]
public async Task GameEvent()
{
Expand All @@ -27,7 +35,17 @@ public async Task GameEvent()
};

// Act
await demo.Start(GotvCompetitiveProtocol13963, default);
if (_readAll)
{
await demo.ReadAllAsync(GotvCompetitiveProtocol13963, default);
}
else
{
await demo.StartReadingAsync(GotvCompetitiveProtocol13963, default);
while (await demo.MoveNextAsync(default))
{
}
}

// Assert
Snapshot.Assert(snapshot.ToString());
Expand Down Expand Up @@ -56,6 +74,16 @@ public async Task PlayerProperties()
Assert.That(e.PlayerPawn, Is.Not.Null);
};

await demo.Start(GotvCompetitiveProtocol13963, default);
if (_readAll)
{
await demo.ReadAllAsync(GotvCompetitiveProtocol13963, default);
}
else
{
await demo.StartReadingAsync(GotvCompetitiveProtocol13963, default);
while (await demo.MoveNextAsync(default))
{
}
}
}
}
Loading