Table of Contents

Class ClientConnectionManager

Namespace
FishMMO.Client
Assembly
FishMMO.Client.dll

Manages client connection lifecycle: connect, disconnect, reconnect with exponential backoff, and connection state tracking. Extracted from Client.cs.

public class ClientConnectionManager
Inheritance
ClientConnectionManager
Inherited Members

Constructors

ClientConnectionManager(NetworkManager)

Creates a ClientConnectionManager and subscribes to NetworkManager connection events.

public ClientConnectionManager(NetworkManager networkManager)

Parameters

networkManager NetworkManager

The FishNet NetworkManager to manage.

Fields

EnsureConnectionToken

Optional coroutine run immediately before every StartConnection, used to obtain the one-time connection token the game server needs to recover this client's real IP.

Every game server — Login, World and Scene — sits behind the same L4 UDP proxy and binds to loopback, so all of them see 127.0.0.1 as the source address and all of them reject a handshake that arrives without a token. Hooking the fetch here rather than at the individual call sites means world/scene routing and automatic reconnects get a token too, not just the login screen.

public Func<IEnumerator> EnsureConnectionToken

Field Value

Func<IEnumerator>

Properties

CanReconnect

Returns true if the current connection type supports reconnection (World, Scene, or an in-flight world connect).

public bool CanReconnect { get; }

Property Value

bool

Remarks

ConnectingToWorld counts. ConnectToServer(string, ushort, bool) sets it for every world connect — including the reconnects TryReconnect() issues — and FishMMO.Client.ClientConnectionManager.OnClientConnectionState(FishNet.Transporting.ClientConnectionStateArgs) clears CurrentConnectionType to None on the drop that arms the retry, so by the time an attempt fails ConnectingToWorld is the only type left describing it. Without it here, a failed reconnect read as a non-reconnectable failure: no further retry was armed, so MaxReconnectAttempts never counted past one, OnReconnectFailed (and its quit-to-login forward) never fired, and the client sat disconnected with no path forward. lastWorldAddress is assigned before StartConnection on that same path, so a retry always has an address to dial — and TryReconnect no-ops when it does not.

ClientState

The current local connection state (Stopped, Starting, Started, Stopping).

public LocalConnectionState ClientState { get; }

Property Value

LocalConnectionState

ConnectionEstablishTimeoutSeconds

Timeout in seconds waiting for a new connection to reach Started state. Default 20.

public float ConnectionEstablishTimeoutSeconds { get; set; }

Property Value

float

ConnectionStopTimeoutSeconds

Timeout in seconds waiting for a connection to fully stop. Default 10.

public float ConnectionStopTimeoutSeconds { get; set; }

Property Value

float

CurrentConnectionType

The type of server currently connecting to (None, Login, World, Scene).

public ServerConnectionType CurrentConnectionType { get; set; }

Property Value

ServerConnectionType

IsSceneHandoffReconnect

True when the reconnect currently armed or in progress was caused by a scene server deliberately handing the client back, rather than by a lost connection.

public bool IsSceneHandoffReconnect { get; }

Property Value

bool

Remarks

A zone change, a channel switch and a cross-scene bind-point respawn are all implemented as a deliberate drop, so from the outside they are the same event as an outage: OnReconnectPending and OnReconnectAttempt fire for both. Anything that explains the wait to the player needs to tell them apart — labelling a routine teleport "connection lost" is worse than saying nothing at all.

Set alongside the shortened handoff backoff in FishMMO.Client.ClientConnectionManager.OnClientConnectionState(FishNet.Transporting.ClientConnectionStateArgs) and cleared once a connection is established, so it describes the wait that is actually running.

MaxReconnectAttempts

Maximum reconnect attempts before giving up. Range [1, 255]. Default 10.

public int MaxReconnectAttempts { get; set; }

Property Value

int

MaxReconnectDelay

Maximum delay in seconds for exponential backoff. Default 60.

public float MaxReconnectDelay { get; set; }

Property Value

float

NetworkManager

The FishNet NetworkManager managing this client connection.

public NetworkManager NetworkManager { get; }

Property Value

NetworkManager

ReconnectAttemptWaitTime

Base wait time in seconds between reconnect attempts. Default 5.

public float ReconnectAttemptWaitTime { get; set; }

