Files
Impostor/src/Impostor.Tools.ServerReplay/Program.cs
T
2020-10-24 01:18:25 +02:00

175 lines
6.4 KiB
C#

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.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 Serilog;
using ILogger = Serilog.ILogger;
namespace Impostor.Tools.ServerReplay
{
internal static class Program
{
private const string GameRecorderPath = "C:\\DevData\\ImpostorSessions";
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 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();
// Create service provider.
_serviceProvider = BuildServices();
// Create required instances.
_gameCodeFactory = _serviceProvider.GetRequiredService<MockGameCodeFactory>();
_clientManager = _serviceProvider.GetRequiredService<ClientManager>();
_gameManager = _serviceProvider.GetRequiredService<GameManager>();
foreach (var file in Directory.GetFiles(GameRecorderPath))
{
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>();
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:
await Connections[clientId].Client!.HandleDisconnectAsync(null);
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);
var message = new MessageReader(tag, buffer);
if (tag == MessageFlags.HostGame)
{
GameOptions.Add(clientId, Message00HostGameC2S.Deserialize(message));
}
else
{
await Connections[clientId].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();
}
}
}
}