using System.Threading.Tasks;
using Impostor.Api.Innersloth;
using Impostor.Api.Net.Messages;
-using Impostor.Api.Reactor;
namespace Impostor.Api.Net
{
/// </remarks>
string Name { get; }
- /// <summary>
- /// Gets mods sent by client in modded handshake.
- /// </summary>
- ISet<Mod> Mods { get; }
-
/// <summary>
/// Gets the connection of the client.
/// </summary>
RepairSystem = 28,
SetTasks = 29,
UpdateGameData = 30,
- CustomRpc = byte.MaxValue,
}
}
--- /dev/null
+namespace Impostor.Api.Net.Messages.C2S
+{
+ public static class HandshakeC2S
+ {
+ public static void Deserialize(IMessageReader reader, out int clientVersion, out string name, out uint lastNonceReceived)
+ {
+ clientVersion = reader.ReadInt32();
+ name = reader.ReadString();
+ lastNonceReceived = reader.ReadUInt32();
+ }
+ }
+}
+++ /dev/null
-namespace Impostor.Api.Reactor
-{
- public readonly struct Mod
- {
- public readonly string Id;
- public readonly string Version;
- public readonly PluginSide Side;
-
- public Mod(string id, string version, PluginSide side)
- {
- Id = id;
- Version = version;
- Side = side;
- }
-
- public override string ToString()
- {
- return $"{Id} ({Version})";
- }
- }
-}
+++ /dev/null
-using System.Collections.Generic;
-using Impostor.Api.Net.Messages;
-
-namespace Impostor.Api.Reactor
-{
- public static class ModList
- {
- public static void Deserialize(IMessageReader reader, out ISet<Mod> mods)
- {
- var length = reader.ReadPackedInt32();
-
- mods = new HashSet<Mod>(length);
-
- for (var i = 0; i < length; i++)
- {
- var id = reader.ReadString();
- var version = reader.ReadString();
- var pluginSide = (PluginSide)reader.ReadByte();
-
- mods.Add(new Mod(id, version, pluginSide));
- }
- }
- }
-}
+++ /dev/null
-using System.Collections.Generic;
-using Impostor.Api.Net.Messages;
-
-namespace Impostor.Api.Reactor
-{
- public static class ModdedHandshakeC2S
- {
- public static void Deserialize(IMessageReader reader, out int clientVersion, out string name, out ISet<Mod>? mods)
- {
- clientVersion = reader.ReadInt32();
- name = reader.ReadString();
-
- if (reader.Length > reader.Position)
- {
- ModList.Deserialize(reader, out mods);
- }
- else
- {
- mods = null;
- }
- }
- }
-}
+++ /dev/null
-using Impostor.Api.Net.Messages;
-
-namespace Impostor.Api.Reactor
-{
- public static class ModdedHandshakeS2C
- {
- public static void Serialize(IMessageWriter writer, string serverBrand)
- {
- writer.StartMessage(byte.MaxValue);
- writer.Write(serverBrand);
- writer.EndMessage();
- }
- }
-}
+++ /dev/null
-namespace Impostor.Api.Reactor
-{
- /// <summary>
- /// Plugin side used in modded handshake.
- /// </summary>
- public enum PluginSide : byte
- {
- /// <summary>
- /// Required by both sides, reject connection if missing on the other side
- /// </summary>
- Both,
-
- /// <summary>
- /// Required only by client
- /// </summary>
- ClientOnly,
-
- /// <summary>
- /// Required only by server
- /// </summary>
- ServerOnly,
- }
-}
using System;
-using System.Collections.Generic;
using System.Threading.Tasks;
using Impostor.Api;
using Impostor.Api.Games;
using Impostor.Api.Net.Messages;
using Impostor.Api.Net.Messages.C2S;
using Impostor.Api.Net.Messages.S2C;
-using Impostor.Api.Reactor;
using Impostor.Hazel;
using Impostor.Server.Config;
using Impostor.Server.Net.Manager;
private readonly ClientManager _clientManager;
private readonly GameManager _gameManager;
- public Client(ILogger<Client> logger, IOptions<AntiCheatConfig> antiCheatOptions, ClientManager clientManager, GameManager gameManager, string name, int gameVersion, IHazelConnection connection, ISet<Mod> mods)
- : base(name, gameVersion, connection, mods)
+ public Client(ILogger<Client> logger, IOptions<AntiCheatConfig> antiCheatOptions, ClientManager clientManager, GameManager gameManager, string name, int gameVersion, IHazelConnection connection)
+ : base(name, gameVersion, connection)
{
_logger = logger;
_antiCheatConfig = antiCheatOptions.Value;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
-using System.Linq;
using System.Threading.Tasks;
using Impostor.Api;
using Impostor.Api.Innersloth;
using Impostor.Api.Net;
using Impostor.Api.Net.Messages;
using Impostor.Api.Net.Messages.S2C;
-using Impostor.Api.Reactor;
using Impostor.Hazel;
using Impostor.Server.Net.State;
{
internal abstract class ClientBase : IClient
{
- protected ClientBase(string name, int gameVersion, IHazelConnection connection, ISet<Mod> mods)
+ protected ClientBase(string name, int gameVersion, IHazelConnection connection)
{
Name = name;
GameVersion = gameVersion;
Connection = connection;
- Mods = mods;
Items = new ConcurrentDictionary<object, object>();
-
- ModIdMap = new Dictionary<int, string>();
-
- var i = -1;
-
- foreach (var mod in mods.OrderBy(x => x.Id))
- {
- if (mod.Side == PluginSide.Both)
- {
- ModIdMap[i--] = mod.Id;
- }
- }
}
public int Id { get; set; }
public int GameVersion { get; }
- public ISet<Mod> Mods { get; }
-
- public Dictionary<int, string> ModIdMap { get; }
-
public IHazelConnection Connection { get; }
public IDictionary<object, object> Items { get; }
using System;
-using System.Collections.Generic;
using Impostor.Api.Net;
-using Impostor.Api.Reactor;
using Microsoft.Extensions.DependencyInjection;
namespace Impostor.Server.Net.Factories
_serviceProvider = serviceProvider;
}
- public ClientBase Create(IHazelConnection connection, string name, int clientVersion, ISet<Mod> mods)
+ public ClientBase Create(IHazelConnection connection, string name, int clientVersion)
{
- var client = ActivatorUtilities.CreateInstance<TClient>(_serviceProvider, name, clientVersion, connection, mods);
+ var client = ActivatorUtilities.CreateInstance<TClient>(_serviceProvider, name, clientVersion, connection);
connection.Client = client;
return client;
}
-using System.Collections.Generic;
-using Impostor.Api.Net;
-using Impostor.Api.Reactor;
+using Impostor.Api.Net;
namespace Impostor.Server.Net.Factories
{
internal interface IClientFactory
{
- ClientBase Create(IHazelConnection connection, string name, int clientVersion, ISet<Mod> mods);
+ ClientBase Create(IHazelConnection connection, string name, int clientVersion);
}
}
public abstract ValueTask DeserializeAsync(IClientPlayer sender, IClientPlayer? target, IMessageReader reader, bool initialState);
public abstract ValueTask<bool> HandleRpcAsync(ClientPlayer sender, ClientPlayer? target, RpcCalls call, IMessageReader reader);
-
- // TODO move to Reactor.Impostor plugin
- protected ValueTask<bool> HandleCustomRpc(IMessageReader reader, Game game)
- {
- var lengthOrShortId = reader.ReadPackedInt32();
-
- var pluginId = lengthOrShortId < 0
- ? game.Host!.Client.ModIdMap[lengthOrShortId]
- : reader.ReadString(lengthOrShortId);
-
- var id = reader.ReadPackedInt32();
-
- return ValueTask.FromResult(true);
- }
}
}
Rpc19EnterVent.Deserialize(reader, out ventId);
break;
- case RpcCalls.CustomRpc:
- return await HandleCustomRpc(reader, _game);
-
default:
return await UnregisteredCall(call, sender);
}
break;
}
- case RpcCalls.CustomRpc:
- return await HandleCustomRpc(reader, _game);
-
default:
return await UnregisteredCall(call, sender);
}
break;
}
- case RpcCalls.CustomRpc:
- return await HandleCustomRpc(reader, _game);
-
default:
return await UnregisteredCall(call, sender);
}
return await HandleSetStartCounter(sender, sequenceId, startCounter);
}
- case RpcCalls.CustomRpc:
- return await HandleCustomRpc(reader, _game);
-
default:
return await UnregisteredCall(call, sender);
}
break;
}
- case RpcCalls.CustomRpc:
- return await HandleCustomRpc(reader, _game);
-
default:
return await UnregisteredCall(call, sender);
}
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using Impostor.Api.Events.Managers;
using Impostor.Api.Innersloth;
using Impostor.Api.Net;
using Impostor.Api.Net.Messages;
using Impostor.Api.Net.Messages.S2C;
-using Impostor.Api.Reactor;
using Impostor.Hazel;
using Impostor.Server.Config;
using Impostor.Server.Net.Factories;
-using Impostor.Server.Utils;
using Microsoft.Extensions.Logging;
namespace Impostor.Server.Net.Manager
GameVersion.GetVersion(2021, 3, 25), // 2021.3.31s
};
- private static readonly string ServerBrand = $"Impostor {DotnetUtils.GetVersion()}";
-
private readonly ILogger<ClientManager> _logger;
private readonly ConcurrentDictionary<int, ClientBase> _clients;
private readonly IClientFactory _clientFactory;
return clientId;
}
- public async ValueTask RegisterConnectionAsync(IHazelConnection connection, string name, int clientVersion, ISet<Mod>? mods)
+ public async ValueTask RegisterConnectionAsync(IHazelConnection connection, string name, int clientVersion)
{
if (!SupportedVersions.Contains(clientVersion))
{
return;
}
- var client = _clientFactory.Create(connection, name, clientVersion, mods ?? new HashSet<Mod>(0));
+ var client = _clientFactory.Create(connection, name, clientVersion);
var id = NextId();
client.Id = id;
_logger.LogTrace("Client connected.");
_clients.TryAdd(id, client);
-
- using var writer = MessageWriter.Get(MessageType.Reliable);
- ModdedHandshakeS2C.Serialize(writer, ServerBrand);
- await connection.SendAsync(writer);
}
public void Remove(IClient client)
using System.Net;
using System.Net.Sockets;
using System.Threading.Tasks;
-using Impostor.Api.Reactor;
+using Impostor.Api.Events.Managers;
+using Impostor.Api.Net.Messages.C2S;
using Impostor.Hazel;
using Impostor.Hazel.Udp;
using Impostor.Server.Net.Hazel;
private async ValueTask OnNewConnection(NewConnectionEventArgs e)
{
// Handshake.
- ModdedHandshakeC2S.Deserialize(e.HandshakeData, out var clientVersion, out var name, out var mods);
+ HandshakeC2S.Deserialize(e.HandshakeData, out var clientVersion, out var name);
var connection = new HazelConnection(e.Connection, _connectionLogger);
// Register client
- await _clientManager.RegisterConnectionAsync(connection, name, clientVersion, mods);
+ await _clientManager.RegisterConnectionAsync(connection, name, clientVersion);
}
}
}
-using System.Collections.Generic;
-using System.Threading.Tasks;
+using System.Threading.Tasks;
using Impostor.Api.Innersloth;
using Impostor.Api.Net.Messages;
using Impostor.Api.Net.Messages.C2S;
using Impostor.Api.Net.Messages.S2C;
-using Impostor.Api.Reactor;
using Impostor.Hazel;
using Impostor.Server.Config;
using Impostor.Server.Net.Hazel;
string name,
int gameVersion,
HazelConnection connection,
- ISet<Mod> mods,
ClientManager clientManager,
INodeProvider nodeProvider,
INodeLocator nodeLocator)
- : base(name, gameVersion, connection, mods)
+ : base(name, gameVersion, connection)
{
_clientManager = clientManager;
_nodeProvider = nodeProvider;
using System;
-using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Impostor.Api.Games;
using Impostor.Api.Innersloth;
using Impostor.Api.Net;
using Impostor.Api.Net.Messages;
-using Impostor.Api.Reactor;
using Impostor.Hazel;
using Impostor.Server.Events;
using Microsoft.Extensions.DependencyInjection;
return GameJoinResult.FromError(GameJoinError.GameDestroyed);
}
- if (Host != null)
- {
- foreach (var hostMod in Host.Client.Mods)
- {
- if (hostMod.Side == PluginSide.Both && client.Mods.All(clientMod => hostMod.Id != clientMod.Id))
- {
- return GameJoinResult.CreateCustomError($"You are missing {hostMod.Id} - {hostMod.Version}");
- }
- }
-
- foreach (var clientMod in client.Mods)
- {
- if (clientMod.Side == PluginSide.Both && Host.Client.Mods.All(hostMod => clientMod.Id != hostMod.Id))
- {
- return GameJoinResult.CreateCustomError($"Host of this game is missing {clientMod.Id} - {clientMod.Version}");
- }
- }
- }
-
var isNew = false;
if (player == null || player.Game != this)
try
{
- Log.Information("Starting Impostor v{0}", DotnetUtils.GetVersion());
+ Log.Information("Starting Impostor v{0}", DotnetUtils.Version);
CreateHostBuilder(args).Build().Run();
return 0;
}
-using System.Collections.Generic;
-using System.Threading.Tasks;
+using System.Threading.Tasks;
using Impostor.Api.Net.Messages;
-using Impostor.Api.Reactor;
using Impostor.Server.Config;
using Impostor.Server.Net;
using Impostor.Server.Net.Hazel;
private bool _createdGame;
private bool _recordAfter;
- public ClientRecorder(ILogger<Client> logger, IOptions<AntiCheatConfig> antiCheatOptions, ClientManager clientManager, GameManager gameManager, string name, int gameVersion, HazelConnection connection, ISet<Mod> mods, PacketRecorder recorder)
- : base(logger, antiCheatOptions, clientManager, gameManager, name, gameVersion, connection, mods)
+ public ClientRecorder(ILogger<Client> logger, IOptions<AntiCheatConfig> antiCheatOptions, ClientManager clientManager, GameManager gameManager, string name, int gameVersion, HazelConnection connection, PacketRecorder recorder)
+ : base(logger, antiCheatOptions, clientManager, gameManager, name, gameVersion, connection)
{
_recorder = recorder;
_isFirst = true;
{
context.Writer.Write((uint)ServerReplayVersion.Initial);
context.Writer.Write(_startTime.ToUnixTimeMilliseconds());
- context.Writer.Write(DotnetUtils.GetVersion());
+ context.Writer.Write(DotnetUtils.Version);
await WriteAsync(context.Stream!);
}
namespace Impostor.Server.Utils
{
- internal static class DotnetUtils
+ public static class DotnetUtils
{
- private const string DefaultUnknownBuild = "UNKNOWN";
+ private static string? _version;
- public static string GetVersion()
+ public static string Version
{
- var attribute = typeof(DotnetUtils).Assembly.GetCustomAttribute<AssemblyInformationalVersionAttribute>();
- if (attribute != null)
+ get
{
- return attribute.InformationalVersion;
- }
+ if (_version == null)
+ {
+ var attribute = typeof(DotnetUtils).Assembly.GetCustomAttribute<AssemblyInformationalVersionAttribute>();
+ _version = attribute != null ? attribute.InformationalVersion : "UNKNOWN";
+ }
- return DefaultUnknownBuild;
+ return _version;
+ }
}
}
}
// Create and register connection.
var connection = new MockHazelConnection(address);
- await _clientManager.RegisterConnectionAsync(connection, name, gameVersion, null);
+ await _clientManager.RegisterConnectionAsync(connection, name, gameVersion);
// Store reference for ourselfs.
Connections.Add(clientId, connection);