Using memory pooling and spans for tick parsing
This commit is contained in:
parent
31ada6ba55
commit
41a29662ec
@ -26,7 +26,7 @@ public class Benchy
|
||||
false
|
||||
,
|
||||
true
|
||||
)]
|
||||
)]
|
||||
public bool SkipImages;
|
||||
|
||||
[GlobalSetup]
|
||||
|
||||
@ -12,26 +12,9 @@
|
||||
*
|
||||
* | Method | SkipImages | Mean | Error | StdDev | Gen0 | Allocated |
|
||||
* |---------- |----------- |----------:|---------:|---------:|--------:|----------:|
|
||||
* | ReadFully | False | 187.55 us | 3.079 us | 2.880 us | 45.4102 | 93.52 KB |
|
||||
* | ReadFully | True | 26.44 us | 0.335 us | 0.297 us | 6.4392 | 13.17 KB |
|
||||
*
|
||||
* | Method | SkipImages | Mean | Error | StdDev | Gen0 | Allocated |
|
||||
* |---------- |----------- |----------:|---------:|---------:|--------:|----------:|
|
||||
* | ReadFully | False | 217.73 us | 4.190 us | 4.483 us | 45.4102 | 93.9 KB |
|
||||
* | ReadFully | True | 23.28 us | 0.391 us | 0.366 us | 6.1340 | 12.54 KB |
|
||||
*
|
||||
* | Method | SkipImages | Mean | Error | StdDev | Gen0 | Allocated |
|
||||
* |---------- |----------- |----------:|---------:|---------:|--------:|----------:|
|
||||
* | ReadFully | False | 211.93 us | 2.418 us | 2.144 us | 43.4570 | 89.84 KB |
|
||||
* | ReadFully | True | 20.60 us | 0.296 us | 0.262 us | 4.3640 | 8.94 KB |
|
||||
*
|
||||
* | Method | SkipImages | UseFileStream | Mean | Error | StdDev | Median | Gen0 | Gen1 | Allocated |
|
||||
* |---------- |----------- |-------------- |----------:|----------:|----------:|----------:|--------:|-------:|----------:|
|
||||
* | ReadFully | False | False | 265.56 us | 13.334 us | 39.316 us | 258.33 us | 43.4570 | 0.4883 | 90.08 KB |
|
||||
* | ReadFully | False | True | 599.75 us | 14.393 us | 39.644 us | 587.87 us | 42.9688 | 0.9766 | 90.08 KB |
|
||||
* | ReadFully | True | False | 21.15 us | 0.385 us | 0.674 us | 21.01 us | 4.4861 | - | 9.17 KB |
|
||||
* | ReadFully | True | True | 70.86 us | 1.392 us | 1.302 us | 70.92 us | 4.3945 | - | 9.17 KB |
|
||||
*
|
||||
* | Method | SkipImages | UseFileStream | Mean | Error | StdDev | Gen0 | Allocated |
|
||||
* |---------- |----------- |-------------- |----------:|----------:|----------:|--------:|----------:|
|
||||
* | ReadFully | False | False | 237.75 us | 4.725 us | 13.092 us | 43.4570 | 88.95 KB |
|
||||
@ -78,21 +61,6 @@ Init Replay.Actions list with capacity of Replay.TotalTicks / 2
|
||||
| ReadFull | 4v4.rec | False | 1,417.59 us | 28.016 us | 23.395 us | 1,407.82 us | 97.6563 | 68.3594 | 27.3438 | 616.45 KB |
|
||||
| ReadFull | 4v4.rec | True | 1,098.68 us | 21.912 us | 38.949 us | 1,087.36 us | 70.3125 | 54.6875 | 27.3438 | 414.01 KB |
|
||||
|
||||
| Method | Replay | SkipImages | Mean | Error | StdDev | Median | Gen0 | Gen1 | Gen2 | Allocated |
|
||||
|----------- |---------------- |----------- |--------------:|------------:|------------:|--------------:|----------:|---------:|---------:|-----------:|
|
||||
| ReadHeader | 1v1.rec | False | 1.572 us | 0.0294 us | 0.0275 us | 1.572 us | 0.6695 | - | - | 1.37 KB |
|
||||
| ReadInfo | 1v1.rec | False | 141.536 us | 2.6164 us | 2.3194 us | 141.797 us | 42.4805 | - | - | 87.67 KB |
|
||||
| ReadFull | 1v1.rec | False | 141.130 us | 1.8004 us | 1.4056 us | 141.015 us | 43.2129 | - | - | 89.06 KB |
|
||||
| ReadHeader | 1v1.rec | True | 1.680 us | 0.0376 us | 0.1074 us | 1.646 us | 0.6695 | - | - | 1.37 KB |
|
||||
| ReadInfo | 1v1.rec | True | 11.819 us | 0.2225 us | 0.3955 us | 11.720 us | 3.2501 | - | - | 6.64 KB |
|
||||
| ReadFull | 1v1.rec | True | 14.857 us | 0.2916 us | 0.4088 us | 14.860 us | 3.9215 | - | - | 8.03 KB |
|
||||
| ReadHeader | 4p_withbots.rec | False | 1.849 us | 0.0362 us | 0.0355 us | 1.844 us | 0.7801 | - | - | 1.59 KB |
|
||||
| ReadInfo | 4p_withbots.rec | False | 75.350 us | 1.4535 us | 1.4927 us | 74.821 us | 22.2168 | - | - | 45.76 KB |
|
||||
| ReadFull | 4p_withbots.rec | False | 15,368.249 us | 303.3914 us | 755.5498 us | 15,409.927 us | 1078.1250 | 890.6250 | 421.8750 | 6492.96 KB |
|
||||
| ReadHeader | 4p_withbots.rec | True | 1.912 us | 0.0382 us | 0.1000 us | 1.884 us | 0.7782 | - | - | 1.59 KB |
|
||||
| ReadInfo | 4p_withbots.rec | True | 11.963 us | 0.1580 us | 0.1401 us | 11.948 us | 2.5177 | - | - | 5.16 KB |
|
||||
| ReadFull | 4p_withbots.rec | True | 14,558.302 us | 288.3673 us | 803.8528 us | 14,454.221 us | 1046.8750 | 906.2500 | 390.6250 | 6452.2 KB |
|
||||
|
||||
| Method | Replay | SkipImages | Mean | Error | StdDev | Gen0 | Gen1 | Gen2 | Allocated |
|
||||
|--------- |---------------- |----------- |-------------:|-----------:|-----------:|----------:|---------:|---------:|-----------:|
|
||||
| ReadFull | 1v1.rec | False | 151.58 us | 2.997 us | 5.703 us | 43.2129 | 0.2441 | - | 89.02 KB |
|
||||
@ -115,33 +83,6 @@ Init Replay.Actions list with capacity of Replay.TotalTicks / 2
|
||||
| ReadFull | 4v4.rec | False | 1,444.44 us | 28.807 us | 48.130 us | 97.6563 | 68.3594 | 27.3438 | 616.81 KB |
|
||||
| ReadFull | 4v4.rec | True | 1,082.37 us | 18.606 us | 19.107 us | 70.3125 | 54.6875 | 27.3438 | 414.53 KB |
|
||||
|
||||
| Method | Replay | SkipImages | Mean | Error | StdDev | Gen0 | Gen1 | Gen2 | Allocated |
|
||||
|--------- |---------------- |----------- |-------------:|-----------:|-------------:|----------:|---------:|---------:|-----------:|
|
||||
| ReadFull | 1v1.rec | False | 102.87 us | 1.552 us | 2.176 us | 43.4570 | - | - | 89 KB |
|
||||
| ReadFull | 1v1.rec | True | 15.57 us | 0.310 us | 0.839 us | 3.9063 | - | - | 8.03 KB |
|
||||
| ReadFull | 2v2v2.rec | False | 733.72 us | 14.360 us | 18.672 us | 124.0234 | 41.9922 | - | 477.07 KB |
|
||||
| ReadFull | 2v2v2.rec | True | 461.28 us | 8.453 us | 15.877 us | 75.1953 | 23.4375 | - | 234.35 KB |
|
||||
| ReadFull | 4p_withbots.rec | False | 17,231.75 us | 589.520 us | 1,738.212 us | 1031.2500 | 843.7500 | 375.0000 | 6493.06 KB |
|
||||
| ReadFull | 4p_withbots.rec | True | 16,119.01 us | 320.763 us | 710.788 us | 1000.0000 | 875.0000 | 343.7500 | 6452.12 KB |
|
||||
| ReadFull | 4v4.rec | False | 1,561.33 us | 29.811 us | 31.898 us | 97.6563 | 68.3594 | 27.3438 | 616.81 KB |
|
||||
| ReadFull | 4v4.rec | True | 1,188.38 us | 23.616 us | 27.196 us | 70.3125 | 54.6875 | 27.3438 | 414.53 KB |
|
||||
|
||||
// ascii string equals with stackalloc bytes sequenceEqual no ignore case
|
||||
| Method | Replay | SkipImages | Mean | Error | StdDev | Gen0 | Gen1 | Gen2 | Allocated |
|
||||
|--------- |---------------- |----------- |-------------:|-----------:|-----------:|----------:|---------:|---------:|-----------:|
|
||||
| ReadFull | 1v1.rec | True | 13.17 us | 0.258 us | 0.265 us | 3.7079 | - | - | 7.6 KB |
|
||||
| ReadFull | 2v2v2.rec | True | 400.75 us | 7.956 us | 12.848 us | 76.6602 | 20.9961 | - | 233.86 KB |
|
||||
| ReadFull | 4p_withbots.rec | True | 14,380.66 us | 285.889 us | 768.022 us | 1062.5000 | 921.8750 | 406.2500 | 6451.56 KB |
|
||||
| ReadFull | 4v4.rec | True | 1,069.55 us | 20.197 us | 20.741 us | 70.3125 | 54.6875 | 27.3438 | 414.01 KB |
|
||||
|
||||
// ascii string equals with stackalloc bytes custom sequenceEqual with ignore case
|
||||
| Method | Replay | SkipImages | Mean | Error | StdDev | Gen0 | Gen1 | Gen2 | Allocated |
|
||||
|--------- |---------------- |----------- |-------------:|-----------:|-----------:|----------:|---------:|---------:|-----------:|
|
||||
| ReadFull | 1v1.rec | True | 13.96 us | 0.273 us | 0.507 us | 3.7079 | - | - | 7.6 KB |
|
||||
| ReadFull | 2v2v2.rec | True | 409.48 us | 7.863 us | 6.970 us | 77.1484 | 20.9961 | - | 233.86 KB |
|
||||
| ReadFull | 4p_withbots.rec | True | 13,161.68 us | 238.163 us | 185.942 us | 1000.0000 | 875.0000 | 343.7500 | 6451.48 KB |
|
||||
| ReadFull | 4v4.rec | True | 1,049.49 us | 20.183 us | 17.892 us | 70.3125 | 54.6875 | 27.3438 | 414.01 KB |
|
||||
|
||||
// Extract of logic and cleaning ExBinaryReader
|
||||
| Method | Replay | SkipImages | Mean | Error | StdDev | Gen0 | Gen1 | Gen2 | Allocated |
|
||||
|--------- |---------------- |----------- |-------------:|-----------:|-----------:|----------:|---------:|---------:|-----------:|
|
||||
@ -155,24 +96,26 @@ Init Replay.Actions list with capacity of Replay.TotalTicks / 2
|
||||
| ReadFull | 4v4.rec | True | 1,106.32 us | 21.747 us | 35.731 us | 70.3125 | 54.6875 | 27.3438 | 414.01 KB |
|
||||
|
||||
|
||||
26.07.2024
|
||||
| Method | Replay | SkipImages | Mean | Error | StdDev | Gen0 | Gen1 | Gen2 | Allocated |
|
||||
|--------- |---------------- |----------- |------------:|----------:|----------:|----------:|---------:|---------:|-----------:|
|
||||
| ReadFull | 1v1.rec | False | 109.6 us | 1.65 us | 1.46 us | 42.4805 | 7.0801 | - | 88.45 KB |
|
||||
| ReadFull | 2v2v2.rec | False | 735.7 us | 14.28 us | 12.66 us | 109.3750 | 58.5938 | - | 476.2 KB |
|
||||
| ReadFull | 4p_withbots.rec | False | 14,794.2 us | 295.22 us | 635.50 us | 1078.1250 | 906.2500 | 421.8750 | 6492.21 KB |
|
||||
| ReadFull | 4v4.rec | False | 1,352.9 us | 16.24 us | 14.40 us | 93.7500 | 64.4531 | 27.3438 | 615.98 KB |
|
||||
|
||||
|
||||
27.07.2024 Images parsing is better
|
||||
| Method | Replay | SkipImages | Mean | Error | StdDev | Median | Gen0 | Gen1 | Gen2 | Allocated |
|
||||
|--------- |---------------- |----------- |-------------:|-----------:|-------------:|-------------:|----------:|---------:|---------:|-----------:|
|
||||
| ReadFull | 1v1.rec | False | 42.87 us | 0.473 us | 0.395 us | 42.80 us | 42.5415 | 7.0801 | - | 88.27 KB |
|
||||
| ReadFull | 1v1.rec | True | 12.87 us | 0.095 us | 0.080 us | 12.87 us | 3.6926 | - | - | 7.55 KB |
|
||||
| ReadFull | 2v2v2.rec | False | 551.09 us | 10.990 us | 23.656 us | 541.74 us | 107.4219 | 53.7109 | - | 475.77 KB |
|
||||
| ReadFull | 2v2v2.rec | True | 427.14 us | 3.915 us | 3.269 us | 427.37 us | 74.7070 | 20.9961 | - | 233.8 KB |
|
||||
| ReadFull | 4p_withbots.rec | False | 14,880.91 us | 294.969 us | 561.210 us | 15,118.21 us | 1078.1250 | 906.2500 | 421.8750 | 6492.25 KB |
|
||||
| ReadFull | 4p_withbots.rec | True | 15,426.41 us | 403.218 us | 1,103.803 us | 15,222.37 us | 1046.8750 | 890.6250 | 390.6250 | 6451.52 KB |
|
||||
| ReadFull | 4v4.rec | False | 1,227.00 us | 24.521 us | 28.238 us | 1,222.49 us | 93.7500 | 64.4531 | 27.3438 | 615.61 KB |
|
||||
| ReadFull | 4v4.rec | True | 1,152.13 us | 26.309 us | 73.340 us | 1,117.18 us | 70.3125 | 54.6875 | 27.3438 | 413.96 KB |
|
||||
// 27.07.2024 Images parsing is better
|
||||
| Method | Replay | SkipImages | Mean | Error | StdDev | Gen0 | Gen1 | Gen2 | Allocated |
|
||||
|--------- |---------------- |----------- |-------------:|-----------:|-------------:|----------:|---------:|---------:|-----------:|
|
||||
| ReadFull | 1v1.rec | False | 42.87 us | 0.473 us | 0.395 us | 42.5415 | 7.0801 | - | 88.27 KB |
|
||||
| ReadFull | 1v1.rec | True | 12.87 us | 0.095 us | 0.080 us | 3.6926 | - | - | 7.55 KB |
|
||||
| ReadFull | 2v2v2.rec | False | 551.09 us | 10.990 us | 23.656 us | 107.4219 | 53.7109 | - | 475.77 KB |
|
||||
| ReadFull | 2v2v2.rec | True | 427.14 us | 3.915 us | 3.269 us | 74.7070 | 20.9961 | - | 233.8 KB |
|
||||
| ReadFull | 4p_withbots.rec | False | 14,880.91 us | 294.969 us | 561.210 us | 1078.1250 | 906.2500 | 421.8750 | 6492.25 KB |
|
||||
| ReadFull | 4p_withbots.rec | True | 15,426.41 us | 403.218 us | 1,103.803 us | 1046.8750 | 890.6250 | 390.6250 | 6451.52 KB |
|
||||
| ReadFull | 4v4.rec | False | 1,227.00 us | 24.521 us | 28.238 us | 93.7500 | 64.4531 | 27.3438 | 615.61 KB |
|
||||
| ReadFull | 4v4.rec | True | 1,152.13 us | 26.309 us | 73.340 us | 70.3125 | 54.6875 | 27.3438 | 413.96 KB |
|
||||
|
||||
// 27.07.2024 Using Memory pooling and spans for tick parsing
|
||||
| Method | Replay | SkipImages | Mean | Error | StdDev | Gen0 | Gen1 | Gen2 | Allocated |
|
||||
|--------- |---------------- |----------- |-------------:|-----------:|-----------:|----------:|---------:|---------:|-----------:|
|
||||
| ReadFull | 1v1.rec | False | 47.21 us | 0.916 us | 1.091 us | 42.5415 | 7.0801 | - | 88.27 KB |
|
||||
| ReadFull | 1v1.rec | True | 12.81 us | 0.090 us | 0.075 us | 3.6926 | - | - | 7.55 KB |
|
||||
| ReadFull | 2v2v2.rec | False | 456.30 us | 5.616 us | 5.253 us | 105.4688 | 54.6875 | - | 475.77 KB |
|
||||
| ReadFull | 2v2v2.rec | True | 359.79 us | 6.755 us | 5.988 us | 74.7070 | 21.4844 | - | 233.8 KB |
|
||||
| ReadFull | 4p_withbots.rec | False | 14,020.18 us | 278.529 us | 581.394 us | 1093.7500 | 984.3750 | 437.5000 | 6491.99 KB |
|
||||
| ReadFull | 4p_withbots.rec | True | 13,371.46 us | 267.402 us | 383.500 us | 1093.7500 | 984.3750 | 453.1250 | 6451.67 KB |
|
||||
| ReadFull | 4v4.rec | False | 1,095.98 us | 14.512 us | 12.865 us | 93.7500 | 64.4531 | 27.3438 | 615.62 KB |
|
||||
| ReadFull | 4v4.rec | True | 954.46 us | 9.933 us | 9.291 us | 70.3125 | 54.6875 | 27.3438 | 413.96 KB |
|
||||
@ -1,8 +1,8 @@
|
||||
namespace SoulstormReplayReader.Core.Domain.Action;
|
||||
|
||||
public sealed class GameActionModel(int tick) : IGameAction
|
||||
public sealed class GameActionModel : IGameAction
|
||||
{
|
||||
public int Tick { get; } = tick;
|
||||
public int Tick { get; set; }
|
||||
|
||||
public int PlayerId { get; set; }
|
||||
public int PlayerActionCount { get; set; }
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Library</OutputType>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<Configurations>Debug;Release;DebugLogging</Configurations>
|
||||
<Configurations>Debug;Release</Configurations>
|
||||
<Platforms>AnyCPU</Platforms>
|
||||
<Version>1.0.0</Version>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
using System.Buffers.Binary;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Buffers;
|
||||
using System.Buffers.Binary;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using SoulstormReplayReader.Core.Domain;
|
||||
@ -431,9 +431,33 @@ public sealed class SsReplayReader(Stream stream) : IDisposable
|
||||
if (tickType == TickType.Normal)
|
||||
{
|
||||
if (tickSize == 17)
|
||||
SkipEmptyTick();
|
||||
{
|
||||
_binaryReader.Skip(tickSize); // Всегда 17 байт
|
||||
}
|
||||
else
|
||||
ReadOrdinaryTick();
|
||||
{
|
||||
byte[] rentBytes = null;
|
||||
var bytes = tickSize switch
|
||||
{
|
||||
> 0 and < 0xFF => stackalloc byte[tickSize],
|
||||
_ => rentBytes = ArrayPool<byte>.Shared.Rent(tickSize)
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
bytes = _binaryReader.ReadBytes(bytes[..tickSize]);
|
||||
ParseOrdinaryTick(bytes);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine(ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (rentBytes is not null)
|
||||
ArrayPool<byte>.Shared.Return(rentBytes);
|
||||
}
|
||||
}
|
||||
|
||||
CurrentTick++;
|
||||
}
|
||||
@ -443,36 +467,32 @@ public sealed class SsReplayReader(Stream stream) : IDisposable
|
||||
ReadWierdTick((int)tickType, tickSize);
|
||||
}
|
||||
|
||||
|
||||
// Всегда 17 байт
|
||||
private void SkipEmptyTick()
|
||||
private void ParseOrdinaryTick(Span<byte> bytes)
|
||||
{
|
||||
_binaryReader.Skip(17);
|
||||
}
|
||||
var spanReader = new SpanReader(bytes);
|
||||
|
||||
|
||||
private void ReadOrdinaryTick()
|
||||
{
|
||||
// -- TICK HEADER --
|
||||
_binaryReader.Skip(1); // 0x50
|
||||
var tickCount = _binaryReader.ReadInt32();
|
||||
_binaryReader.Skip(8); // int32 "Номер действия игрока" ??? + int32 Random
|
||||
var playerChunksCount = _binaryReader.ReadInt32();
|
||||
// -- TICK HEADER -- size: 17
|
||||
spanReader.Skip(1); // 1 byte = 0x50
|
||||
var tickCount = spanReader.ReadInt32();
|
||||
spanReader.Skip(8); // 8 bytes = int32 "Номер действия игрока" ??? + int32 Random
|
||||
var playerChunksCount = spanReader.ReadInt32();
|
||||
|
||||
// -- TICK BODY --
|
||||
for (var i = 0; i < playerChunksCount; i++) // для каждого игрока предусмотрен свой чанк со своим размером
|
||||
{
|
||||
// -- PLAYER CHUNK HEADER --
|
||||
_binaryReader.Skip(8); // ???
|
||||
var playerChunkSize = _binaryReader.ReadInt32();
|
||||
_binaryReader.Skip(1); // то же самое
|
||||
// -- PLAYER CHUNK HEADER -- size: 13 + пока размер чанка != 0
|
||||
spanReader.Skip(8); // 8 bytes = ???
|
||||
var playerChunkSize = spanReader.ReadInt32();
|
||||
spanReader.Skip(1); // 1 byte = playerChunkSize, но байт
|
||||
|
||||
// -- PLAYER CHUNK BODY --
|
||||
while (playerChunkSize != 0)
|
||||
{
|
||||
var actionSize = _binaryReader.ReadInt16(); // размер захватывает 2 байта след чанка
|
||||
var actionSize = spanReader.ReadInt16(); // размер захватывает 2 байта (размера) следующего экшена
|
||||
|
||||
var action = ReadPlayerAction(tickCount, actionSize);
|
||||
spanReader.SliceToOffset();
|
||||
var action = ParsePlayerAction(ref spanReader, actionSize - 2);
|
||||
action.Tick = tickCount;
|
||||
|
||||
Replay.Actions.Add(action);
|
||||
playerChunkSize -= actionSize;
|
||||
@ -480,34 +500,21 @@ public sealed class SsReplayReader(Stream stream) : IDisposable
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private GameActionModel ReadPlayerAction(int tickCount, int actionSize)
|
||||
private GameActionModel ParsePlayerAction(ref SpanReader spanReader, int actionSize)
|
||||
{
|
||||
var actionEndPos = _binaryReader.Position + actionSize - 2;
|
||||
|
||||
// -- ACTION HEADER --
|
||||
_binaryReader.SkipInt32(); // какое то время (свое для каждого игрока)
|
||||
spanReader.Skip(4); // 4 bytes = какое то время (свое для каждого игрока)
|
||||
// (начинается с рандомного значения и увеличивается по ходу игры)
|
||||
// Скорее всего является global timer
|
||||
|
||||
// var s_cmd = _binaryReader.ReadInt32();
|
||||
// var s_param = _binaryReader.ReadInt32();
|
||||
// var s_shiftPressed = _binaryReader.ReadByte() == 1;
|
||||
// var s_playerId = _binaryReader.Skip(2).ReadInt16() % 10;
|
||||
//
|
||||
//
|
||||
// var leftOverBytes2 = actionEndPos - _binaryReader.Position;
|
||||
// Console.WriteLine(_binaryReader.ReadBytes((int)leftOverBytes2).ToContentString());
|
||||
// return new GameActionModel(1);
|
||||
|
||||
var cmd = _binaryReader.ReadInt32();
|
||||
var arg = _binaryReader.ReadByte(); // int32 in game
|
||||
var subCmd = _binaryReader.ReadInt16();
|
||||
var someNum = _binaryReader.ReadByte();
|
||||
var shiftPressed = _binaryReader.ReadByte() == 1;
|
||||
|
||||
var playerId = _binaryReader.Skip(2).ReadInt16() % 10;
|
||||
var playerActionCount = _binaryReader.ReadInt16();
|
||||
var cmd = spanReader.ReadInt32();
|
||||
var arg = spanReader.ReadByte(); // int32 in game
|
||||
var subCmd = spanReader.ReadInt16();
|
||||
var someNum = spanReader.ReadByte();
|
||||
var shiftPressed = spanReader.ReadByte() == 1;
|
||||
// 2 bytes = player id
|
||||
var playerId = spanReader.Skip(2).ReadInt16() % 10;
|
||||
var playerActionCount = spanReader.ReadInt16();
|
||||
|
||||
#if DEBUGLOGGING
|
||||
var selectedCount = _binaryReader.ReadByte();
|
||||
@ -523,10 +530,10 @@ public sealed class SsReplayReader(Stream stream) : IDisposable
|
||||
var primaryId = _binaryReader.ReadInt32();
|
||||
var actionBodyDataType = _binaryReader.ReadByte();
|
||||
#else
|
||||
_binaryReader.Skip(7);
|
||||
// _binaryReader.Skip(7);
|
||||
#endif
|
||||
|
||||
var curAction = new GameActionModel(tickCount)
|
||||
var curAction = new GameActionModel
|
||||
{
|
||||
Cmd = cmd,
|
||||
Arg = arg,
|
||||
@ -542,6 +549,8 @@ public sealed class SsReplayReader(Stream stream) : IDisposable
|
||||
if (CheckForBugs)
|
||||
Replay.Players[playerId].BugChecker?.Check(curAction);
|
||||
|
||||
spanReader.Skip((uint)(actionSize - spanReader.offset));
|
||||
|
||||
|
||||
#if DEBUGLOGGING
|
||||
// -- ACTION BODY --
|
||||
@ -565,8 +574,8 @@ public sealed class SsReplayReader(Stream stream) : IDisposable
|
||||
// }
|
||||
#else
|
||||
// -- ACTION BODY --
|
||||
var leftOverBytes = actionEndPos - _binaryReader.Position;
|
||||
_binaryReader.Skip((int)leftOverBytes);
|
||||
// var leftOverBytes = actionEndPos - _binaryReader.Position;
|
||||
// _binaryReader.Skip((int)leftOverBytes);
|
||||
#endif
|
||||
|
||||
return curAction;
|
||||
@ -577,7 +586,7 @@ public sealed class SsReplayReader(Stream stream) : IDisposable
|
||||
{
|
||||
var tickType = _binaryReader.ReadInt32();
|
||||
_binaryReader.Skip(4); // Размер тика
|
||||
_binaryReader.Skip(1); // То же самое
|
||||
_binaryReader.Skip(1); // Размер тика, но байт
|
||||
|
||||
if (tickType == 0)
|
||||
ReadPlayerQuit();
|
||||
|
||||
59
SoulstormReplayReader.Core/Utils/SpanReader.cs
Normal file
59
SoulstormReplayReader.Core/Utils/SpanReader.cs
Normal file
@ -0,0 +1,59 @@
|
||||
namespace SoulstormReplayReader.Core.Utils;
|
||||
|
||||
public ref struct SpanReader
|
||||
{
|
||||
public Span<byte> bytes;
|
||||
public int offset = 0;
|
||||
|
||||
public SpanReader(Span<byte> bytes)
|
||||
{
|
||||
this.bytes = bytes;
|
||||
}
|
||||
|
||||
public SpanReader SliceToOffset()
|
||||
{
|
||||
bytes = bytes[offset..];
|
||||
offset = 0;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SpanReader Skip(uint count)
|
||||
{
|
||||
offset += (int)count;
|
||||
return this;
|
||||
}
|
||||
|
||||
public byte ReadByte()
|
||||
{
|
||||
var value = bytes[offset];
|
||||
offset++;
|
||||
return value;
|
||||
}
|
||||
|
||||
public short ReadInt16()
|
||||
{
|
||||
var value = BitConverter.ToInt16(bytes[offset..]);
|
||||
offset += sizeof(short);
|
||||
return value;
|
||||
}
|
||||
|
||||
public int ReadInt32()
|
||||
{
|
||||
var value = BitConverter.ToInt32(bytes[offset..]);
|
||||
offset += sizeof(int);
|
||||
return value;
|
||||
}
|
||||
|
||||
public long ReadInt64()
|
||||
{
|
||||
var value = BitConverter.ToInt64(bytes[offset..]);
|
||||
offset += sizeof(long);
|
||||
return value;
|
||||
}
|
||||
|
||||
public readonly void RequireInRange()
|
||||
{
|
||||
if (offset >= bytes.Length)
|
||||
throw new ArgumentOutOfRangeException(nameof(offset));
|
||||
}
|
||||
}
|
||||
@ -8,7 +8,11 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\SoulstormReplayReader.Core\SoulstormReplayReader.Core.csproj" />
|
||||
<ProjectReference Include="..\SoulstormReplayReader.Core\SoulstormReplayReader.Core.csproj"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="TestReplays/*" CopyToOutputDirectory="PreserveNewest"/>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user