Firebase from Scratch, pt IV: Games, Services and Tournaments

February 29th, 2012 by larsan

In a series of posts we’ll do “Firebase From Scratch”, an introduction to Firebase and its concepts and ideas. Hopefully, reading this series will give you a firm grasp of what Firebase is and what it can do.

When it comes to the server code in Firebase, we divide it into three different things, three different artifacts which all have different responsibilities. In the last episode (see “A Maven Interlude“) we kind of skipped past them, but let’s take a closer look shall we?

Game
This is the heart of the game server side. It is what receives actions from players and decides what is going to happen next. The game is packaged and deployed as a GAR archive; it is easy to remember as Game Archive. When you start out in Firebase land, this is the first kind of server code you’ll write, and for simple games, it might be all you need.

Service
But if you write several games and want to re-use components between them or if you want to “extend” Firebase? This is where a service comes in: A service is a piece of Java code which is shared across an entire Firebase server. It is packaged and deployed in SAR archives – that is: Service Archives. Here’s some examples of what services are really good for:

  • A random number generator that can be certified and reused
  • User management. In fact: in order to customize the Firebase login procedure you must write a service.
  • Any kind of access to a 3rd party system, such as payment gateways and back offices
  • Statistics collectors that can be re-used by multiple games
  • Etc…

Tournament
Firebase has support for tournament: where many table or game areas compete against each other. The tournament code in Firebase is special: it does not depend on any particular game. So in theory you can write, say 3 different card games, but only one tournament which would handle all 3 games. In order to achieve this the tournament is packaged and deployed separately from the game, in a TAR, a Tournament Archive (and yes, it is unfortunate that “tar” is usually something completely different…)

So to wrap it up:

  • Game: This is where you execute game logic when clients send action to the server
  • Service: A modular and re-usable piece of code that can be shared between games and tournaments
  • Tournament: A tournament controller which manages… er… tournaments

We’re still fairly theoretical, but hang tough: soon there will be code!

Firebase from Scratch, pt III: A Maven Interlude

February 23rd, 2012 by larsan

In a series of posts we’ll do “Firebase From Scratch”, an introduction to Firebase and its concepts and ideas. Hopefully, reading this series will give you a firm grasp of what Firebase is and what it can do.

Actually, I lied in the last section: We won’t talk about the server game implementation here. Instead we’ll take a quick peak at Maven and how Firebase uses it. If you plan to roll your own using Ant or other tools, this is probably good for you to know anyway.

Maven? What Maven?
Really, if you’re developing in Java you already know this stuff. But if you’re new to the language, this is something you need to read up on, especially as a large part of the Java ecosystem is build with Maven. So if you need it, start here: What is Maven?

Here we will focus on only three of Maven’s aspects, as they are used in Firebase development.

  • Packaging: There’s Firebase specific types for each build, which will make sure you get artifacts out from each build that can be deployed right into a Firebase installation.
  • Developing: You can actually run Firebase right from the command line. This makes it extremely fast to test your games.
  • Quick setup: Firebase comes with so-called Maven archetypes, making setting up new projects a breeze.

So, we’ll ignore dependency management for now, although we will get back to it later in the series when we get down to class loading and best practises.

Archetypes: The Quick Start
In Maven speak, an “archetype” is a skeleton project and a way to quickly create a new project. A template if you will. So, you can let Maven itself create a new project, complete with POM file, folder structure and even example code. All the major Firebase artifacts – games, services and tournaments, have Maven archetypes already, and here’s an example:

mvn archetype:generate
      -DarchetypeGroupId=com.cubeia.tools
      -DarchetypeArtifactId=firebase-game-archetype
      -DarchetypeVersion=1.8.0
      -DarchetypeRepository=http://m2.cubeia.com/nexus/content/groups/public

As you probably understand, the above should be on one line, so remove all line breaks before you try it.

Have a good look, in the middle you’ll find that “archetypeArtifactId” is set to “firebase-game-archetype”. Now what do you think would happen if you replaced “game” with “service”, or “tournament” on that line? That’s correct, you’d create a service or tournament project instead. Neat huh?

Configuring a POM file
But if you already have an existing project, with an existing POM file there’s some basic information you need to add in order to use Firebase specific features. All this information is added automatically if you use the archetypes above, and you can skip this section. But if you want to understand, or roll your own, here’s what you need in your POM file:

