• Examples (HTML5)
• Examples (iOS)
• Examples (Android)
• Examples (C++)
Server API Documentation

 

» Java Extensions: an overview

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

The diagram above shows a simplified version of the server stack, where at the bottom clients connect via a number of protocols and can invoke both the public server API and the custom functions exposed by the game developer via Extensions.

In simple terms SmartFoxServer Extensions are to games what PHP/JSP pages are to websites. They allow for custom code to run on the server side and add entirely new application logic.

In SmartFoxServer 2X 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 of that Room, while a Zone Extension can listen for a much larger number of events and controls all Rooms and users.

» Let's write an Extension

public class MyExtension extends SFSExtension
{
	@Override
	public void init()
	{
	    trace("Hello, this is my first SFS2X Extension!");
     
	    // Add a new Request Handler
	    addRequestHandler("sum", SumReqHandler.class);
	}

	public class SumReqHandler extends BaseClientRequestHandler
	{
	    @Override
	    public void handleClientRequest(User sender, ISFSObject params)
	    {
	        // 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 simple dictionary-like object to store key/value pairs, with the added benefit of declaring exactly what type each data is. This in turn allows to optimize the network usage.
More information on SFSObject is available in this document; also check the JSDoc.

Extensions can also declare a destroy() method but it's not mandatory. It is only required for deallocating resources that require manual release such as active database connections, open files, or scheduled tasks.

As a side note, the trace() method allows you to output log information on the server side.

Let's now build a small JavaScript client, connect to the server and test our custom server code:

//  SmartFox client config object
var sfsConfig = {};
sfsConfig.host = "127.0.0.1";
sfsConfig.port = 8080;
sfsConfig.zone = "BasicExamples";
sfsConfig.debug = false;

var sfs;

function run()
{
	// Create SmartFox client instance
	sfs = new SFS2X.SmartFox(sfsConfig);
	
	// Set debugging level
	sfs.logger.level = SFS2X.LogLevel.INFO;

	sfs.addEventListener(SFS2X.SFSEvent.CONNECTION, onConnection, this);
	sfs.addEventListener(SFS2X.SFSEvent.CONNECTION_LOST, onConnectionLost, this);
	sfs.addEventListener(SFS2X.SFSEvent.LOGIN, onLogin, this);
	sfs.addEventListener(SFS2X.SFSEvent.LOGIN_ERROR, onLoginError, this);
	sfs.addEventListener(SFS2X.SFSEvent.EXTENSION_RESPONSE, onExtensionResponse, this);

	sfs.connect();
}

function onConnection(evtParams) 
{
	if (evtParams.success)
	{
		console.log("Connected");
		sfs.send( new SFS2X.LoginRequest("") );
	}
	else
		console.log("Connection failed");
}

function onConnectionLost(evtParams) 
{
	console.log("--{{ Disconnected }}--");
}

function onLogin(evtParams) 
{
	console.log("Logged in as: " + sfs.mySelf.name);

	var params = new SFS2X.SFSObject();
	params.putInt("a", 25);
	params.putInt("b", 17);

	sfs.send( new SFS2X.ExtensionRequest("sum", params) );
}

function onLoginError(evtParams) 
{
	console.log("Login Error: " + evtParams.errorMessage);
}

function onExtensionResponse(evtParams) 
{
	console.log("Result: " + evtParams.params.getInt("res"));
}
        

In the onLogin() function 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 a server-side Extension can also listen for a number of Server's events, such as login events, logout, join room and many more.

Listening for server events is as simple as handling client requests: we just create a function and register it as event handler. Here's a basic example with no purpose other than demonstrating this functionality:

public class MyExtension extends SFSExtension
{
	@Override
	public void init()
	{
	    trace("Hello, this is my first SFS2X Extension!");
     
	    // Add a new Event Handler
	    addEventHandler(SFSEventType.USER_JOIN_ZONE, ZoneEventHandler.class);
	}

	@Override
	public void destroy()
	{
		trace("Destroy is called!");
	}

	public class ZoneEventHandler extends BaseServerEventHandler
	{
	    @Override
	    public void handleServerEvent(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 documentation here.

» Extension deployment

Finally we can take a look at how we can deploy our code to the server and run it. To create an extension you will need to create a new folder under SFS2X/extensions/

We then need to export our compiled Java classes to a jar file. This step is typically 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 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.

» Next steps

There is a lot more ground to cover on Extension development. Once you have digested this introduction we recommend to watch this video tutorial and follow the next articles in this section.