diff options
Diffstat (limited to 'Impostor-dev/src/Impostor.Tools.ServerReplay/Program.cs')
-rw-r--r-- | Impostor-dev/src/Impostor.Tools.ServerReplay/Program.cs | 195 |
1 files changed, 195 insertions, 0 deletions
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<int, IHazelConnection> Connections = new Dictionary<int, IHazelConnection>(); + private static readonly Dictionary<int, GameOptionsData> GameOptions = new Dictionary<int, GameOptionsData>(); + + private static ServiceProvider _serviceProvider; + + private static ObjectPool<MessageReader> _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<ObjectPool<MessageReader>>(); + _gameCodeFactory = _serviceProvider.GetRequiredService<MockGameCodeFactory>(); + _clientManager = _serviceProvider.GetRequiredService<ClientManager>(); + _gameManager = _serviceProvider.GetRequiredService<GameManager>(); + + 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<GameManager>(); + services.AddSingleton<IGameManager>(p => p.GetRequiredService<GameManager>()); + + services.AddSingleton<MockGameCodeFactory>(); + services.AddSingleton<IGameCodeFactory>(p => p.GetRequiredService<MockGameCodeFactory>()); + + services.AddSingleton<ClientManager>(); + services.AddSingleton<IClientFactory, ClientFactory<Client>>(); + services.AddSingleton<INodeLocator, NodeLocatorNoOp>(); + services.AddSingleton<IEventManager, EventManager>(); + + 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(); + } + } + } +} |