<build>
 <plugins>
   <plugin>
     <groupId>com.cubeia.tools</groupId>
     <artifactId>archive-plugin</artifactId>
     <version>1.8.0</version>
     <extensions>true</extensions>
   </plugin>
 </plugins>
</build>

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

<pluginRepositories>
 <pluginRepository>
   <releases>
     <enabled>true</enabled>
   </releases>
   <snapshots>
     <enabled>true</enabled>
   </snapshots>
   <id>cubeia-nexus</id>
   <name>Cubeia Repo</name>
   <url>http://m2.cubeia.com/nexus/content/groups/public</url>
 </pluginRepository>
</pluginRepositories>

That was an awful amount of XML wasn’t it?  But it is really simple: first it tells Maven that there’s a plugin involved in the build process and specifies what it is called and what version to use. Then it sets up two repositories where Maven can go when it wants to find dependencies, such as the build plugin you just specified.

Is that all? Well, in reality you will almost always depend on the Firebase API as well, so you will want this:

<dependencies>
 <dependency>
   <groupId>com.cubeia.firebase</groupId>
   <artifactId>firebase-api</artifactId>
   <version>1.7.4-CE</version>
   <scope>provided</scope>
 </dependency>
</dependencies>

Here’s a small thing to note: We’ve set the “scope” of this dependency to “provided”. This is because when you actually run your game (or service or tournament) it will be within Firebase, and the API JAR will already be present on the class path. So you don’t need it packaged and included along together with your artifact, Firebase will “provide” it when it is time to execute.

Packaging
Each Maven project ends up creating artifacts. The most common of which is an ordinary Java JAR file. However, when deploying a game, service or tournament into Firebase you need special packaging. But this is trivial using Maven: If you’ve configured your POM file as described above, all you need to do is to set the “packaging” element to one of the following:

  • “firebase-gar” – For games…
  • “firebase-sar” – For services…
  • “firebase-tar” – For tournaments…

As Maven doesn’t normally know about these packaging types it will look to it’s build plugins, and the Firebase “archive-plugin” you’ve configured will kick in and package the project for you.

So for example, a POM for a game archive might start like so:

<project>
  <modelVersion>4.0.0</modelVersion>
  <groupId>test</groupId>
  <artifactId>game-test</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>firebase-gar</packaging>
  <name>my little test game</name>

  [...]

But hang on! What does this “packaging” thing actually do? Simple: It will use Maven to compile your code, using all the knowledge about the project found in the POM file. It will then package the resulting JAR into a Firebase artifact together with all relevant dependencies, in other words all dependencies not in scope “provided” or “test”. So now when you do…

mvn package

… you will get a Firebase artifact, ready to be dropped into a server!

Running Firebase
But wouldn’t it be cool if you could not only package your code, but actually run it immediately? Why, that’d be cool, and it is also entirely possible! When we’re done here you’ll be able to do this…

mvn package firebase:run

… and not only will you get your code packaged up, Maven will download and start a Firebase installation with your code already deployed, ready to be tested. This will save you from copying artifacts across and restarting Firebase just because you want to test something you just wrote.

In order for this to work, all you need to do is to tell Maven that there’s another plugin you want to use in the build. In the build plugin section of your POM, add:

<plugin>
  <groupId>com.cubeia.tools</groupId>
  <artifactId>firebase-maven-plugin</artifactId>
  <version>1.7.4-CE</version>
</plugin>

That’s all! Now when maven encounters your “firebase:run” above, it will search it’s plugin and delegate command. Firebase will be downloaded, configured and started for you! The first time this happens it will take a little longer as Firebase needs to be downloaded, but after this your game should be started in a matter of seconds.

On our Wiki you’ll find all the above information, just slightly compressed: Firebase and Maven

How-To Use Cubeia Firebase RNG Service

February 23rd, 2012 by larsan

So, the other day we released an RNG service to the wild. It is a Marsenne Twister implementation with background cycling and discarded draws. It’s fast, secure and possible to drop right into you existing Firebase projects. Here’s how:

First, you need to add the service JAR into your projects dependencies in order to use it. Here’s how it looks in Maven:

