Examples (iOS)
Examples (Android)

 

» SmartFoxServer 2X HOWTOs

In this document we have collected a number of quick tutorials on how to accomplish some simple and specific tasks that you might need during the course of your work with SmartFoxServer 2X.



» How to add new Java libraries or Extension dependencies

Adding new libraries in SmartFoxServer 2X is a breeze. No messing around with the classpath: all you need to do is deploy the .jar file(s) in the proper directory and restart the server.

There are two folders that we recommend to use:

{SFS2XRoot}/lib/
This is where we would recommend adding libraries such as database drivers or other all-purpose libraries that will be used by all Zones and the Server itself. Another example would be a custom implementation of the BuddyList storage class.

{SFS2XRoot}/extensions/__lib__/
This folder is recommended for libraries that will be shared by multiple Extensions in your system. For example the "Google Collections" jar, or the Hibernate jar, etc. Do not add your Extension jar to this folder, because the AdminTool won't ba able to detect it when you setup the Zone/Room configuration.

Finally if you have one or more jar files that are going to be used by one specific Extension only, you can simply deploy these files in your Extension folder which will be something like: {SFS2XRoot}/extensions/{the-extension-name}.

^top menu


» How to setup a connection to an external Database

SFS2X allows connecting to databases in a way that is very similar to its predecessor. All you need to do is downloading the JDBC connector from your Database vendor (e.g. MySQL or MSSQL) and drop the .jar in the {SFS2XRoot}/lib/ folder.

Of course if you use ODBC instead of JDBC you can even skip the driver deployment step. In fact the ODBC driver is already provided by the Java Runtime.

The following is a list of pages where you can find the JDBC drivers for the most common RDBMS:

The next step is running the SFS2X AdminTool, launch the Zone Configurator module, select your Zone and finally click on the Database manager tab to edit the configuration.

Db Setup

At the end of the process click Submit and restart the server.

^top menu


» How to create an Extension-based custom login

Implementing a custom login on the server-side is a simple process. SFS2X fires the following two login events.

In order to add your custom login logic you should execute at least the first two of the following steps.

1) Configure the Zone

Launch the AdminTool, open the Zone Configurator module and enable your Zone's Use custom Login setting; then sestart SFS2X.

2) Server code

Create a new server-side Extension that extends the SFSExtension class. Your init() method should look like this:

@Override 
public void init() 
{ 
   trace("My CustomLogin extension starts!"); 
    
   // Register for login event 
   addEventHandler(SFSEventType.USER_LOGIN, LoginEventHandler.class); 
}    

Now create the LoginEventHandler class which will take care of the user name/password checking. In the following example two specific user names are not allowed to login.

public class LoginEventHandler extends BaseServerEventHandler 
{ 
   @Override 
   public void handleServerEvent(ISFSEvent event) throws SFSException 
   { 
      String name = (String) event.getParameter(SFSEventParam.LOGIN_NAME); 
       
      if (name.equals("Gonzo") || name.equals("Kermit")) 
      {
      	
        // Create the error code to send to the client	
        SFSErrorData errData = new SFSErrorData(SFSErrorCode.LOGIN_BAD_USERNAME);
        errData.addParameter(name);
        
        // Fire a Login exception
        throw new SFSLoginException("Gonzo and Kermit are not allowed in this Zone!", errData); 
      }
   } 
}

If one of the two unwanted names is detected, an SFSException can be fired. In doing so we provide a message that is logged on the server-side and an SFSErrorData object which contains the error code (SFSErrorCode.LOGIN_BAD_USERNAME) and the bad name itself.

Typical error codes used in this context are SFSErrorCode.LOGIN_BAD_USERNAME and SFSErrorCode.LOGIN_BAD_PASSWORD, both taking an additional parameter which is the wrong name or password.

Now this is a very simple example that just shows how to deny access to users with a name of Kermit or Gonzo. Of course your logic might require a little more sophistication but you should get the idea. When you need to stop the execution of the login process you just throw an SFSLoginException.

If no exception is thrown the system will accept the user and continue the login process.
There are other things that could go wrong during this phase, for instance:

Once all these checks are passed the user is finally logged in the Zone. At this point the server code will receive an USER_JOIN_ZONE event, if you subscribed to it.

This last step is optional and it won't be necessary in many cases.
Typically you will use this when you need to perform specific actions after the user is logged in the system (like setting User Variables, auto-join a Room, etc).

TIP
When working with asynchronous events such as USER_LOGIN and USER_JOIN_ZONE it's a bit more difficult to maintain the state of the current transaction/operation.
A convenient way to maintain the state is to use the user Session object. In particular the Session object allows to store custom parameters as key-value pairs (see the JavaDoc, methods getProperty/setProperty, etc).

3) Secure passwords

The user password is never transmitted in clear from the client to the server, for security reasons. In order to be able to compare the encrypted password with your database original password we provide a convenient method in the API.

getApi().checkSecurePassword(session, clearPass, encryptedPass);

The method call will return true if the password match and false otherwise.

On the client side there's absolutely no difference between a "standard" login and a "custom" one. All you need to do is adding a listener for the SFSEvent.LOGIN event to receive the server response, and send a LoginRequest to log into a Zone.

You can check the AS3 documentation and the examples for all the details on how to do this. For the other languages the process is the same. Another interesting reading related to this topic is the discussion about the User Permissions.

