Multiplayer Hosting Guide
NetCrafter connects players through SmartFoxServer 3. This guide explains your hosting options — from dedicated servers to player-hosted sessions — and how to wire the connection layer in your game.
Overview¶
Every NetCrafter game needs a running SmartFoxServer 3 instance that all players connect to. You have two practical options for where that server lives: a dedicated server or player hosting. For smaller games that don’t need SmartFoxServer, NetCrafter Relay is a separate asset.
Dedicated Server
SFS3 runs on a VPS or cloud host. Any player can connect at any time without a host being present. Zero NAT issues. Best for shipped games.
Player Hosting
One player runs SFS3 on their own machine and forwards a port in their router. Friends connect using the host’s public IP. Good for early playtesting.
NetCrafter Relay
A separate Pivec Labs asset for smaller games. Players join with a short code through a coturn relay you host yourself — no port forwarding. See the NetCrafter Relay docs.
All options use the same connection code
The generated SmartFoxConnectionManager implements INetCrafterConnection in all three cases. Switching from playtesting to a dedicated server only requires updating the Host field in the Inspector — no code changes.
Dedicated Server¶
A dedicated server is the most reliable option and the right choice for any game you plan to ship. SmartFoxServer 3 runs on Linux and Windows VPS instances; a $6/month cloud VM handles dozens of concurrent players comfortably for most indie titles.
What you need
- A VPS or cloud instance with a static public IP (any provider: DigitalOcean, Hetzner, Linode, AWS Lightsail, etc.)
- SFS3 installed and licensed on that server
- Ports 9933 (TCP, default SFS3 binary) and 8080 (HTTP, optional) open in the server’s firewall
Pointing NetCrafter at your server
In Unity, find your generated SmartFoxConnectionManager in the scene. In the Inspector, set the Host field to your server’s public IP or hostname:
Host = "your.server.ip" // or a domain name
Port = 9933 // SFS3 binary protocol default
Zone = "BasicExamples" // must match your SFS3 zone name
That’s all. The generated connection manager handles login and room join automatically on Start().
See the Server Deployment Guide for full setup steps
The Server Deployment Guide covers installing SFS3, configuring zones, and setting up a firewall on a Linux VPS from scratch.
Manual Port Forwarding¶
For early playtesting where you don’t want to set up a dedicated server yet, one player can run SFS3 on their own machine and open a port in their home router. This requires a one-time manual step on the host’s router.
- Requires the host to manually configure their router every session (or keep a permanent rule).
- Does not work behind CGNAT (common with mobile/4G connections and some ISPs).
- The server goes offline when the host closes their game or shuts down SFS3.
- Suitable for playtesting with known friends, not for public matchmaking.
Steps for the host
ipconfig (Windows) or ifconfig (Mac/Linux). Note your local IPv4 address — typically 192.168.x.x or 10.x.x.x.192.168.1.1 or 192.168.0.1). Add a port forwarding rule: External port 9933 → Internal IP (your local IP) port 9933, protocol TCP.Public IP changes on reconnect
Most home ISPs assign dynamic public IPs. If the host’s internet reconnects overnight, their public IP may change. For stable playtesting sessions, consider a free dynamic DNS service (DuckDNS, No-IP) so friends always connect to the same hostname.
Connection Architecture¶
Understanding how NetCrafter’s connection layer is structured helps you build a clean join flow and wire up UI correctly.
INetCrafterConnection
The generated SmartFoxConnectionManager implements INetCrafterConnection, an interface declared in the NetCrafter Runtime assembly. This interface is how all of NetCrafter’s built-in components talk to the connection manager without taking a direct dependency on your generated namespace:
public interface INetCrafterConnection
{
bool IsConnected { get; }
int LocalUserId { get; }
string LocalUserName { get; }
void Connect();
void UpdateHost(string hostIP);
void SendExtensionRequest(string cmd, ISFSObject data);
}
NetCrafterEventDispatcher
NetCrafterEventDispatcher is a singleton MonoBehaviour that acts as a cross-assembly event bus. The generated connection manager dispatches named events that your UI scripts can subscribe to:
| Event name | Dispatched when | Payload |
|---|---|---|
RoomJoined | Player successfully joins a SFS3 room | null |
ConnectionLost | Connection fails or drops | string reason |
private Action<object> _roomJoinedHandler;
private void Start()
{
_roomJoinedHandler = _ => OnRoomJoined();
NetCrafterEventDispatcher.Instance?.Subscribe("RoomJoined", _roomJoinedHandler);
NetCrafterEventDispatcher.Instance?.Subscribe("ConnectionLost", OnConnectionLost);
}
private void OnDestroy()
{
NetCrafterEventDispatcher.Instance?.Unsubscribe("RoomJoined", _roomJoinedHandler);
NetCrafterEventDispatcher.Instance?.Unsubscribe("ConnectionLost", OnConnectionLost);
}
private void OnRoomJoined() { /* show game UI */ }
private void OnConnectionLost(object reason) { Debug.LogWarning("Lost: " + reason); }
UpdateHost() for player-hosted sessions
When building a player-hosted join flow, call UpdateHost() before Connect() to point the connection manager at the host’s IP. This resets any existing SFS3 socket so a fresh connection opens to the new address:
// Find SmartFoxConnectionManager via the interface — no generated-namespace dependency
var all = FindObjectsByType<MonoBehaviour>(FindObjectsInactive.Exclude, FindObjectsSortMode.None);
INetCrafterConnection cm = null;
foreach (var mb in all)
if (mb is INetCrafterConnection c) { cm = c; break; }
if (cm != null)
{
cm.UpdateHost("123.45.67.89");
cm.Connect();
}
Building a Join Flow¶
A typical player-hosted join flow consists of a UI panel where a joining player enters the host’s IP, a Connect button, status feedback, and navigation to the game scene on success or an error message on failure.
Minimal join panel script
using System;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;
using TMPro;
using PivecLabs.Netcrafter;
public class JoinPanel : MonoBehaviour
{
public TMP_InputField ipInput;
public Button connectButton;
public TMP_Text statusText;
public UnityEvent onJoinSuccess;
private Action<object> _roomJoinedHandler;
private void Start()
{
connectButton.onClick.AddListener(OnConnect);
_roomJoinedHandler = _ => OnRoomJoined();
NetCrafterEventDispatcher.Instance?.Subscribe("RoomJoined", _roomJoinedHandler);
NetCrafterEventDispatcher.Instance?.Subscribe("ConnectionLost", OnConnectionLost);
}
private void OnDestroy()
{
NetCrafterEventDispatcher.Instance?.Unsubscribe("RoomJoined", _roomJoinedHandler);
NetCrafterEventDispatcher.Instance?.Unsubscribe("ConnectionLost", OnConnectionLost);
}
private void OnConnect()
{
string ip = ipInput.text.Trim();
if (!System.Net.IPAddress.TryParse(ip, out _))
{
statusText.text = "Invalid IP address.";
return;
}
var cm = FindConnectionManager();
if (cm == null) { statusText.text = "ConnectionManager not found."; return; }
statusText.text = "Connecting to " + ip + "...";
cm.UpdateHost(ip);
cm.Connect();
}
private void OnRoomJoined() { onJoinSuccess?.Invoke(); }
private void OnConnectionLost(object r)
{
statusText.text = "Connection failed: " + r;
}
private INetCrafterConnection FindConnectionManager()
{
var all = FindObjectsByType<MonoBehaviour>(FindObjectsInactive.Exclude, FindObjectsSortMode.None);
foreach (var mb in all)
if (mb is INetCrafterConnection c) return c;
return null;
}
}
Wire onJoinSuccess in the Inspector
In the Inspector, connect onJoinSuccess to whatever should happen next — hiding the lobby panel, loading the game scene, or enabling the game HUD. The join panel doesn’t need to know what happens after a successful join.
Testing Locally¶
You can test a full multiplayer session without any router configuration by running SFS3 and two Unity Editor instances on the same machine.
SmartFoxConnectionManager Inspector, set Host to 127.0.0.1. This connects to the SFS3 instance running on the same machine.No port forwarding needed for local testing
When both instances connect to 127.0.0.1, traffic never leaves the machine. Port forwarding and public IPs are only required when players connect from different networks over the internet.
NetCrafter Relay¶
NetCrafter Relay is a separate, standalone Unity asset from Pivec Labs, available now. It is not an add-on to NetCrafter Pro and doesn’t use SmartFoxServer 3. Instead, players connect through a coturn TURN/STUN relay that you host yourself on a low-cost VPS. There is no Pivec Labs–hosted service.
When to choose Relay instead of NetCrafter Pro
- Choose NetCrafter Relay for smaller multiplayer games. One player hosts and friends join with a short code like
GAME-4892, with no port forwarding and no IP sharing, and it works behind Carrier-Grade NAT. - Choose NetCrafter Pro for larger, room-based multiplayer on SmartFoxServer 3 — server-authoritative logic, zones and rooms, and players who can connect without a host being present.
NetCrafter Relay documentation
Setup, tutorials and the relay deployment guide are in the NetCrafter Relay docs.
What’s Next¶
You understand your hosting options. Here are common next steps: