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.
- Part 1: Introduction
- Part 2: Diving In
- Part 3: A Maven Interlude
- Part 4: Games, Services and Tournaments
- Part 5: What’s In a Server Game Anyway?
- Part 6: Activating Games
- Part 7: Actions On The Table
- Part 8: Services
And in this installment we’ll get to some actual code! Exciting! We’ll start off with looking quickly at the major building blocks that goes into a server side Game, and then we’ll dive into a traditional “Hello World”.
A note before we get started: You can write server side games not only in Java, but in Ruby, JavaScript and various other languages. But we’ll use Java here, mostly because it is what must people end up with. If you want examples in other languages, hit our forums and ask.
The Game Class
This is you hub and the first class you’ll implement. This class will be created once only, and for each event it will hand out processors to deal with the actual logic. So although the action takes place elsewhere the game class has a few important uses, mainly regarding common configuration and environment variables.
public class GameImpl implements Game { [...] }
Tables
So if a game doesn’t actually do anything, exactly where does the action take place? The answer is that every game is associated with a number Tables. Each table have a number of players and these players interact according to the game rules. If you think of a poker table you’ll immediately grasp where the term “table” comes from, but in reality your game is not limited to tables, so it might be better to think of it as an “area” or a “room”.
So players “sit”, “leave”, and “watch” tables, and all these operations are handled automatically by Firebase. In addition to this, the actual Table object used in the game also has a number of useful little gadgets you can use:
- Sets of players and watcher at the table
- A “game notifier” for sending events to the players at the table
- A scheduler for repeated or delayed actions
- A customizable game state (see below)
- Etc…
Game Processor
So there are tables, and players at tables, and now the players start actually doing things. The Game Processor class is where this action takes place, and the processor is accessed via the Game, for example:
@Override public GameProcessor getGameProcessor() { return new Processor(); }
For each event at a table, Firebase will ask the game for a processor. You might be tempted to create one processor and re-use it, as opposed to creating a new instance every time as we do above, but resist it: Firebase is single threaded in regards to tables, so it guarantees that there will be one and only one event at the time per table. This means that the above method may be, and indeed will be, called concurrently and if you re-use a processor you will have to deal with multi-threading yourself.
The processor have two methods for handling actions, namely game data actions and game object actions. The names are slightly evil as they don’t really describe what’s going on very well, but in reality it is simple:
- Game data actions are what is send to and from connected clients. The data in question is a simple byte array: Firebase does not suppose what kind of protocol you use, and as such the data is transported back and forward as bytes.
- Game object actions are either actions sent by services or other components within Firebase, or actions that have been scheduled for later execution. A scheduled action is, as opposed to a data action a POJO as it will never leave the cozy environment of the Firebase server.
Let’s do some pseudo-code:
public class Processor implements GameProcessor { @Override public void handle(GameDataAction action, Table table) { byte[] bytes = action.getData().array(); MyEvent event = translateBytesToEvent(bytes); MyEvent out = handleGameEvent(event); if(out != null) { GameDataAction tmp = translateEventToAction(out); GameNotifier notifier = table.getNotifier(); notifier.notifyAllPlayers(tmp); } } [...] }
The above is obviously just an example: On line one we get the bytes the client actually sent us. Then we translates the bytes into a POJO event object we can use internally. We handle the game event, which is where we check the game rules, and if the game rules gives anything back we create a game data action to send, get hold of the “notifier” which knows how to send the event to the players around the table, and then send it.
If this seemed kind of confusing, don’t worry, everything will be made clearer later.
Game State
To remember the state of the game between actions you can set a POJO on the actual Table:
MyGameState state = // this is an ordinary bean table.getGameState().setState(state);
This state is transactional, and in a Firebase cluster it is also replicated between members so even if there’s a failure on one node, game play will not be interrupted and the state will be intact.
In reality you will also want to write data to a database of some sort, but it is an important feature in Firebase that you don’t have to write all events to a database in order to have high availability, fail-over, scalability and all other buzz-words. You should only need to write really important events to a database, the rest should be kept in the game state.
Table Interceptor and Listener
You can also be notified or interact with players when the join or leave the table. This is done via two interfaces, “TableListener” and “TableInterceptor”. The listener get’s notified when players join, leave, watch etc. The interceptor has the ability to OK or deny individual join and leave requests. Both of them have a “provider” companion which you implement on your Game to tell Firebase that you want to listen, or intercept join and leaves.
Finally: Hello World!
Now let’s start coding, shall we? We’ll start simple with a timeless classic: when a player joins a table, we’ll send him a simple greeting. To get going, we’ll use Maven and we’ll setup the project by using an archetype for us (for more on the Maven archetype, have a look at our Wiki):
mvn archetype:generate -DarchetypeGroupId=com.cubeia.tools -DarchetypeArtifactId=firebase-game-archetype -DarchetypeVersion=1.7.0 -DarchetypeRepository=http://m2.cubeia.com/nexus/content/groups/public
The above command should be executed on a command line (and obviously without line breaks). It will give you a complete Firebase game project which you can open/import into your favorite Java IDE. Go in, try it!
Now that we have a project, and an IDE to work in, let’s write some code. First, we must listen for join events, so we’ll start off with implementing a table listener:
public class Listener implements TableListener { @Override public void playerJoined(Table table, GenericPlayer player) { int playerId = player.getPlayerId(); String msg = "Hello " + player.getName() + "!"; GameDataAction action = createAction(table.getId(), playerId, msg); GameNotifier notifier = table.getNotifier(); notifier.notifyPlayer(playerId, action); } private GameDataAction createAction(int tableId, int playerId, String msg) { GameDataAction action = new GameDataAction(playerId, tableId); ByteBuffer bytes = ByteBuffer.wrap(msg.getBytes()); action.setData(bytes); return action; } [...] }
This should be pretty self-explanatory: we create a message tailored for the player who joined, create a data action to send him, and send it. The devil’s in the “createAction” method, but importantly: this method is re-usable and you can, and should, put it in a utility class somewhere for later re-use.
Now, in order for Firebase to use the above listener we must let it access it, and this is done via a listener provider which will implement in our game:
public class GameImpl implements Game, TableListenerProvider { public void init(GameContext con) { } @Override public TableListener getTableListener(Table table) { return new Listener(); } @Override public GameProcessor getGameProcessor() { return new Processor(this); } public void destroy() { } }
Note that we’re letting the game implement “TableListenerProvider”: Firebase will look at the games signature and realize that we have a listener it should call for us. And… that’s it! Really, that’s it. We don’t have a client to test it with, yet, but you can now compile and package the server game and each time a player joins a table, he will get our greeting messages.
You want to try it out? Sure, by know you should be ready for our full Firebase Hello World tutorial, which includes a Flex client so you can actually test the code.
So…
- … wasn’t that an awful lot of code? As “hello world” goes, yes, but think of the heavy lifting Firebase do for you in the background: login, join table, message passing, multi-threading, fail over safety etc. Thing is, your actually very close to a real game if you’ve come this far.
- … can I stop a player from joining a table? Yes, just as the above game implements “TableListenerProvider” you can let it implement “TableInterceptorProvider” which will let you interact with join/leave requests. Go on, try it!
- … how about scheduling events, customizing login or even creating bloody tables?! Easy tiger, we’ll get there, just not in this installment…
Next time will take a look at a very shady Firebase component, the mysterious Game Activator. Stay tuned!