<dependency>
  <groupId>com.cubeia.firebase.service</groupId>
  <artifactId>mt-random</artifactId>
  <version>1.0</version>
  <type>jar</type>
  <scope>provided</scope>
</dependency>

Note that we add it as “provided” as it will be included in the service when we’re deployed, so we don’t need to include it into our other dependencies. Generally it’s a good pattern to try not to duplicate classes that are included in services as you open up a can of class loading problems if you do.

Having done this, what you need in order to get hold of an actual Random object to use, is the Firebase service registry. This is available in, for example, the Game context which you get on the “init” method. If we have the game context we can do a method like this:

private Random getRandom() {
  Class<RandomService> key = RandomService.class;
  ServiceRegistry registry = gameContext.getServices(); // needs context
  RandomService randomService = registry.getServiceInstance(key); // get service
  return randomService.getSystemDefaultRandom(); // get random
}

Now you’re ready to roll! You could assign the random to an instance field, but make sure you don’t do it in the game state as the Random is not serialize at the moment, and it will result in an ugly exception if you try it.

Here’s one more trick for you: if you want to use “mvn firebase:run” in you project (have a look here for more details on that), you need to add another dependency. The Firebase Maven plugin needs to know about the actual service archive in order to get your dependencies right, so also add the following to your dependencies:

<dependency>
  <groupId>com.cubeia.firebase.service</groupId>
  <artifactId>mt-random</artifactId>
  <version>1.0</version>
  <type>firebase-sar</type>
  <scope>provided</scope>
</dependency>

By default, all Firebase artifact such as the one above, which are in the scope “provided” will be included in the deploy folder when you run Firebase via Maven. If on the other hand, you’re running Firebase from a standard installation, just copy the “mt-random.sar” archive into “game/deploy” and you’re done!

WebSocket Performance

February 7th, 2012 by larsan

We’re closing in on Firebase 1.8 and the question everyone want to know the answer to: is it smoking? is it hot? And now we have an answer, read on for you performance test fix: Firebase 1.8 Web Socket Performance.

Cubeia Poker Network Demo

January 31st, 2012 by fredrik

We are quickly moving forward with our HTML5 support and are now proud to make our complete poker network demo with an HTML5 prototype client publically available!

You can grab the demo here: http://www.cubeia.org/index.php/labs

Download, unzip and run startup.bat (the demo only runs on Windows).

NOTE: There is a problem with some of the USB demos we handed out at ICE where some files were marked as read-only. If you have a USB demo and it is not starting up correctly you can follow the steps below to fix it (or download the zip above):

  1. Mark all files and folders in the root of the USB stick
  2. Right click and select ‘Properties’
  3. Uncheck ‘read-only’, click OK
  4. Choose ‘Apply changes to the selected items, subfolders and files’, click OK

Thats it! Now it should start as intended. If you want to speed up the startup process you can copy the content from the USB stick to a local hard drive.

Feedback is, as always, most welcome! :)

Getting Warmer!

January 18th, 2012 by larsan

You want to write HTML5 games? And support Flash clients? And desktop clients? Well, Firebase can now do it all for you: We’ve released an RC on Firebase 1.8-CE which adds WebSocket and HTTP/Comet support. Hit the forum for more information.

Mobile devices on the rise!

December 1st, 2011 by fredrik

While doing some research for an article today I stumbled upon a study made by KPCB regarding Internet trends for 2011. Below is a graph from the study depicting the percentage of traffic generated from mobile devices for some of the leading service providers Facebook, Twitter and Pandora respectively.

Mobile device traffic

These numbers are actually staggering. In only 3 years one third of the traffic to Facebook have shifted from computers to mobile devices. Mobile search has grown four times in past years. The estimate is that 152 million Android mobiles have been shipped in the second quarter of 2010.

There is no doubt that this will completely change the way we look at online services and how we use them in the near future.

Of course, as a platform developer we ask ourselves how can a game developer most efficiently provide content on such a fragmented market? Choosing the right client technology has never seemed more important than now.

Playing with HTML5 and WebSockets

October 20th, 2011 by fredrik

We have been looking at implementing support for HTTP and HTML5 WebSockets in Firebase in the next version to better support Javascript and the emerging HTML5 standards. Read more to see a short update on the status as well as an example of a use case against the latest version.

HTML5

Read the rest of this entry »

