diff --git a/src/Impostor.Api/Innersloth/Net/Objects/InnerPlayerControl.cs b/src/Impostor.Api/Innersloth/Net/Objects/InnerPlayerControl.cs
index dd2eb8a3..57efe8c4 100644
--- a/src/Impostor.Api/Innersloth/Net/Objects/InnerPlayerControl.cs
+++ b/src/Impostor.Api/Innersloth/Net/Objects/InnerPlayerControl.cs
@@ -395,8 +395,6 @@ namespace Impostor.Api.Innersloth.Net.Objects
{
PlayerInfo.IsDead = true;
PlayerInfo.LastDeathReason = reason;
-
- Console.WriteLine($"{PlayerInfo.PlayerName,-15} died {reason}");
}
}
}
\ No newline at end of file
diff --git a/src/Impostor.Api/Net/IHazelConnection.cs b/src/Impostor.Api/Net/IHazelConnection.cs
index a39e0b5c..282e439a 100644
--- a/src/Impostor.Api/Net/IHazelConnection.cs
+++ b/src/Impostor.Api/Net/IHazelConnection.cs
@@ -30,5 +30,12 @@ namespace Impostor.Api.Net
/// The message.
///
ValueTask SendAsync(IMessageWriter writer);
+
+ ///
+ /// Disconnects the client and invokes the disconnect handler.
+ ///
+ /// A reason.
+ ///
+ ValueTask DisconnectAsync(string reason);
}
}
\ No newline at end of file
diff --git a/src/Impostor.Api/Unity/Mathf.cs b/src/Impostor.Api/Unity/Mathf.cs
index ed883c8f..4b034176 100644
--- a/src/Impostor.Api/Unity/Mathf.cs
+++ b/src/Impostor.Api/Unity/Mathf.cs
@@ -13,22 +13,31 @@
///
public static float Clamp(float value, float min, float max)
{
- if ((double) value < (double) min)
+ if (value < (double)min)
+ {
value = min;
- else if ((double) value > (double) max)
+ }
+ else if (value > (double)max)
+ {
value = max;
+ }
+
return value;
}
///
/// Clamps value between 0 and 1 and returns value.
///
- ///
+ /// Value.
+ /// Clamped value.
public static float Clamp01(float value)
{
- if ((double) value < 0.0)
+ if (value < 0.0)
+ {
return 0.0f;
- return (double) value > 1.0 ? 1f : value;
+ }
+
+ return (double)value > 1.0 ? 1f : value;
}
///
@@ -40,6 +49,6 @@
///
/// The interpolated float result between the two float values.
///
- public static float Lerp(float a, float b, float t) => a + (b - a) * Mathf.Clamp01(t);
+ public static float Lerp(float a, float b, float t) => a + ((b - a) * Clamp01(t));
}
}
\ No newline at end of file
diff --git a/src/Impostor.Server/Constants.cs b/src/Impostor.Server/Constants.cs
new file mode 100644
index 00000000..62d90b29
--- /dev/null
+++ b/src/Impostor.Server/Constants.cs
@@ -0,0 +1,8 @@
+namespace Impostor.Server
+{
+ internal static class Constants
+ {
+ public const int SpawnTimeout = 2500;
+ public const int ConnectionTimeout = 2500;
+ }
+}
\ No newline at end of file
diff --git a/src/Impostor.Server/Net/Hazel/HazelConnection.cs b/src/Impostor.Server/Net/Hazel/HazelConnection.cs
index 3e92594d..9a9a0714 100644
--- a/src/Impostor.Server/Net/Hazel/HazelConnection.cs
+++ b/src/Impostor.Server/Net/Hazel/HazelConnection.cs
@@ -32,6 +32,16 @@ namespace Impostor.Server.Net.Hazel
return InnerConnection.SendAsync(writer);
}
+ public ValueTask DisconnectAsync(string reason)
+ {
+ return InnerConnection.Disconnect(reason);
+ }
+
+ public void DisposeInnerConnection()
+ {
+ InnerConnection.Dispose();
+ }
+
private async ValueTask ConnectionOnDisconnected(DisconnectedEventArgs e)
{
if (Client != null)
diff --git a/src/Impostor.Server/Net/State/ClientPlayer.cs b/src/Impostor.Server/Net/State/ClientPlayer.cs
index 30412a1b..7bb6164b 100644
--- a/src/Impostor.Server/Net/State/ClientPlayer.cs
+++ b/src/Impostor.Server/Net/State/ClientPlayer.cs
@@ -1,14 +1,24 @@
-using System.Threading.Tasks;
+using System;
+using System.Threading;
+using System.Threading.Tasks;
using Impostor.Api.Innersloth.Net;
using Impostor.Api.Innersloth.Net.Objects;
using Impostor.Api.Net;
+using Microsoft.Extensions.Logging;
namespace Impostor.Server.Net.State
{
internal partial class ClientPlayer : IClientPlayer
{
- public ClientPlayer(ClientBase client, Game game)
+ private readonly ILogger _logger;
+
+ private Timer _spawnTimeout;
+
+ public ClientPlayer(ILogger logger, ClientBase client, Game game)
{
+ _logger = logger;
+ _spawnTimeout = new Timer(RunSpawnTimeout, null, -1, -1);
+
Game = game;
Client = client;
Limbo = LimboStates.PreSpawn;
@@ -27,6 +37,17 @@ namespace Impostor.Server.Net.State
public string Scene { get; internal set; }
+ public void InitializeSpawnTimeout()
+ {
+ _spawnTimeout.Change(Constants.SpawnTimeout, -1);
+ }
+
+ public void DisableSpawnTimeout()
+ {
+ _spawnTimeout.Dispose();
+ _spawnTimeout = null;
+ }
+
///
public bool IsOwner(InnerNetObject netObject)
{
@@ -44,5 +65,26 @@ namespace Impostor.Server.Net.State
{
return Game.HandleKickPlayer(Client.Id, true);
}
+
+ private async void RunSpawnTimeout(object state)
+ {
+ try
+ {
+ if (Character == null)
+ {
+ _logger.LogInformation("{0} - Player {1} spawn timed out, kicking.", Game.Code, Client.Id);
+
+ await KickAsync();
+ }
+ }
+ catch (Exception e)
+ {
+ _logger.LogError(e, "Exception caught while kicking player for spawn timeout.");
+ }
+ finally
+ {
+ await _spawnTimeout.DisposeAsync();
+ }
+ }
}
}
\ No newline at end of file
diff --git a/src/Impostor.Server/Net/State/Game.Data.cs b/src/Impostor.Server/Net/State/Game.Data.cs
index d9f3396a..e4bc64fe 100644
--- a/src/Impostor.Server/Net/State/Game.Data.cs
+++ b/src/Impostor.Server/Net/State/Game.Data.cs
@@ -81,6 +81,7 @@ namespace Impostor.Server.Net.State
if (TryGetPlayer(control.OwnerId, out var player))
{
player.Character = control;
+ player.DisableSpawnTimeout();
}
// Hook up InnerPlayerControl <-> InnerPlayerControl.PlayerInfo.
diff --git a/src/Impostor.Server/Net/State/Game.Incoming.cs b/src/Impostor.Server/Net/State/Game.Incoming.cs
index 7fa778df..06b5272a 100644
--- a/src/Impostor.Server/Net/State/Game.Incoming.cs
+++ b/src/Impostor.Server/Net/State/Game.Incoming.cs
@@ -6,6 +6,7 @@ using Impostor.Api.Innersloth.Data;
using Impostor.Api.Net;
using Impostor.Api.Net.Messages;
using Impostor.Hazel;
+using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
namespace Impostor.Server.Net.State
@@ -79,7 +80,7 @@ namespace Impostor.Server.Net.State
if (player == null || player.Game != this)
{
- var clientPlayer = new ClientPlayer(client, this);
+ var clientPlayer = new ClientPlayer(_serviceProvider.GetRequiredService>(), client, this);
if (!_clientManager.Validate(client))
{
diff --git a/src/Impostor.Server/Net/State/Game.State.cs b/src/Impostor.Server/Net/State/Game.State.cs
index f62f60b2..f375e665 100644
--- a/src/Impostor.Server/Net/State/Game.State.cs
+++ b/src/Impostor.Server/Net/State/Game.State.cs
@@ -6,6 +6,7 @@ using Impostor.Api.Innersloth.Data;
using Impostor.Api.Net;
using Impostor.Api.Net.Messages;
using Impostor.Hazel;
+using Impostor.Server.Net.Hazel;
using Microsoft.Extensions.Logging;
namespace Impostor.Server.Net.State
@@ -27,6 +28,8 @@ namespace Impostor.Server.Net.State
await InitGameDataAsync(player);
}
+ player.InitializeSpawnTimeout();
+
await _eventManager.CallAsync(new PlayerJoinedGameEvent(this, player));
}
@@ -73,6 +76,18 @@ namespace Impostor.Server.Net.State
await _eventManager.CallAsync(new PlayerLeftGameEvent(this, player, isBan));
+ // Player can refuse to be kicked and keep the connection open, check for this.
+ _ = Task.Run(async () =>
+ {
+ await Task.Delay(Constants.ConnectionTimeout);
+
+ if (player.Client.Connection.IsConnected)
+ {
+ _logger.LogInformation("{0} - Player {1} ({2}) kept connection open after leaving, disposing.", Code, player.Client.Name, playerId);
+ ((HazelConnection) player.Client.Connection).DisposeInnerConnection();
+ }
+ });
+
return true;
}
diff --git a/src/Impostor.Tools.ServerReplay/Program.cs b/src/Impostor.Tools.ServerReplay/Program.cs
index 7a8802da..c9040816 100644
--- a/src/Impostor.Tools.ServerReplay/Program.cs
+++ b/src/Impostor.Tools.ServerReplay/Program.cs
@@ -42,11 +42,11 @@ namespace Impostor.Tools.ServerReplay
private static async Task Main(string[] args)
{
- // Log.Logger = new LoggerConfiguration()
- // // .MinimumLevel.Verbose()
- // .MinimumLevel.Debug()
- // .WriteTo.Console()
- // .CreateLogger();
+ Log.Logger = new LoggerConfiguration()
+ // .MinimumLevel.Verbose()
+ .MinimumLevel.Debug()
+ .WriteTo.Console()
+ .CreateLogger();
var stopwatch = Stopwatch.StartNew();