### Client-Host (Listen Server) Socket Initialization Source: https://context7.com/firstgeargames/fishyfacepunch/llms.txt This pattern starts the server first, then initiates a client connection on the same instance. Fish-Net's NetworkManager.StartHost() automatically uses ClientHostSocket for an in-process loopback when the server is already running, avoiding the Steam network. ```csharp // Pattern: start server first, then start client on the same instance // Fish-Net's NetworkManager.StartHost() does exactly this sequence: transport.StartConnection(server: true); // opens relay socket, sets LocalUserSteamID // ... wait for OnServerConnectionState → Started ... transport.StartConnection(server: false); // detects server running → uses ClientHostSocket // Internally, ClientHostSocket.SendToServer packs a LocalPacket and hands it // directly to ServerSocket.ReceivedFromClientHost — no Steam round-trip: // // LocalPacket packet = new LocalPacket(segment, channelId); // _server.ReceivedFromClientHost(packet); // // And server → host-client path: // LocalPacket packet = new LocalPacket(segment, channelId); // _clientHost.ReceivedFromLocalServer(packet); // CLIENT_HOST_ID is the reserved connection ID for the local host client Debug.Log(FishyFacepunch.CLIENT_HOST_ID); // 32767 (short.MaxValue) ``` -------------------------------- ### Dedicated Server Mode Configuration Source: https://context7.com/firstgeargames/fishyfacepunch/llms.txt For headless dedicated-server builds, define UNITY_SERVER. The server uses a standard NetAddress-bound socket, skipping Steam client initialization. Ensure the bind address and port are set before starting the connection. ```csharp // Dedicated server startup (UNITY_SERVER build): // SteamNetworkingSockets.CreateNormalSocket(NetAddress.From(bindAddress, port)) // is used instead of CreateRelaySocket. // Set bind address before starting: transport.SetServerBindAddress("0.0.0.0", IPAddressType.IPv4); transport.SetPort(27015); transport.SetMaximumClients(64); transport.StartConnection(server: true); // Clients connecting to a dedicated server use an IP address, not a SteamID64: // SteamNetworkingSockets.ConnectNormal(NetAddress.From(address, port)) transport.SetClientAddress("192.168.1.100"); // IP of dedicated server transport.StartConnection(server: false); ``` -------------------------------- ### FishyFacepunch Transport Component Configuration and Usage Source: https://context7.com/firstgeargames/fishyfacepunch/llms.txt Configure and use the FishyFacepunch transport component. Set Steam App ID, port, and maximum clients via the Inspector or at runtime. Start and stop server/client connections, and access the local user's SteamID. ```csharp // Inspector-configured fields (set via Unity Inspector or at runtime before StartConnection): // _steamAppID (uint) – Steam App ID (default: 480, Spacewar test app) // _port (ushort) – Port for dedicated-server normal socket (default: 27015) // _maximumClients (ushort) – Max simultaneous remote connections (default: 16) // _clientAddress (string) – SteamID64 of the host to connect to // _timeout (int) – Connection attempt timeout in seconds (default: 25) // Runtime access via NetworkManager FishyFacepunch transport = networkManager.TransportManager.Transport as FishyFacepunch; // Read local user's SteamID after server starts (display to players who want to join) ulong mySteamId = transport.LocalUserSteamID; Debug.Log($"Share this SteamID with players who want to join: {mySteamId}"); // Override settings at runtime before starting transport.SetClientAddress("76561198012345678"); // host's SteamID64 transport.SetPort(27015); transport.SetMaximumClients(32); // Start server (host) bool serverStarted = transport.StartConnection(server: true); // Start client (connect to a remote host's SteamID64) transport.SetClientAddress("76561198012345678"); bool clientStarted = transport.StartConnection(server: false); // Stop gracefully transport.StopConnection(server: true); transport.StopConnection(server: false); // Full shutdown (stops both client and server) transport.Shutdown(); ``` -------------------------------- ### Initialize Method Source: https://context7.com/firstgeargames/fishyfacepunch/llms.txt Called automatically by Fish-Net's NetworkManager. Initializes the Steam client (if not already initialised by another system), enables Steam P2P relay, and prepares the three socket instances. On dedicated servers (`UNITY_SERVER` define), the Steam client initialisation and relay step are skipped. ```APIDOC ## Initialization: `Initialize` Called automatically by Fish-Net's `NetworkManager`. Initialises the Steam client (if not already initialised by another system), enables Steam P2P relay, and prepares the three socket instances. On dedicated servers (`UNITY_SERVER` define), the Steam client initialisation and relay step are skipped. ```csharp // Fish-Net calls this internally; shown here for clarity on what happens during setup. // Manual call pattern when embedding without NetworkManager: var go = new GameObject("NetworkManager"); var nm = go.AddComponent(); var tm = go.AddComponent(); var transport = go.AddComponent(); // Fish-Net will call: // transport.Initialize(nm, transportIndex: 0); // Internally this runs: // SteamClient.Init(steamAppID, asyncCallbacks: true); // skipped if already valid // SteamNetworking.AllowP2PPacketRelay(true); // _clientHost.Initialize(transport); // _client.Initialize(transport); // _server.Initialize(transport); // After initialization, LocalUserSteamID is populated when the server starts: transport.OnServerConnectionState += args => { if (args.ConnectionState == LocalConnectionState.Started) Debug.Log($"Server started. Local SteamID: {transport.LocalUserSteamID}"); }; ``` ``` -------------------------------- ### FishyFacepunch Transport Initialization Source: https://context7.com/firstgeargames/fishyfacepunch/llms.txt Understand the initialization process of the FishyFacepunch transport. This includes initializing the Steam client, enabling P2P relay, and preparing socket instances. Note that Steam client initialization is skipped for dedicated servers. ```csharp // Fish-Net calls this internally; shown here for clarity on what happens during setup. // Manual call pattern when embedding without NetworkManager: var go = new GameObject("NetworkManager"); var nm = go.AddComponent(); var tm = go.AddComponent(); var transport = go.AddComponent(); // Fish-Net will call: // transport.Initialize(nm, transportIndex: 0); // Internally this runs: // SteamClient.Init(steamAppID, asyncCallbacks: true); // skipped if already valid // SteamNetworking.AllowP2PPacketRelay(true); // _clientHost.Initialize(transport); // _client.Initialize(transport); // _server.Initialize(transport); // After initialization, LocalUserSteamID is populated when the server starts: transport.OnServerConnectionState += args => { if (args.ConnectionState == LocalConnectionState.Started) Debug.Log($"Server started. Local SteamID: {transport.LocalUserSteamID}"); }; ``` -------------------------------- ### Incoming / Outgoing Iteration and Data Handling Source: https://context7.com/firstgeargames/fishyfacepunch/llms.txt Details on how to manually iterate through incoming and outgoing data buffers, and how to subscribe to events for receiving parsed data on the server and client. ```APIDOC ## Incoming / Outgoing Iteration: `IterateIncoming` / `IterateOutgoing` Fish-Net drives these every frame tick. `IterateIncoming` pulls up to 256 messages per socket call from the Steam message queue and dispatches them via `HandleServerReceivedDataArgs` / `HandleClientReceivedDataArgs`. `IterateOutgoing` flushes the Steam send buffer for each active connection. ```csharp // Fish-Net calls these automatically each tick; replicated here for custom loop usage: void Update() { // Pull all pending messages off Steam's internal queues transport.IterateIncoming(server: true); // process data arriving at the server transport.IterateIncoming(server: false); // process data arriving at the client // Flush outbound send buffers transport.IterateOutgoing(server: true); transport.IterateOutgoing(server: false); } // Subscribe to receive parsed data transport.OnServerReceivedData += (ServerReceivedDataArgs args) => { byte[] data = args.Data.Array; int length = args.Data.Count; int offset = args.Data.Offset; Channel channel = args.Channel; int fromConnection = args.ConnectionId; Debug.Log($"Server received {length} bytes on channel {channel} from connection {fromConnection}"); }; transport.OnClientReceivedData += (ClientReceivedDataArgs args) => { string msg = System.Text.Encoding.UTF8.GetString( args.Data.Array, args.Data.Offset, args.Data.Count); Debug.Log($"Client received: {msg} on channel {args.Channel}"); }; ``` ``` -------------------------------- ### Connection State Events and Queries Source: https://context7.com/firstgeargames/fishyfacepunch/llms.txt This section covers the events and methods related to managing and querying connection states for both server and client sockets, as well as individual remote connections. ```APIDOC ## Connection State Events Three events expose connection lifecycle changes to the rest of the application. ```csharp FishyFacepunch transport = GetComponent(); // Fired when the local server socket changes state transport.OnServerConnectionState += (ServerConnectionStateArgs args) => { Debug.Log($"Server state: {args.ConnectionState}"); // States: Starting → Started | Stopping → Stopped }; // Fired when the local client socket changes state transport.OnClientConnectionState += (ClientConnectionStateArgs args) => { Debug.Log($"Client state: {args.ConnectionState}"); }; // Fired when a remote client connects to or disconnects from the server transport.OnRemoteConnectionState += (RemoteConnectionStateArgs args) => { if (args.ConnectionState == RemoteConnectionState.Started) Debug.Log($"Remote client {args.ConnectionId} connected."); else Debug.Log($"Remote client {args.ConnectionId} disconnected."); }; // Query current states at any time LocalConnectionState serverState = transport.GetConnectionState(server: true); LocalConnectionState clientState = transport.GetConnectionState(server: false); RemoteConnectionState remoteState = transport.GetConnectionState(connectionId: 3); string address = transport.GetConnectionAddress(connectionId: 3); // returns SteamID64 string ``` ``` -------------------------------- ### Send Data Using FishyFacepunch Transport Source: https://context7.com/firstgeargames/fishyfacepunch/llms.txt Utilize SendToServer and SendToClient methods for low-level data transmission. Channel 0 is reliable, and channel 1 is unreliable. Use GetMTU to check message size limits and StopConnection to disconnect clients. ```csharp // From client → server (Fish-Net calls this; shown for custom transport usage) byte[] payload = System.Text.Encoding.UTF8.GetBytes("Hello Server"); var segment = new ArraySegment(payload); transport.SendToServer(channelId: 0, segment); // channel 0 = Reliable // From server → specific client (connectionId obtained from OnRemoteConnectionState) byte[] response = System.Text.Encoding.UTF8.GetBytes("Hello Client"); var responseSegment = new ArraySegment(response); transport.SendToClient(channelId: 1, responseSegment, connectionId: 2); // channel 1 = Unreliable // MTU limits per channel int reliableMTU = transport.GetMTU(0); // 1,048,576 bytes int unreliableMTU = transport.GetMTU(1); // 1,200 bytes // Disconnect a specific remote client from the server transport.StopConnection(connectionId: 2, immediately: false); ``` -------------------------------- ### Handle Connection State Events in FishyFacepunch Source: https://context7.com/firstgeargames/fishyfacepunch/llms.txt Subscribe to connection state changes for the server, client, and remote connections. Use these events to log state transitions or react to client connect/disconnect actions. ```csharp FishyFacepunch transport = GetComponent(); // Fired when the local server socket changes state transport.OnServerConnectionState += (ServerConnectionStateArgs args) => { Debug.Log($ ``` ```csharp // States: Starting → Started | Stopping → Stopped }; // Fired when the local client socket changes state transport.OnClientConnectionState += (ClientConnectionStateArgs args) => { Debug.Log($"Client state: {args.ConnectionState}"); }; // Fired when a remote client connects to or disconnects from the server transport.OnRemoteConnectionState += (RemoteConnectionStateArgs args) => { if (args.ConnectionState == RemoteConnectionState.Started) Debug.Log($"Remote client {args.ConnectionId} connected."); else Debug.Log($"Remote client {args.ConnectionId} disconnected."); }; // Query current states at any time LocalConnectionState serverState = transport.GetConnectionState(server: true); LocalConnectionState clientState = transport.GetConnectionState(server: false); RemoteConnectionState remoteState = transport.GetConnectionState(connectionId: 3); string address = transport.GetConnectionAddress(connectionId: 3); // returns SteamID64 string ``` -------------------------------- ### Process Incoming and Outgoing Messages in FishyFacepunch Source: https://context7.com/firstgeargames/fishyfacepunch/llms.txt Manually iterate through incoming messages and flush outgoing buffers using IterateIncoming and IterateOutgoing. Subscribe to OnServerReceivedData and OnClientReceivedData to handle received data. ```csharp // Fish-Net calls these automatically each tick; replicated here for custom loop usage: void Update() { // Pull all pending messages off Steam's internal queues transport.IterateIncoming(server: true); // process data arriving at the server transport.IterateIncoming(server: false); // process data arriving at the client // Flush outbound send buffers transport.IterateOutgoing(server: true); transport.IterateOutgoing(server: false); } // Subscribe to receive parsed data transport.OnServerReceivedData += (ServerReceivedDataArgs args) => { byte[] data = args.Data.Array; int length = args.Data.Count; int offset = args.Data.Offset; Channel channel = args.Channel; int fromConnection = args.ConnectionId; Debug.Log($"Server received {length} bytes on channel {channel} from connection {fromConnection}"); }; transport.OnClientReceivedData += (ClientReceivedDataArgs args) => { string msg = System.Text.Encoding.UTF8.GetString( args.Data.Array, args.Data.Offset, args.Data.Count); Debug.Log($"Client received: {msg} on channel {args.Channel}"); }; ``` -------------------------------- ### Sending Data: SendToServer / SendToClient Source: https://context7.com/firstgeargames/fishyfacepunch/llms.txt Provides methods for sending data to the server or a specific client, along with utilities for retrieving Maximum Transmission Unit (MTU) sizes and disconnecting clients. ```APIDOC ## Sending Data: `SendToServer` / `SendToClient` Low-level send methods called by Fish-Net internally. Channel 0 uses Steam's `Reliable` send flag; channel 1 uses `Unreliable`. The channel index is packed as the trailing byte of each message so the receiver can strip it out on arrival. ```csharp // From client → server (Fish-Net calls this; shown for custom transport usage) byte[] payload = System.Text.Encoding.UTF8.GetBytes("Hello Server"); var segment = new ArraySegment(payload); transport.SendToServer(channelId: 0, segment); // channel 0 = Reliable // From server → specific client (connectionId obtained from OnRemoteConnectionState) byte[] response = System.Text.Encoding.UTF8.GetBytes("Hello Client"); var responseSegment = new ArraySegment(response); transport.SendToClient(channelId: 1, responseSegment, connectionId: 2); // channel 1 = Unreliable // MTU limits per channel int reliableMTU = transport.GetMTU(0); // 1,048,576 bytes int unreliableMTU = transport.GetMTU(1); // 1,200 bytes // Disconnect a specific remote client from the server transport.StopConnection(connectionId: 2, immediately: false); ``` ``` -------------------------------- ### FishyConnectionManager Client Callback Shim Source: https://context7.com/firstgeargames/fishyfacepunch/llms.txt FishyConnectionManager is used by the client's outbound connection. It forwards raw message pointers to FishyFacepunch's processing pipeline via an Action delegate, minimizing allocations. ```csharp // FishyConnectionManager is used by the client's outbound connection: public class FishyConnectionManager : ConnectionManager { public Action ForwardMessage; public override void OnMessage(IntPtr data, int size, long messageNum, long recvTime, int channel) { ForwardMessage(data, size); // dispatches to ClientSocket.OnMessageReceived } } // ProcessMessage (inside CommonSocket) strips the trailing channel byte: // protected (byte[], int) ProcessMessage(IntPtr ptrs, int size) // { // byte[] managedArray = new byte[size]; // Marshal.Copy(ptrs, managedArray, 0, size); // int channel = managedArray[managedArray.Length - 1]; // Array.Resize(ref managedArray, managedArray.Length - 1); // return (managedArray, channel); // } ``` -------------------------------- ### FishyFacepunch Transport Component Source: https://context7.com/firstgeargames/fishyfacepunch/llms.txt The main MonoBehaviour/Transport component that Fish-Net's NetworkManager drives. Attach it to the same GameObject as a TransportManager, enter your Steam App ID, and Fish-Net will call Initialize, StartConnection, IterateIncoming, IterateOutgoing, and Shutdown automatically. ```APIDOC ## Transport Component: `FishyFacepunch` The main `MonoBehaviour`/`Transport` component that Fish-Net's `NetworkManager` drives. Attach it to the same GameObject as a `TransportManager`, enter your Steam App ID, and Fish-Net will call `Initialize`, `StartConnection`, `IterateIncoming`, `IterateOutgoing`, and `Shutdown` automatically. ```csharp // Inspector-configured fields (set via Unity Inspector or at runtime before StartConnection): // _steamAppID (uint) – Steam App ID (default: 480, Spacewar test app) // _port (ushort) – Port for dedicated-server normal socket (default: 27015) // _maximumClients (ushort) – Max simultaneous remote connections (default: 16) // _clientAddress (string) – SteamID64 of the host to connect to // _timeout (int) – Connection attempt timeout in seconds (default: 25) // Runtime access via NetworkManager FishyFacepunch transport = networkManager.TransportManager.Transport as FishyFacepunch; // Read local user's SteamID after server starts (display to players who want to join) ulong mySteamId = transport.LocalUserSteamID; Debug.Log($"Share this SteamID with players who want to join: {mySteamId}"); // Override settings at runtime before starting transport.SetClientAddress("76561198012345678"); // host's SteamID64 transport.SetPort(27015); transport.SetMaximumClients(32); // Start server (host) bool serverStarted = transport.StartConnection(server: true); // Start client (connect to a remote host's SteamID64) transport.SetClientAddress("76561198012345678"); bool clientStarted = transport.StartConnection(server: false); // Stop gracefully transport.StopConnection(server: true); transport.StopConnection(server: false); // Full shutdown (stops both client and server) transport.Shutdown(); ``` ``` -------------------------------- ### FishySocketManager Server Callback Shim Source: https://context7.com/firstgeargames/fishyfacepunch/llms.txt FishySocketManager is used by the server's relay or normal socket. It forwards raw message pointers to FishyFacepunch's processing pipeline via an Action delegate to avoid allocations in the hot path. ```csharp // FishySocketManager is used by the server's relay/normal socket: public class FishySocketManager : SocketManager { public Action ForwardMessage; public override void OnMessage(Connection connection, NetIdentity identity, IntPtr data, int size, long messageNum, long recvTime, int channel) { ForwardMessage(connection, data, size); // dispatches to ServerSocket.OnMessageReceived } } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.