GeoSus
This commit is contained in:
@@ -132,7 +132,20 @@ public class GameClient : IDisposable
|
||||
return false;
|
||||
}
|
||||
|
||||
public void Disconnect(string reason = "User disconnected")
|
||||
/// <summary>
|
||||
/// Tears down the socket and crypto session. When `transient` is true
|
||||
/// (network drop, decrypt-failure cascade, anything we expect to retry),
|
||||
/// the lobby/role/task/state caches are preserved so the post-reconnect
|
||||
/// flow can re-associate via Reconnect(LobbyId). Default false matches
|
||||
/// pre-P9 behavior (full state wipe) for explicit user disconnects.
|
||||
///
|
||||
/// Critical for the P9 reconnect bug: previously every Disconnect path
|
||||
/// nuked LobbyId, so by the time GameManager_Network's reconnect coroutine
|
||||
/// fired, the client had no idea which lobby it had been in - the
|
||||
/// post-handshake Reconnect call had nothing to send and the server
|
||||
/// answered the next vote/action with NOT_IN_LOBBY.
|
||||
/// </summary>
|
||||
public void Disconnect(string reason = "User disconnected", bool transient = false)
|
||||
{
|
||||
_cts?.Cancel();
|
||||
_tcpClient?.Close();
|
||||
@@ -140,15 +153,22 @@ public class GameClient : IDisposable
|
||||
_stream = null;
|
||||
_encryption?.Dispose();
|
||||
_encryption = null;
|
||||
|
||||
LobbyId = null;
|
||||
JoinCode = null;
|
||||
CurrentLobbyState = null;
|
||||
MyRole = null;
|
||||
MyTasks.Clear();
|
||||
PlayerPositions.Clear();
|
||||
Bodies.Clear();
|
||||
|
||||
|
||||
if (!transient)
|
||||
{
|
||||
LobbyId = null;
|
||||
JoinCode = null;
|
||||
CurrentLobbyState = null;
|
||||
MyRole = null;
|
||||
MyTasks.Clear();
|
||||
PlayerPositions.Clear();
|
||||
Bodies.Clear();
|
||||
}
|
||||
// PlayerPositions are stale anyway after a drop, but we keep them so
|
||||
// the UI doesn't blink avatars off-map mid-meeting; the next position
|
||||
// broadcast overwrites them. LastEventId is intentionally preserved
|
||||
// so the Reconnect message can ask the server for missed events.
|
||||
|
||||
Dispatcher.Post(() => OnDisconnected?.Invoke(reason));
|
||||
}
|
||||
|
||||
@@ -236,7 +256,8 @@ public class GameClient : IDisposable
|
||||
decryptFailures++;
|
||||
if (decryptFailures >= 3)
|
||||
{
|
||||
Disconnect("Too many decryption failures");
|
||||
// Transient: keep LobbyId for the reconnect coroutine.
|
||||
Disconnect("Too many decryption failures", transient: true);
|
||||
return;
|
||||
}
|
||||
continue;
|
||||
@@ -253,7 +274,9 @@ public class GameClient : IDisposable
|
||||
}
|
||||
catch (Exception ex) when (!ct.IsCancellationRequested)
|
||||
{
|
||||
Disconnect($"Connection error: {ex.Message}");
|
||||
// Transient: TCP RST / read failure is exactly what reconnect was
|
||||
// designed for. Keep LobbyId so post-reconnect flow can re-attach.
|
||||
Disconnect($"Connection error: {ex.Message}", transient: true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -508,7 +531,7 @@ public class GameClient : IDisposable
|
||||
|
||||
#region Game Actions
|
||||
|
||||
public void CreateLobby(Position? center = null, int impostorCount = 1, int taskCount = 5, string? password = null, double playAreaRadius = 500)
|
||||
public void CreateLobby(Position? center = null, int impostorCount = 1, int taskCount = 5, string? password = null, double playAreaRadius = 500, GameSettingsOverrides? settings = null)
|
||||
{
|
||||
Send(new CreateLobby
|
||||
{
|
||||
@@ -516,7 +539,8 @@ public class GameClient : IDisposable
|
||||
PlayAreaRadius = playAreaRadius,
|
||||
ImpostorCount = impostorCount,
|
||||
TaskCount = taskCount,
|
||||
Password = password
|
||||
Password = password,
|
||||
Settings = settings
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user