diff --git a/CHANGELOG.md b/CHANGELOG.md index 37e145b..539cc85 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [2.4.0] - 2024-11-13 ### Changed - support .net9 +- fix parsing of `FRepMovement` with `RepMoveOptionalAcceleration` (thanks @Zaid) ### Removed - support .net6 diff --git a/src/ConsoleReader/Program.cs b/src/ConsoleReader/Program.cs index 2e19161..a8c37a3 100644 --- a/src/ConsoleReader/Program.cs +++ b/src/ConsoleReader/Program.cs @@ -5,7 +5,6 @@ using System.Diagnostics; using System.IO; using Unreal.Core.Models.Enums; -using static System.Environment; // Set up dependency injection and logging services var serviceCollection = new ServiceCollection() @@ -16,8 +15,7 @@ var logger = provider.GetService>(); // Define the folder containing replay files -var localAppDataFolder = GetFolderPath(SpecialFolder.LocalApplicationData); -// var replayFilesFolder = Path.Combine(localAppDataFolder, @"FortniteGame\Saved\Demos"); +//var replayFilesFolder = Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.LocalApplicationData), @"FortniteGame\Saved\Demos"); var replayFilesFolder = @"C:\Users\ferro\Downloads\"; var replayFiles = Directory.EnumerateFiles(replayFilesFolder, "*.replay"); @@ -25,12 +23,11 @@ long total = 0; #if DEBUG -var reader = new ReplayReader(logger, ParseMode.Minimal); +var reader = new ReplayReader(logger, ParseMode.Normal); #else var reader = new ReplayReader(null, ParseMode.Minimal); #endif -// Process each replay file foreach (var replayFile in replayFiles) { sw.Restart(); diff --git a/src/Unreal.Core.Test/NetBitReaderTest.cs b/src/Unreal.Core.Test/NetBitReaderTest.cs index 5690087..dd76a47 100644 --- a/src/Unreal.Core.Test/NetBitReaderTest.cs +++ b/src/Unreal.Core.Test/NetBitReaderTest.cs @@ -26,12 +26,12 @@ public class NetBitReaderTest // sniper rifle bullet season 11 [InlineData(new byte[] { 0x34, 0x88, 0xDF, 0x03, 0xE0, 0xE9, 0xCB, 0x3F, 0x92, 0x3B, 0x53, 0x3C, - 0x47, 0x61, 0xD6, 0x01}, 122, + 0x47, 0x61, 0xD6, 0x01 }, 122, VectorQuantization.RoundWholeNumber, RotatorQuantization.ByteComponents, VectorQuantization.RoundWholeNumber)] // supply drop season 11 [InlineData(new byte[] { 0x74, 0x20, 0x88, 0x53, 0x86, 0xDA, 0x16, 0xD8, 0x02, 0x40, 0x00, 0x38, - 0x2B, 0x00}, 105, + 0x2B, 0x00 }, 105, VectorQuantization.RoundWholeNumber, RotatorQuantization.ByteComponents, VectorQuantization.RoundWholeNumber)] // meat vehicle 11.40 [InlineData(new byte[] { @@ -39,12 +39,21 @@ public class NetBitReaderTest 0x83, 0x55, 0x1A, 0xF9, 0x47, 0xF2, 0xBD, 0xBE, 0x54, 0x3B, 0xFB, 0x88, 0xAB, 0xBF, 0x70, 0xB3, 0xCB, 0x02}, 236, VectorQuantization.RoundWholeNumber, RotatorQuantization.ShortComponents, VectorQuantization.RoundTwoDecimals)] + [InlineData(new byte[] { + 0xA0, 0x65, 0x06, 0xE5, 0x68, 0x79, 0x0F, 0x60, 0xD8, 0x85, 0xFD, 0x05, + 0x15, 0x04 }, 111, VectorQuantization.RoundTwoDecimals, RotatorQuantization.ByteComponents, VectorQuantization.RoundWholeNumber, + EngineNetworkVersionHistory.CustomExports)] public void RepMovementTest(byte[] rawData, int bitCount, VectorQuantization locationQuantizationLevel = VectorQuantization.RoundTwoDecimals, RotatorQuantization rotationQuantizationLevel = RotatorQuantization.ByteComponents, - VectorQuantization velocityQuantizationLevel = VectorQuantization.RoundWholeNumber) + VectorQuantization velocityQuantizationLevel = VectorQuantization.RoundWholeNumber, + EngineNetworkVersionHistory engineNetworkVersion = EngineNetworkVersionHistory.HISTORY_INITIAL) { - var reader = new NetBitReader(rawData, bitCount); + var reader = new NetBitReader(rawData, bitCount) + { + EngineNetworkVersion = engineNetworkVersion + }; + reader.SerializeRepMovement(locationQuantizationLevel, rotationQuantizationLevel, velocityQuantizationLevel); Assert.False(reader.IsError); Assert.True(reader.AtEnd()); diff --git a/src/Unreal.Core/BitReader.cs b/src/Unreal.Core/BitReader.cs index 5f97b6a..48a75db 100644 --- a/src/Unreal.Core/BitReader.cs +++ b/src/Unreal.Core/BitReader.cs @@ -23,7 +23,7 @@ public class BitReader : FBitArchive public override int MarkPosition { get; protected set; } - private readonly Dictionary _tempLastBit = new(); + private readonly Dictionary _tempLastBit = []; public BitReader() @@ -132,7 +132,7 @@ public override ReadOnlySpan ReadBits(int bitCount) if (!CanRead(bitCount) || bitCount < 0) { IsError = true; - return ReadOnlySpan.Empty; + return []; } var bitCountUsedInByte = Position & 7; @@ -205,7 +205,7 @@ public override ReadOnlySpan ReadBytes(int byteCount) if (!CanRead(byteCount * 8) || byteCount < 0) { IsError = true; - return Span.Empty; + return []; } var bitCountUsedInByte = Position & 7; diff --git a/src/Unreal.Core/Models/FRepMovement.cs b/src/Unreal.Core/Models/FRepMovement.cs index 6a422d9..5c90b56 100644 --- a/src/Unreal.Core/Models/FRepMovement.cs +++ b/src/Unreal.Core/Models/FRepMovement.cs @@ -28,6 +28,11 @@ public struct FRepMovement /// public FRotator Rotation { get; set; } + /// + /// Acceleration of component in world space. Only valid if bRepAcceleration is set. + /// + public FVector? Acceleration { get; set; } + /// /// If set, RootComponent should be sleeping. /// @@ -38,6 +43,11 @@ public struct FRepMovement /// public bool bRepPhysics { get; set; } + /// + /// If set, additional acceleration data will be replicated. + /// + public bool bRepAcceleration { get; set; } + /// /// Server physics step /// diff --git a/src/Unreal.Core/NetBitReader.cs b/src/Unreal.Core/NetBitReader.cs index dad9710..5548cb1 100644 --- a/src/Unreal.Core/NetBitReader.cs +++ b/src/Unreal.Core/NetBitReader.cs @@ -60,7 +60,6 @@ public FRepMovement SerializeRepMovement( bRepPhysics = bRepPhysics, Location = SerializePropertyQuantizedVector(locationQuantizationLevel), Rotation = rotationQuantizationLevel == RotatorQuantization.ByteComponents ? ReadRotation() : ReadRotationShort(), - LinearVelocity = SerializePropertyQuantizedVector(velocityQuantizationLevel) }; @@ -79,6 +78,15 @@ public FRepMovement SerializeRepMovement( repMovement.ServerPhysicsHandle = ReadIntPacked(); } + if (EngineNetworkVersion >= EngineNetworkVersionHistory.RepMoveOptionalAcceleration) + { + repMovement.bRepAcceleration = ReadBit(); + if (repMovement.bRepAcceleration) + { + repMovement.Acceleration = SerializePropertyQuantizedVector(velocityQuantizationLevel); + } + } + return repMovement; } diff --git a/src/Unreal.Core/ReplayReader.cs b/src/Unreal.Core/ReplayReader.cs index d89881e..234cdb8 100644 --- a/src/Unreal.Core/ReplayReader.cs +++ b/src/Unreal.Core/ReplayReader.cs @@ -1729,7 +1729,7 @@ public virtual bool ReceiveProperties(FBitArchive archive, NetFieldExportGroup g #if DEBUG Debug("failed-properties", $"Property {export.Name} (handle: {handle}, path: {group.PathName}) caused error when reading (bits: {numBits}, group: {group.PathName})"); _cmdReader.Reset(); - Debug($"cmd-{export.Name}-{numBits}", "cmds", _cmdReader.ReadBytes(Math.Max((int) Math.Ceiling(_cmdReader.GetBitsLeft() / 8.0), 1))); + Debug($"cmd-{export.Name}-{numBits}", "cmds", _cmdReader.ReadBits(_cmdReader.GetBitsLeft())); #endif continue; } @@ -1742,7 +1742,7 @@ public virtual bool ReceiveProperties(FBitArchive archive, NetFieldExportGroup g #if DEBUG Debug("failed-properties", $"Property {export.Name} (handle: {handle}, path: {group.PathName}) didnt read proper number of bits: {(_cmdReader.LastBit - _cmdReader.GetBitsLeft())} out of {numBits}"); _cmdReader.Reset(); - Debug($"cmd-{export.Name}-{numBits}", "cmds", _cmdReader.ReadBytes(Math.Max((int) Math.Ceiling(_cmdReader.GetBitsLeft() / 8.0), 1))); + Debug($"cmd-{export.Name}-{numBits}", "cmds", _cmdReader.ReadBits(_cmdReader.GetBitsLeft())); #endif continue; }