4) Change the user name at login time

There are cases in which you need to change the name provided by the user at login time with another one extracted from the database. An example is when the user logs in with an email address as the login name, but on the database you have stored his nickname, which should be used instead of the email.

We have established a simple convention that allows you to provide an alternative name to the login system. In the USER_LOGIN event you are passed an empty SFSObject that can be used to return custom data to the client. You just need to provide tha name in that object under a very specific (and reserved) key name. See code below:

public class LoginEventHandler extends BaseServerEventHandler 
{ 
   @Override 
   public void handleServerEvent(ISFSEvent event) throws SFSException 
   { 
      String name = (String) event.getParameter(SFSEventParam.LOGIN_NAME); 
      ISFSObject outData = (ISFSObject) event.getParameter(SFSEventParam.LOGIN_OUT_DATA);
       
      // ...
      // your login logic goes here
      // ...
      
      // Provide a new name for the user:
      String newName = "User-" + name;
      outData.putUtfString(SFSConstants.NEW_LOGIN_NAME, newName);
   } 
}

^top menu


» How to use the SmartFoxBits 2X

Together with SFS2X we provide the latest version of our SmartFoxBits components, which can save you a ton of time in setting up the application GUI if you are using the Adobe Flash platform to build your client.

The base SmartFoxBits pack contains five components:

You can check all the details and read the documentation on the SmartFoxBits page.

^top menu


» How to check the server logs

SFS2X provides detailed logging of all its activities. You can consult them at any time by checking the logs/ folder. Additionally under the logs/boot/ folder you will find detailed logs of the boot phase.

Should the server have any issues starting the boot logs will help you pinpoint the problem quickly.

^top menu


» How to debug your Extensions

You can easily attach a Remote Debugger to the server and enable your favorite Debugger for bug hunting in your Extensions.

SmartFoxServer 2X can be started with the sfs2x.bat (Windows) or sfs2x.sh (Linux/Unix/MacOSX) scripts. By adding some JVM switches to the launch script you can enable remote debugging. You can do it by following these steps:

If you want to keep the script allowing debug separate from the standard start script, simply duplicate the start script and modify it by adding the above switches using a text editor. Then save the script as debug.sh or debug.bat and launch it.

^top menu


» How to schedule timed tasks in an Extension

Often times in the server-side game logic it is necessary to use timers for recurring events that are sent to the clients (e.g. the end of a turn time, npc actions, etc).

A quick solution to this problem is using the ScheduledThreadPoolExecutor class provided in the JDK which offers a convenient task executor backed by a pool of threads. SFS2X already runs its own instance of this Executor (wrapped in a class called TaskScheduler).

The following snippet of Java code shows how to run a looping task using the SmartFoxServer's own TaskScheduler.

public class SchedulerTestExtension extends SFSExtension
{
	private class TaskRunner implements Runnable
	{
		private int runningCycles = 0;
		
		public void run()
		{
			try
			{
				runningCycles++;	
				trace("Inside the running task. Cycle:  " + runningCycles);
			
				if (runningCycles >= 10)
				{
					trace("Time to stop the task!");
					taskHandle.cancel();
				}
			}
			
			catch(Exception e)
			{
				e.printStackTrace();
			}
		}
	}
	
	// Keeps a reference to the task execution
	ScheduledFuture<?> taskHandle;
	
	@Override
	public void init()
	{
		SmartFoxServer sfs = SmartFoxServer.getInstance();
		
		// Schedule the task to run every second, with no initial delay
		taskHandle = sfs.getTaskScheduler().scheduleAtFixedRate(new TaskRunner(), 0, 1, TimeUnit.SECONDS);
	}
}

The scheduleAtFixedRate method takes four arguments:

  1. a Runnable object that will execute the Task's code;
  2. the initial delay before the execution starts;
  3. the interval at which the task will be executed;
  4. the time unit used to express the time values.

The Scheduler also exposes a schedule method that executes a Runnable task once after the specified amount of time. Finally the Scheduler's thread pool can be resized on-the-fly at runtime via the resizeThreadPool() method.

IMPORTANT: runtime exceptions occurring inside the run() method will stop the Task from running. If don't want your Task to be interrupted by an expected error make sure to catch any Exception that might occur.

NOTE
The initial size of the system TaskScheduler's thread pool can be adjusted via the Server Configurator module in the AdminTool.

^top menu


» How to send an email from an Extension

Emails can be sent directly from your server side code in order to provide registration confirmations, updates or even debugging and stats reports.

In order to enable email sending you will need to setup the Emailer Service from the AdminTool: from the ServerConfigurator choose the Emailer tab, turn on the service and set your SMTP parameters.

Restart the server and you are now ready to send emails using a couple of lines of code like this:

Email myEmail = new SFSEmail("sender@email.com", "recipient@email.it", "Test mail", "Hello from SFS2X");
SmartFoxServer.getInstance().getMailService().sendEmail(myEmail); 

There are three modalities to send emails: "blindly", with a confirmation event and delayed. You can learn about this and lots more from the SFSPostOffice class in the javadoc.

^top menu


» More recipes...

We have more recipes available in our SmartFoxServer Blog. Keep an eye for monthly updates and subscribe to our Twitter / FB / G+ pages for automatic updates.