Custom Room Storage with SFS2X 2.18

Since the release of SmartFoxServer 2.18 we have introduced a way to override the default implementations for the Room Persistence API so that they can be customized to your needs.

Prior to this release we provided a file-based and a relational database-based storage mechanisms that could be used in conjunction with the API to save the state of multiple active Rooms.

With the new release you can now create your own storage implementations and plug them into the Persistence API. In this short article we’ll walk you through what has changed and how you can create a custom storage class.

» The basics

If you are not familiar with the Room Persistence API we highly recommend to start with the fundamentals on our docs website.

In our quick-start example from the docs we show how to initialize the API in your Extension’s init() method:

public void init()
{
    //Initialize Persistence API
    getParentZone().initRoomPersistence(RoomStorageMode.FILE_STORAGE, new FileRoomStorageConfig());
 
    //...
}

It’s a simple one-line call to the Zone’s initRoomPersistence() method, where we provide the RoomStorageMode and the relative configuration object.

In SmartFoxServer 2X 2.18 we have added a new mode called CUSTOM which, unsurprisingly, allows us to specify a custom implementation of the IRoomStorage interface.

» Three easy steps

To get started with the development of a custom storage class we need three ingredients:

  • an implementation of the IRoomStorage interface
  • a configuration object extending BaseStorageConfig
  • one line in the Extension’s main init() method to set it all up

Implementing IRoomStorage

The interface is relatively simple in its structure, even if it exposes a number of different methods:

void init(Zone zone, BaseStorageConfig cfg);
void destroy();	

void saveAllRooms() throws SFSStorageException;
void saveRoom(Room theRoom) throws SFSStorageException;
void saveAllRooms(String groupId) throws SFSStorageException;

CreateRoomSettings loadRoom(String name) throws SFSStorageException;
List<CreateRoomSettings> loadAllRooms() throws SFSStorageException;
List<CreateRoomSettings> loadAllRooms(String groupId) throws SFSStorageException;

void removeRoom(String name) throws SFSStorageException;
void removeAllRooms(String groupId) throws SFSStorageException;
void removeAllRooms() throws SFSStorageException;

(You can read more details in the server side javadoc)

Essentially there are an init() and destroy() method that manage the life cycle of the object and allow to create and dispose useful resources (e.g. a database driver, a connection pool etc.)

Then we have the load, save and remove methods each coming in sets of three, depending if we’re dealing with a single Room, a selection of Rooms or all the Rooms.

Create a configuration object

Next we need a configuration object that can be populated with settings for our Storage logic. For instance if we were to read and write from a database we’d need a connection string to reach the DB server and probably a database name and table name.

The base class for our configuration object is called BaseStorageConfig and comes pre-populated with a few global settings:

public class BaseStorageConfig
{
	public boolean storeInactiveRooms = false;
	
	public boolean storeRoomVariables = true;
	
	public boolean skipStaticRooms = true;
	
	public String customStorageClassName;
}

Continuing with the example of a DB-based storage here’s how one could extend the class:

public class MyDBStorageConfig extends BaseStorageConfig
{
	public String connectionString;

	public String driverName;
	
	public String databaseName;
	
	public String tableName;
}

PLEASE NOTE: keep in mind that your custom Storage logic should honor the settings contained in the base class. In other words it should check the values of the base class’ flags and filter out the relative data accordingly.

Putting it all together

When it’s time to deploy the storage classes we can include them in our Extension jar file. Next we can initialize the Room Persistence API as follows:

public class CustomRoomStorageExtension extends SFSExtension
{
	@Override
	public void init()
	{
		MyDBStorageConfig config = new MyDBStorageConfig();
		config.param1 = ...
		config.paramX = ...
		config.customStorageClassName = "my.sfs2x.game.MyRoomStorage";
		
		getParentZone().initRoomPersistence(RoomStorageMode.CUSTOM, config);
	}
}

Notice the customStorageClassName property: it must provide the fully qualified name of our IRoomStorage implementation. This will instantiate the storage class and allow us to invoke the Room Persistence API as needed.

» A complete example

To help you build a custom Room Storage class we have included the source code for our file-based Room Storage implementation so you can look at a simple practical example. Hopefully this will clarify some of the more abstract concepts we have outlined here.

If you have any doubts or questions on this subject feel free to get in touch with us through our support forums and let us know.