Property Value

float

ReconnectsAttempted

Number of reconnect attempts made since the last successful connection.

public int ReconnectsAttempted { get; }

Property Value

int

SceneHandoffReconnectDelay

Delay used for the first retry after a scene server hands the client back, instead of the full backoff. Jittered so a scene-wide event does not send every client at once.

public float SceneHandoffReconnectDelay { get; set; }

Property Value

float

Remarks

A scene-to-scene transfer is implemented as a deliberate drop: the scene server releases the character and disconnects, and the client is expected to return to the world server to be re-routed. That return went through the ordinary reconnect backoff, so every teleport and channel switch cost a full ReconnectAttemptWaitTime (5s) of dead time — during which the scene has already unloaded and the loading overlay has already been dismissed by OnSceneEndUnload, leaving the player looking at an empty world.

Only the first attempt is fast-pathed, and only from a Scene connection. If that attempt fails the normal exponential backoff resumes from attempt 1, so a genuinely unreachable world server is still not hammered.

Methods

CancelReconnect()

Cancels pending reconnect and fires OnReconnectFailed immediately.

public void CancelReconnect()

ConnectToServer(string, ushort, bool)

Initiates a connection. Guards against concurrent calls via CAS.

public void ConnectToServer(string address, ushort port, bool isWorldServer = false)

Parameters

address string

Server IP or hostname.

port ushort

Server port.

isWorldServer bool

If true, stores address for reconnection logic.

ForceDisconnect()

Forces the connection closed and prevents auto-reconnect until reset.

public void ForceDisconnect()

Remarks

The suppression flag is only latched when there is a connection left to tear down. FishMMO.Client.ClientConnectionManager.OnClientConnectionState(FishNet.Transporting.ClientConnectionStateArgs) is what consumes it, so latching it against a connection that is already Stopped strands it: no further Stopped transition is raised to clear it, and the next ConnectToServer(string, ushort, bool) aborts inside OnAwaitingConnectionReady(string, ushort, bool) — silently, with the guard released and no connection started. The login screen reaches that state routinely, because every auth-error dialog calls this whether or not the transport is still up.

IsConnectionReady(bool)

Returns true if connected and optionally authenticated.

public bool IsConnectionReady(bool requireAuthentication = true)

Parameters

requireAuthentication bool

If true, also checks connection is authenticated.

Returns

bool

True if the connection is ready for use.

ResetReconnectState()

Resets all reconnect state: attempt count, connection type, stored address.

public void ResetReconnectState()

Shutdown()

Unsubscribes from NetworkManager events. Call during client teardown.

public void Shutdown()

TryReconnect()

Attempts a reconnect with exponential backoff. The backoff delay is set in FishMMO.Client.ClientConnectionManager.OnClientConnectionState(FishNet.Transporting.ClientConnectionStateArgs) when the connection stops and counted down in Update(). This method is called by Update() when the timer expires — it must NOT reset the delay or the reconnect will never fire.

public void TryReconnect()

Update()

Drives reconnect timer. Called every frame from the owning client.

public void Update()

Events

OnConnectionAttemptFailed

Fired when a non-reconnectable connection attempt fails (e.g. login server unreachable).

public event Action OnConnectionAttemptFailed

Event Type

Action

OnConnectionSuccessful

Fired when a connection to the server is successfully established.

public event Action OnConnectionSuccessful

Event Type

Action

OnReconnectAttempt

Fired on each reconnect attempt with current and max attempt counts.

public event Action<int, int> OnReconnectAttempt

Event Type

Action<int, int>

OnReconnectFailed

Fired when all reconnect attempts are exhausted without success.

public event Action OnReconnectFailed

Event Type

Action

OnReconnectPending

Fired the moment a reconnect is armed, before the backoff delay begins.

public event Action OnReconnectPending

Event Type

Action

Remarks

OnReconnectAttempt fires when the retry actually starts, which leaves the whole backoff window unreported. That window is not idle time during a scene transfer: the scene server has already unloaded the client's scene, so the loading overlay has been dismissed by the unload-end event and the player is looking at an empty world until the retry fires. Shortening the delay for a deliberate hop reduces that to a flicker; this event closes it, by letting the overlay treat "a reconnect is coming" as a transition in progress rather than waiting for it to begin.