From e9ea621b93fbb58d9edfca8375918791637bbd52 Mon Sep 17 00:00:00 2001 From: chai Date: Wed, 30 Dec 2020 20:59:04 +0800 Subject: +init --- .../Impostor.Tools.ServerReplay.csproj | 16 ++ .../Mocks/MockGameCodeFactory.cs | 14 ++ .../Mocks/MockHazelConnection.cs | 31 ++++ .../src/Impostor.Tools.ServerReplay/Program.cs | 195 +++++++++++++++++++++ ...session_1604255331821_dead_player_exception.dat | Bin 0 -> 47057 bytes 5 files changed, 256 insertions(+) create mode 100644 Impostor-dev/src/Impostor.Tools.ServerReplay/Impostor.Tools.ServerReplay.csproj create mode 100644 Impostor-dev/src/Impostor.Tools.ServerReplay/Mocks/MockGameCodeFactory.cs create mode 100644 Impostor-dev/src/Impostor.Tools.ServerReplay/Mocks/MockHazelConnection.cs create mode 100644 Impostor-dev/src/Impostor.Tools.ServerReplay/Program.cs create mode 100644 Impostor-dev/src/Impostor.Tools.ServerReplay/sessions/session_1604255331821_dead_player_exception.dat (limited to 'Impostor-dev/src/Impostor.Tools.ServerReplay') diff --git a/Impostor-dev/src/Impostor.Tools.ServerReplay/Impostor.Tools.ServerReplay.csproj b/Impostor-dev/src/Impostor.Tools.ServerReplay/Impostor.Tools.ServerReplay.csproj new file mode 100644 index 0000000..98fa689 --- /dev/null +++ b/Impostor-dev/src/Impostor.Tools.ServerReplay/Impostor.Tools.ServerReplay.csproj @@ -0,0 +1,16 @@ + + + + Exe + net5.0 + + + + + + + + + + + diff --git a/Impostor-dev/src/Impostor.Tools.ServerReplay/Mocks/MockGameCodeFactory.cs b/Impostor-dev/src/Impostor.Tools.ServerReplay/Mocks/MockGameCodeFactory.cs new file mode 100644 index 0000000..1111b7e --- /dev/null +++ b/Impostor-dev/src/Impostor.Tools.ServerReplay/Mocks/MockGameCodeFactory.cs @@ -0,0 +1,14 @@ +using Impostor.Api.Games; + +namespace Impostor.Tools.ServerReplay.Mocks +{ + public class MockGameCodeFactory : IGameCodeFactory + { + public GameCode Result { get; set; } + + public GameCode Create() + { + return Result; + } + } +} \ No newline at end of file diff --git a/Impostor-dev/src/Impostor.Tools.ServerReplay/Mocks/MockHazelConnection.cs b/Impostor-dev/src/Impostor.Tools.ServerReplay/Mocks/MockHazelConnection.cs new file mode 100644 index 0000000..43f0257 --- /dev/null +++ b/Impostor-dev/src/Impostor.Tools.ServerReplay/Mocks/MockHazelConnection.cs @@ -0,0 +1,31 @@ +using System.Net; +using System.Threading.Tasks; +using Impostor.Api.Net; +using Impostor.Api.Net.Messages; + +namespace Impostor.Tools.ServerReplay.Mocks +{ + public class MockHazelConnection : IHazelConnection + { + public MockHazelConnection(IPEndPoint endPoint) + { + EndPoint = endPoint; + IsConnected = true; + Client = null; + } + + public IPEndPoint EndPoint { get; } + public bool IsConnected { get; } + public IClient? Client { get; set; } + + public ValueTask SendAsync(IMessageWriter writer) + { + return ValueTask.CompletedTask; + } + + public ValueTask DisconnectAsync(string reason) + { + return ValueTask.CompletedTask; + } + } +} \ No newline at end of file diff --git a/Impostor-dev/src/Impostor.Tools.ServerReplay/Program.cs b/Impostor-dev/src/Impostor.Tools.ServerReplay/Program.cs new file mode 100644 index 0000000..5aaa954 --- /dev/null +++ b/Impostor-dev/src/Impostor.Tools.ServerReplay/Program.cs @@ -0,0 +1,195 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Net; +using System.Threading.Tasks; +using Impostor.Api.Events.Managers; +using Impostor.Api.Games; +using Impostor.Api.Games.Managers; +using Impostor.Api.Innersloth; +using Impostor.Api.Net; +using Impostor.Api.Net.Messages; +using Impostor.Api.Net.Messages.C2S; +using Impostor.Hazel; +using Impostor.Hazel.Extensions; +using Impostor.Server.Events; +using Impostor.Server.Net; +using Impostor.Server.Net.Factories; +using Impostor.Server.Net.Manager; +using Impostor.Server.Net.Redirector; +using Impostor.Server.Recorder; +using Impostor.Tools.ServerReplay.Mocks; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.ObjectPool; +using Serilog; +using ILogger = Serilog.ILogger; + +namespace Impostor.Tools.ServerReplay +{ + internal static class Program + { + private static readonly ILogger Logger = Log.ForContext(typeof(Program)); + private static readonly Dictionary Connections = new Dictionary(); + private static readonly Dictionary GameOptions = new Dictionary(); + + private static ServiceProvider _serviceProvider; + + private static ObjectPool _readerPool; + private static MockGameCodeFactory _gameCodeFactory; + private static ClientManager _clientManager; + private static GameManager _gameManager; + + private static async Task Main(string[] args) + { + Log.Logger = new LoggerConfiguration() + // .MinimumLevel.Verbose() + .MinimumLevel.Debug() + .WriteTo.Console() + .CreateLogger(); + + var stopwatch = Stopwatch.StartNew(); + + foreach (var file in Directory.GetFiles(args[0])) + { + // Clear. + Connections.Clear(); + GameOptions.Clear(); + + // Create service provider. + _serviceProvider = BuildServices(); + + // Create required instances. + _readerPool = _serviceProvider.GetRequiredService>(); + _gameCodeFactory = _serviceProvider.GetRequiredService(); + _clientManager = _serviceProvider.GetRequiredService(); + _gameManager = _serviceProvider.GetRequiredService(); + + await using (var stream = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read)) + using (var reader = new BinaryReader(stream)) + { + await ParseSession(reader); + } + } + + var elapsedMilliseconds = stopwatch.ElapsedMilliseconds; + + Logger.Information($"Took {elapsedMilliseconds}ms."); + } + + private static ServiceProvider BuildServices() + { + var services = new ServiceCollection(); + + services.AddLogging(builder => + { + builder.ClearProviders(); + builder.AddSerilog(); + }); + + services.AddSingleton(); + services.AddSingleton(p => p.GetRequiredService()); + + services.AddSingleton(); + services.AddSingleton(p => p.GetRequiredService()); + + services.AddSingleton(); + services.AddSingleton>(); + services.AddSingleton(); + services.AddSingleton(); + + services.AddHazel(); + + return services.BuildServiceProvider(); + } + + private static async Task ParseSession(BinaryReader reader) + { + while (reader.BaseStream.Position < reader.BaseStream.Length) + { + var dataLength = reader.ReadInt32(); + var data = reader.ReadBytes(dataLength - 4); + + await using (var stream = new MemoryStream(data)) + using (var readerInner = new BinaryReader(stream)) + { + await ParsePacket(readerInner); + } + } + } + + private static async Task ParsePacket(BinaryReader reader) + { + var dataType = (RecordedPacketType) reader.ReadByte(); + + // Read client id. + var clientId = reader.ReadInt32(); + + switch (dataType) + { + case RecordedPacketType.Connect: + // Read data. + var addressLength = reader.ReadByte(); + var addressBytes = reader.ReadBytes(addressLength); + var addressPort = reader.ReadUInt16(); + var address = new IPEndPoint(new IPAddress(addressBytes), addressPort); + var name = reader.ReadString(); + + // Create and register connection. + var connection = new MockHazelConnection(address); + + await _clientManager.RegisterConnectionAsync(connection, name, 50516550); + + // Store reference for ourselfs. + Connections.Add(clientId, connection); + break; + + case RecordedPacketType.Disconnect: + string reason = null; + + if (reader.BaseStream.Position < reader.BaseStream.Length) + { + reason = reader.ReadString(); + } + + await Connections[clientId].Client!.HandleDisconnectAsync(reason); + Connections.Remove(clientId); + break; + + case RecordedPacketType.Message: + { + var messageType = (MessageType)reader.ReadByte(); + var tag = reader.ReadByte(); + var length = reader.ReadInt32(); + var buffer = reader.ReadBytes(length); + using var message = _readerPool.Get(); + + message.Update(buffer, tag: tag); + + if (tag == MessageFlags.HostGame) + { + GameOptions.Add(clientId, Message00HostGameC2S.Deserialize(message)); + } + else if (Connections.TryGetValue(clientId, out var client)) + { + await client.Client!.HandleMessageAsync(message, messageType); + } + + break; + } + + case RecordedPacketType.GameCreated: + _gameCodeFactory.Result = GameCode.From(reader.ReadString()); + + await _gameManager.CreateAsync(GameOptions[clientId]); + + GameOptions.Remove(clientId); + break; + + default: + throw new ArgumentOutOfRangeException(); + } + } + } +} diff --git a/Impostor-dev/src/Impostor.Tools.ServerReplay/sessions/session_1604255331821_dead_player_exception.dat b/Impostor-dev/src/Impostor.Tools.ServerReplay/sessions/session_1604255331821_dead_player_exception.dat new file mode 100644 index 0000000..e5f441b Binary files /dev/null and b/Impostor-dev/src/Impostor.Tools.ServerReplay/sessions/session_1604255331821_dead_player_exception.dat differ -- cgit v1.1-26-g67d0