Monthly Archives: March 2010

Asynchronous Games in Firebase; pt II

Last post I looked at the motivation for writing asynchronous multiplayer games on top of Firebase.  This post I’ll sketch an outline on how to actually do it.

The first thing to consider is that we now have two notions: The Firebase concept of area (called “table” for legacy reasons) and the overall concept of a “game”. Firebase tables are associated with games, but whereas in a synchronous game the table probably would be the game such that if the table is closed, the game is over, in asynchronous games the table may come and go, but the game itself would survive.

Oh by the way, I’ll use Java in this post, but remember you can write it in script languages Ruby, Python and Groovy as well. 🙂

Let’s step it through:

  1. The game is created. This is probably done on a website somewhere and does not involve Firebase at all.
  2. Client connects. When game client is opened (someone wants to make a move), the client connects to Firebase and does the following:
    1. Search the lobby for any table with the correct “gameId” set in the attributes.
    2. If a table is found, attempt a “join” command.
    3. If a table is not found, or the join fails, send a table creation request and make sure to include the “gameId”.
  3. Activator creates table. When a client cannot find a table for the game, it send a table creation request, the activator then reads the game and its state from database, and creates a new table.
  4. Game play. The player makes its moves and actions normally via Firebase. The game in Firebase either saves the state on each action, or delegates to the time when the table is being closed (see below).
  5. Table closes. When the activator finds  table which has not been accessed for some time. If needed it should also save the game state at this point (see above).

I’ll focus on points no. 3, 4 and 5 above for the rest of this post. And I’ll use code examples from the Kalaha game I’m currently involved in writing.

Activator / Table creation
The game activator in Firebase is the components that know how to create and destroy tables in the system. We’ll follow best practises (but we’ll skip the “init” state for now) as it helps us save the state to database.

The activator should first make sure to implement RequestAwareActivator to make sure it gets the requests:

