Quick Start
SmartFoxServer allows developers to write their server side code to extend the server's capabilities, integrate it with other services and manage the game state in a centralized and authoritative place.

The diagram illustrates the essential components of the server stack: at the bottom clients connect via a number of protocols and send requests to the public server API (SystemController) or custom code (Extension Controller) exposed by the developer's Extensions.
If you're familiar with web development, Extensions are to games what PHP/JSP code is to websites. They allow custom code to run on the server side and manage the application logic.
In SmartFoxServer, Extensions can be attached to a Zone or a Room depending on the scope of the Extension itself. A Room Extension has a smaller scope, dealing with events, calls and users from that Room, while a Zone Extension can listen for a much larger number of events and controls all the Rooms and Users under that Zone.
A common use case for Room Extensions is to manage the logic of a specific game. You can then create any number of game Rooms and attach the appropriate Extension depending on the game that was selected.
Steps to build an Extension
From a high level perspective, these are the steps required to build and deploy your Extension:
- Create a class that inherits from the SFSExtension class in Java (or Kotlin/Scala/Groovy)
- Generate a .jar file and place it under server/extensions/{ExtensionName}
- Using the AdminTool > Zone Configurator tell the server which Extension should be loaded
- Restart SmartFoxServer
Let's write an Extension
The following is a simple Extension example:
public class MyExtension extends SFSExtension
{
@Override
public void init()
{
trace("Hello, this is my first SFS3 Extension!");
// Add a new Request Handler
addRequestHandler("sum", SumReqHandler.class);
}
public static class SumReqHandler extends BaseClientRequestHandler
{
@Override
public void handleClientRequest(User sender, ISFSObject params, TransportType txType)
{
// Get the client parameters
int n1 = params.getInt("n1");
int n2 = params.getInt("n2");
// Create a response object
ISFSObject resObj = new SFSObject();
resObj.putInt("res", n1 + n2);
// Send it back
send("sum", resObj, sender);
}
}
}
Every Extension inherits from the SFSExtension base class and implements an init() method, which is called by the server at start up. Here we can initialize global objects or data structures and register event handlers. In this example we declare a command called "sum" which is handled by our SumReqHandler.
The handler extracts the parameters from the SFSObject passed by the client (used to transport data between client and server) and sends the response back. You can think of SFSObject as a dictionary-like object that holds key/value pairs, with the added benefit of using a different data type for each item. This in turn allows to optimize the network usage. More information on SFSObject/Array is available in this document.
Extensions can also declare a destroy() method but it's not mandatory. It is only required for deallocating resources that need manual release such as active database connections, open files, or scheduled tasks.
Also notice the trace() method used to output log information on the server side.
Let's now build a simple client to connect to the server and test our custom server code:
public class ExtensionTester : MonoBehaviour
{
private SmartFox sfs;
void Start()
{
// Create SmartFox client instance
sfs = new SmartFox();
// Add event listeners
sfs.AddEventListener(SFSEvent.CONNECTION, OnConnection);
sfs.AddEventListener(SFSEvent.CONNECTION_LOST, OnConnectionLost);
sfs.AddEventListener(SFSEvent.LOGIN, OnLogin);
sfs.AddEventListener(SFSEvent.LOGIN_ERROR, OnLoginError);
sfs.AddEventListener(SFSEvent.EXTENSION_RESPONSE, OnExtensionResponse);
// Set connection parameters
var cfg = new ConfigData();
cfg.Host = "127.0.0.1";
cfg.Port = 9977;
cfg.Zone = "Playground";
// Connect to SFS
sfs.Connect(cfg);
}
void Update()
{
if (sfs != null)
sfs.ProcessEvents();
}
private void OnConnection(ApiEvent evt)
{
var success = (bool) evt.Params[EventParam.Success]!;
if (success)
{
Debug.Log("Connected");
// Send login request
sfs.Send(new LoginRequest(""));
}
else
Debug.Log("Connection failed");
}
private void OnConnectionLost(ApiEvent evt)
{
Debug.Log("Disconnected");
}
private void OnLogin(ApiEvent evt)
{
Debug.Log("Logged in as: " + sfs.MySelf!.Name);
// Send test request to Extension
ISFSObject params = new SFSObject();
params.PutInt("n1", 20);
params.PutInt("n2", 30);
sfs.Send(new ExtensionRequest("sum", params));
}
private void OnLoginError(ApiEvent evt)
{
var errMsg = (string) evt.Params[EventParam.ErrorMessage]!;
Debug.LogError("Login error: " + errMsg);
}
private void OnExtensionResponse(ApiEvent evt)
{
// Retrieve response object
var responseParams = (SFSObject) evt.Params[EventParam.ExtParams]!;
var res = (int?) responseParams.GetInt("res");
if (res != null)
Debug.Log("Result: " + res);
}
}
In the OnLogin() handler we wrap our parameters and send the command via the ExtensionRequest object. To handle the server response we make sure to register for the EXTENSION_RESPONSE event and read the result using the same key(s) used on the server side.
Server Side Events
In addition to handling client requests an Extension can also listen for a number of Server events, such as login, logout, room join and many more. Let's take a look:
public class MyExtension extends SFSExtension
{
@Override
public void init()
{
trace("My Extension is running!");
// Add a new Event Handler
addEventHandler(SFSEventType.USER_JOIN_ZONE, this::handleJoinZone);
}
@Override
public void destroy()
{
// Always make sure to invoke the parent class first
super.destroy();
trace("Destroy was called!");
}
void handleJoinZone(ISFSEvent event) throws SFSException
{
User user = (User) event.getParameter(SFSEventParam.USER);
trace("Welcome new user: " + user.getName());
}
}
Each event provides a number of parameters that can be accessed as shown in the code. For a full list of events, check the server side API documentation.
Extension deployment
Let's take a look at how Extensions are deployed on SmartFoxServer. To deploy your Extension you will need to create a new folder under server/extensions/.
We then need to export our compiled Java classes to a jar file. This step is done with the help of your IDE of choice such as Eclipse, Netbeans or Intellij IDEA. Next we open the AdminTool, select the Zone Configurator and click the Zone Extension tab.

First make sure the Type dropdown is set to JAVA, then from the top dropdown select the Extension folder and the main Extension class, which is the one with the init() method. We can now save and restart the server to activate the changes.
The Reload mode option set to AUTO allows to auto-reload an Extension every time a change is made to the main file, thus making it very quick to reload our code on the fly. This is convenient for development and testing but in production it is best to set this to MANUAL to avoid accidental reloads.
Note:
If you want to attach the Extension to a specific Room instead of a Zone you can repeat the same exact process, this time selecting the target Room from the Zone Configurator.