How to Handle Client Reconnects

September 23rd, 2011 by larsan

Cubeia Firebase comes with a very good High Availability support right out from the box: a Firebase cluster aren’t supposed to drop any events at all within reasonable, pragmatic, boundaries. For reference, our release testing is loading a cluster with 1000 events per second when testing fail-over. This corresponds to at least 20 000 poker players (depending on player speed), so it should be pretty safe even for you.

The Problem
Internally Firebase replicates events and state to minimize the risk of data loss, however, there is one instance where this is particular hard, and that is between the clients and the server. And here’s why:

Because Firebase is not one-to-one when mapping incoming events to players, but rather one-to-many we have chosen to not extend the transaction boundaries to the clients themselves as this would be extremely costly.

This means that if a client looses its TCP connection unexpectedly, there may be messages lost. This might come about from several scenarios, for example:

  • A client role node in the Firebase cluster crashes. This will normally disconnect all players from the node, and upon reconnection they will be load balanced to another server.
  • The client application crashes. When opened again, the client will reconnect to the Firebase cluster.
  • A glitch in the routing between the client and the server disconnects the client.

In any of the cases we’ll look at today, the client will be able to realize it has lost the connection and reconnect.

Preconditions
The only thing that is really necessary to start handling reconnects gracefully is for the client to recognise it is reconnecting. If it is handled in-process this should be trivial, and when a client starts it may look to a cookie or a saved state to see if it was closed correctly, ie. a “dirty state” flag.

Also, you need to mark crucial events with ID:s and optionally a flag which can tell you if an event is “resent” (more on this below), and also make sure such events have corresponding answers from the server. Remember that Firebase is an asynchronous system, so you’ll send a critical event, then some time later, you will get an answer, hence the importance of an event ID.

And what events are “critical”? It’s up to you really, but probably those that can significantly alter the outcome of the game. The events that you really don’t want to get lost. But the key word is “significantly”, you probably don’t want to enforce a call/response-pattern on all events in all games. In gambling most events such as bet, call, fold etc are significant, whereas in a social shooter perhaps very few are.

Idempotency to the Rescue
In event processing idempotency is usually meant as the ability to resend events without changing the initial outcome more than once. In an idempotent system, if event X is sent ten times, only the first received will be executed upon, the rest will be ignored. For Firebase this means that the client should be able to send a critical event several times and the server will simply respond as if the event is executed if it is already acted upon.

Let’s break it down:

  • The client must keep a back log of sent “critical” events which it has yet to receive answers to. So for each critical event it will save an ID in a map together with the entire event, and for each response to a critical event the ID will be removed from the map. If the client is not awaiting any response the map will be empty.
  • When a reconnection occur, the client should check if the above map is empty, if not any event therein may theoretically have been dropped. Each event in the map should be resent, optionally with a flag detailing that this is indeed a resent event.
  • The server should keep a map of ID to response objects for a reasonable amount of time, or be able to calculate a response without changing the internal state. So if it receives an event which it has already executed upon, it should recalculate the response, or fetch the response from a map.

Example: Load Test
The load test we’re using internally is very simple: Each client sends a sequence of integers and the server simply echoes the integers right back. So the client may send “5″ and will wait for the server to send “5″ back. It then waits for X milliseconds before increasing the sequence to “6″ and repeat. This simple game allows us not only to determine the exact load at any given time (ie. events per second) but also verify that Firebase honours its FIFO behaviour.

So the client will keep a queue of integers it expects the server to respond to, and it also has an integer sequence to create new events from. The queue of integers acts as the client side map: if it is empty there’s no response outstanding. On reconnect the client checks the queue and resends any integers found in it. The server simply echoes the integers back to the client, but also checks that the sequence is intact (again checking FIFO ordering) except for the case of reconnects when the sequence is allowed to jump back a few steps.

Finally
Hopefully this should have straightened out a few questions. Keeping strict idempotency in any system is tricky, but it will give you a very robust platform, and paired off with Firebase will be damn near bullet-proof!

Firbease Guice Support Patched

September 14th, 2011 by larsan

We’ve just patched the Firebase Guice Support to 1.1.1. This patch contains a single bug fix: If you configure your game to use a table listener, this listener needed also to be a tournament table listener previously. But no more!

The new version is available on the Firebase download page.