Maintaining game state across multiple reloads

Continuing from a previous post about Singletons  we are going to discuss a simple strategy to maintain application state across multiple Extension reloads. Before delving into the details, let’s first analyze the reasons why this may help.

The ability to update an Extension at runtime comes at the cost of destroying all of the data managed by the Extension itself, which in some cases can be a pain. Whether the Zone Extension is handling the global game state or multiple Room game states, it will loose all of the runtime data, which makes re-deployments a critical activity, requiring careful scheduling to avoid too much downtime for players.

Using a Singleton class as described in the previous article we can store all of the necessary game state in a safe memory space, that won’t be affected by a redeployment of our code.

» How does this work?

In our documentation we have a section dedicated to how class loading works in the JVM. The image below outlines the class loader hierarchy in SFS2X.

class-loadersWhat is important in this simple diagram is the Extension Global ClassLoader, which sits on top of all deployed Extensions and whose life cycle is independent from its children. We will therefore exploit this top class loader to maintain state across multiple re-deployments.

As mentioned in the previous article this top class loader manages all jar files under the extensions/__lib__/ folder, so we’ll deploy our singleton class and its dependencies in a separate jar file to this folder.

» An example

Here is a simple pseudo-code of a singleton game model:

public class GameSingleton
{
	private static final GameSingleton INSTANCE = new GameSingleton();

	// Here we keep the state for each game in the Zone
	private Map<String, GameState> gamesTable = new ConcurrentHashMap<>();

	private GameSingleton() {}

	public static GameSingleton getInstance()
	{
		return INSTANCE;
	}
}

public class GameState
{
	private HighScoreTable hsTable;
	private List<Player> players;

	// ... more game data ...
}

public class HighScoreTable
{
	...
}

public class Player
{
	...
}

The main singleton class keeps a map of GameState objects, one for each game running in the Zone. Each instance will in turn describe all of the runtime data for the game, such as high scores, the players properties and whatever other information is needed.

NOTE: When deploying the code we will make sure that the main singleton object and all the related game state classes are packed in the same jar file and exported to the extensions/__lib__/ folder.

 

In our main Extension init() method we will just need to access the Singleton class, which in turn will either get initialized, if it’s the very first time this class is loaded, or we’ll get a reference to object already in memory.

public class MyGameExtension extends SFSExtension
{
	private GameSingleton gameSingleton;

	@Override
	public void init()
	{
		gameSingleton = GameSingleton.getInstance();

		// etc...
	}
}

As a final remark, keep in mind that this approach will work fine as long as you don’t need to re-deploy changes to the singleton or related model classes. In that particular case a server restart will be required.

NOTE: If during the implementation of this solution you’re getting a ClassCastException when accessing the global game data, chances are you haven’t deployed your model classes correctly. In particular the class that has raised the Exception is likely to have been exported in the wrong jar, i.e. in the Extension jar vs the Singleton jar.