public class ActivatorImpl implements GameActivator,
   RequestAwareActivator {

[...]

When a client wants a table to join for a specific game, it’ll send a table creation request, and the activator should read the game state from the database and create a new table. Somewhat compressed, it may look like this:

@Override
public RequestCreationParticipant getParticipantForRequest(
        int pid, int seats, Attribute[] atts)
    throws CreationRequestDeniedException {

    // find the game id in the parameters
    int gameId = getKalahaGameId(atts);
    if(gameId == -1) {
        // you may want to handle this as a special form of "new game"
    } else {
        log.debug("Ressurecting game " + gameId + " for player id " + pid);
        // read the game from the database
        Game game = gameManager.getGame(gameId);
        if(game == null) {
            // code 1 for "no such game"
            throw new CreationRequestDeniedException(1);
        }
	return new Participant(game);
    }
}

The Participant is an inner class for handling the request, like so:

private static class Participant implements RequestCreationParticipant {

    private final Game game;

    public Participant(Game game) {
        this.game = game;
    }

    @Override
    public void tableCreated(Table table, LobbyTableAttributeAccessor atts) {
        table.getGameState().setState(new net.kalaha.game.action.State(game.getState()));
        atts.setStringAttribute(TABLE_STATE_ATTRIBUTE, "OPEN");
	atts.setIntAttribute("gameId", game.getId());
    }

    @Override
    public LobbyPath getLobbyPathForTable(Table table) {
        return new LobbyPath(table.getMetaData().getGameId(), "", table.getId());
    }

    [...]
}

As you can see above the creation participant sets the Game object on the table when it is created. It also sets a lobby attribute with the game ID which is important for the client to find the table. The lobby path above is kept simple for this example and the TABLE_STATE_ATTRIBUTE is a constant you can define yourself.

Now we need to close the table when it isn’t used. This is somewhat outside the scope of this post, but I’ll post some pseudo code here to demonstrate table destruction:

public void checkTables() {
    TableFactory fact = context.getTableFactory();
    for (LobbyTable table : fact.listTables()) {
        int tableId = table.getTableId();
        long lastModified = getLastModifiedFromAttributes(table);
        int seated = getSeatedFromAttributes(table);
        if(seated == 0 && isOld(lastModified)) {
            checkClose(tableId, table);
        }
    }
}

The above should be called regularly from a scheduled task. The “get from attributes” method are trivial, for example:

private long getLastModifiedFromAttributes(LobbyTable table) {
    Map map = table.getAttributes();
    AttributeValue a = map.get(DefaultTableAttributes._LAST_MODIFIED);
    return a.getDateValue().getTime();
}

The attributes “last modified” and “seated” are standard attributes and always available. The “table state” attribute is not and you’d have to set and get it yourself. In “check close” we’ll check the table state, destroy it if it is closed and if not, send an action to the table in order to clsoe it:

private void checkClose(int tableId, LobbyTable table) {
    TableFactory fact = context.getTableFactory();
    String state = getTableStateFromAttributes(table);
    if(state.equals("CLOSED")) {
        // the table is closed, so destroy
        fact.destroyTable(tableId, true);
    } else {
        sendCloseActionToTable(tableId);
    }
}

And finally, the method to send a “close youself” action to the table would look something like this:

private void sendCloseActionToTable(int tableId) {
    ActivatorRouter router = context.getActivatorRouter();
    CloseTableAction action = // create your action here
    byte[] actionBytes = // convert action to bytes
    GameDataAction wrap = new GameDataAction(-1, tableId);
    wrap.setData(ByteBuffer.wrap(actionBytes));
    router.dispatchToGame(tableId, wrap);
}

Which should be more or less self-explainable. The action is of course whatever type of object and encoding you use in your game, it could be standard Java objects and Serialization for example.

Table Play / Closing
The table should work as usual, the only thing we’ll add is to save the game state on the “close table command”. We need to translate the action byte data to an object, then differ between internal actions and client actions and process. Something like this perhaps (again from my Kalaha game):

public void handle(GameDataAction action, Table table) {
    Object act = // translate to action object
    log.debug("Got action: " + act);
    if(act instanceof KalahaAction) {
        // here's where you'll handle the actual game state
    } if(act instanceof CloseTableAction) {
        setTableClosedAttribute(table);
        saveTableStateToDb(table);
    } else {
        log.warn("Unknown action: " + act);
    }
}

In the above all kalaha actions are treated separately as client actions and the “close table” action simple sets the table state attribute to “CLOSED” to mark for the activator that the table is safe to remove, and then saves the game state to database.

Conclusion
As you can see, the actual code to manage asynchronous games in Firebase is minimal, you’re going to spend infinitely more time on game logic than state handling. All the code I’ve omitted is trivial. In fact, writing this article took me longer than implementing the feature in my game!

Which ends our discussion about asynchronous games in Firebase. Last post we looked at motivation and background, and in this post we’ve seen how to actually program it in Firebase. Now go and try it yourself!

By |Friday, March 12, 2010|firebase|1 Comment

Asynchronous Games in Firebase; pt I

Since the social web started to expand, asynchronous multiplayer games seems to really have taken off. So my immediate question is obviously, can I do that on Firebase? And the short answer is: of course. For the long answer, please read on.

Let’s recap first. In a traditional synchronous game you play against other people in real-time, everyone you play against will have to be online at the same time. But given the nature of our everyday Internet use, a different pattern has emerged: in asynchronous games not all players have to be online at the same time. For example, turn-based games can easily be made asynchronous, you play your turn and then sometime in the future you opponents will have been online and performed their moves. As such, a classic game such as chess in play-be-email mode is a prime example of an asynchronous game. But you’re not limited to turn-based games, you can define the order to act on time or any metric you’d like, the only mandatory feature is that all players do not have to be online at the same time.

Firebase is fundamentally a synchronous multiplayer server. The technical difficulties Firebase set out to solve are all issues arising from the kind of distributed computing you get when a couple of thousand players have to interact in real-time. So normally you’d build an asynchronous game on a traditional web platform, as the demand on timely updates just got a lot less urgent standard web techniques can be easily applied. But having said that, is there anything you’d gain by using Firebase?

I believe there is: A synchronous option. Easy to overlook, this is actually a big one. If you build your asynchronous game on Firebase from the start, you have an immediate option of including synchronous play. Or better yet, the difference between synchronous and asynchronous could be a simple configuration issue. And by the way, who says it’s either or? Why not both?

Let me explain the above in an example: At the moment I’m hacking on a Kalaha game for Facebook on my past-time. And obviously it’ll be asynchronous, players will take their turn while logged in, and the game mechanics will inform you of your move via the Facebook streams. But if two players are online at the same time and want to play against each other, why shouldn’t they? And would quick matches be fun, say max 5 seconds per move? And how about tournaments?

Here’s some other, perhaps minor, points to consider:

  • Duplex communication: implicit in the entire discussion is that Firebase can push events both ways from and to clients and server. In HTTP you’re forced to use Comet patterns, whereas Firebase uses a persistent connection and any actions are delivered to the clients immediately.
  • Latency: Just because you’re building an asynchronous game doesn’t automatically mean latency is not important. If your game is based on actions against a common notion of time, you might be interested in latency anyway. Firebase has an very low latency compared to most application/web servers.
  • Bandwidth: If it turns out you have a hugely successful game, and a large portion of the traffic is made up of game data (as opposed to actual web pages or other contextual data) you’ll be happy just to avoid the HTTP headers and the overhead they automatically bring to the table. Firebase uses TCP only at the moment, thus dramatically reducing the bandwidth requirements.

There are other less apparent options as well, but lets be honest, anything but a huge advantage would probably be negated by the additional platform with the integration and administration it’d mean. That is to say, if you can built it using standard web tools only, why add another platform with which to communicate, integrate and administrate?

So that’s my declaration: Using Firebase gives you the entire range from highly synchronous to entirely asynchronous on one platform! Next post I’ll sketch a proposal on how to actually do it as well. Stay tuned!

By |Thursday, March 11, 2010|firebase|1 Comment

Script Support in Firebase

Now we have released a candidate for script support in Firebase! This is something we’re very excited about as it means no more Java (unless you want to of course, old hands like me aren’t likely to change in a hurry).

This is a first release so there’s no support for tournaments or services yet. But is not far off.

We’re using Java’s built in scripting support under the hood. It turned out to be not to trivial, but not very hard either. The interesting issues are likely to arrive when we start optimizing and bug hunting. And speaking of optimizing, I ran a few bots, say 50, against a very small script (basically the equivalent of a hello world) and on avarage the bots returned on 10 ms. That’s 10 ms for network latency, Firebase internals, and script evaluation for each event. Pretty damn good! Next step there will be to start optimizing depending on the script implementation, cashing compiled scripts, mutli-threading etc.

One major up-shot of writing on a script language and re-evaluating the script for each event is the velocity: you don’t have to restart Firebase when you change code, the script is re-evaluated automatically. The round-trip time is cut dramatically!

And… You want to see code? Here’ you are, this is the server part of the Hello World tutorial, written in…

JavaScript:

function handleDataAction(action, table) {
    _log.debug('Entering handleDataAction');
    var data = _support.getActionDataAsUTF8(action);
    var playerId = action.getPlayerId();
    var outAction = _support.newGameDataAction(playerId, table);
    _support.setActionDataAsUTF8(outAction, data);
    table.getNotifier().notifyAllPlayers(outAction);
    _log.debug('Exiting handleDataAction');
}

Ruby…

def handleDataAction(action, table)
    $_log.debug("Entering handleDataAction")
    data = $_support.getActionDataAsUTF8(action)
    playerId = action.getPlayerId()
    outAction = $_support.newGameDataAction(playerId, table)
    $_support.setActionDataAsUTF8(outAction, data)
    table.getNotifier().notifyAllPlayers(outAction)
    $_log.debug('Exiting handleDataAction')
end

Python…

def handleDataAction(action, table):
    _log.debug("Entering handleDataAction")
    data = _support.getActionDataAsUTF8(action)
    playerId = action.getPlayerId()
    outAction = _support.newGameDataAction(playerId, table)
    _support.setActionDataAsUTF8(outAction, data)
    table.getNotifier().notifyAllPlayers(outAction)
    _log.debug('Exiting handleDataAction')

Groovy…

def handleDataAction(action, table) {
    _log.debug('Entering handleDataAction')
    data = _support.getActionDataAsUTF8(action)
    playerId = action.getPlayerId()
    outAction = _support.newGameDataAction(playerId, table)
    _support.setActionDataAsUTF8(outAction, data)
    table.getNotifier().notifyAllPlayers(outAction)
    _log.debug('Exiting handleDataAction')
}

Cool, eh?

You’ll notice some strange objects above. We bound some helper objects in the evaluation context, “_log” a Firebase Log4j logger, “_support” a tool for string to byte conversion etc, and some other helpful stuff.

The JavaScript Hello World can be found here.And tentative documentation here. Have fun!

By |Wednesday, March 10, 2010|firebase|2 Comments

Guice Support in Firebase

I’ve always wanted to add dependency injection support to Firebase, and today we released a candidate for Guice! And if you ask me, it’s very cool indeed.

The documentation is a bit sparse at the moment, but can be found on our wiki. The rest of the post I’ll just show how a small fictional game would look using Guice.

To start with, the Guice support comes in a set of abstract base classes, one for each Firebase artefact. And to use those you’d have to add a dependency to you Maven build (I’ll assume Maven here, you can of course use whatever you’d like):

<dependency>
  <groupId>com.cubeia.firebase</groupId>
  <artifactId>guice-support</artifactId>
  <version>1.0-RC.1</version>
</dependency>

And if you haven’t already got it, you’d need our repository as well:

<repository>
  <id>cubeia-nexus</id>
  <url>http://m2.cubeia.com/nexus/content/groups/public/</url>
  <releases>
    <enabled>true</enabled>
  </releases>
  <snapshots>
    <enabled>true</enabled>
  </snapshots>
</repository>

Now your all set to go, just extend GuiceGame and return the class of you game processor within the configuration, like so:

public class MyGame extends GuiceGame {
    public Configuration getConfigurationHelp() {
        return new ConfigurationAdapter() {
            public Class getGameProcessorClass() {
                return MyProcessor.class;
            }
        };
    }
}

So what’s the magic then? It is this: The class MyProcessor will be instantiated by Guice and can therefore contain injections. And further, it will be done in a custom scope, per event, thus isolating instances nicely.

You can also add your own modules to the injection context, again by overriding a method in GuiceGame:

protected void preInjectorCreation(List list) {
    list.add(new MyGameModule());
}

Which means, you can inject not only stuff from the current table but also, your own classes. So if we continue:

public class MyProcessor implements MyProcessor {

    /*
     * This is probably configured in the "MyGameModule" configured
     * in the guice game extension.
     */
    @Inject
    private MyHandler handler;

    /*
     * This is a speciality, you can inject Firebase services
     * right into your classes.
     */
    @Service
    private ScriptSupport support;

    /*
     * And another shortcut, if you use Log4j, we have a
     * a helper annotation for you...
     */
    @Log4j
    private Logger log;

    public void handle(GameDataAction action, Table table) {
        // do something here eh?
    }

    [...]

}

That should give you the idea. You can inject Firebase services as well as a logger (and remember, if you don’t use Log4j, Guice support the Java utility logging package from scratch). There’s a couple of things not shown here, for example, you can inject table members directly into the classes and the state object, so you don’t have to pass those around.

Any catch? Well, when you create your own modules you’ll need to keep in mind that the processor will only work in a custom scope, called EventScope. So if you have something which needs to be bound not as a singleton or in the default scope, you’ll probably need to do something like this:

bind(MyHandler.class).to(MyHandlerImpl.class).in(EventScoped.class);

And that’s it! In a few days we’ll release our script support, which is as you might imagine built on top of the Guice support. And so far? I love it!

By |Thursday, March 4, 2010|firebase|1 Comment