Realtime Database
How to implement a Guild Chat with Firebase Realtime Database
Benjamin Button Edition, Part 1 (or Part 3?)
At FUN-GI, we build games that define new genres and roll out features that ease our largely casual player base into more mid-core game experiences. In this three-part series, our team will walk through how we built and organized workflow for MMO (massively multiplayer online) guild chat in our top-rated iOS and Android home renovation and decoration game, House Flip. To aid in digestion, we’re telling a Firebase Realtime Database story in reverse chronology by starting off with our Google Cloud Platform backend integration first, then frontend hook-ups in Unity, and tying it all together with project and workflow management in Asana.
To fast forward some context, one of the recent additions to our game, House Flip, is a community feature which our players call Squads, but most MMO folks would call a guild. The game in its previous state played mostly as single-player, even though it had multiplayer competitive & leaderboard elements. With this guild feature we wanted to increase the social elements by allowing players to actually interact with one another and even participate in renovating a shared house in a team-based environment.
Server Structure — Firebase Nodes
As our main goal was to create a sense of community for players who join Squads, we set aside two-party chat, and instead focused on designing a system optimized for a Squad-wide chat. Firebase Realtime Database was a natural fit for a chat system. For instance, whenever a new Squad is created.
We would assign it a unique squad_id
and use it as a channel_id
as well:
Whenever we want to send a new message, we simply push a new entry at this path. Using the Firebase Node.js client, we would do so as follows
Since we do not need to give the user the option to edit past messages, on the client we would only need to listen for children added to this path. As new children are added in order, this means we can easily limit the number of messages we need to download and show to the user by adding the limitToLast
filter. Optionally, we can dynamically request more messages based on the user’s request.
You perhaps noticed that the data we’re storing for this message is pretty minimal. As you would expect, we also would want to have the squad member’s name and avatar displayed when showing their messages. This information can potentially be part of the message itself, while this would duplicate this information that would presumably also be stored somewhere else for the user in every single message. Depending on the typical usage envision for this feature, this might be a significant increase in the data being requested. De-normalized data can work well with the Firebase Realtime Database and can be an appropriate solution for certain applications, especially as it takes away the complexity at the point of querying: you would only need one query to get the data you want to display.
An alternative is to keep your data normalized. This will ensure the consistency of your data, but there are additional considerations for this approach. For example, let’s imagine we have our users info stored as follows:
Then when the client loads the data for a squad channel, we can query this user info for all channel members, cache that map locally and read from it when displaying messages by checking the sender data in this user’s map. Additionally, we can directly listen to changes in the avatar and name to reflect it immediately.
Handling Broad Cases and Security
Keep in mind that we’re using a list of Squad members as the pool of users that we query further info for to display on the client. If a member leaves or is removed from the Squad, we would not have the name or avatar to display for historical messages, which can be acceptable if we set up a default avatar and a removed member name. In our case, we preferred to keep that information shown in the chat channel. While this would not be an issue if these references were part of the message, (with this normalized set up) we would need instead to keep track of removed members for the Squad and use that the query for the name and avatar
Another important factor when setting up a chat feature is ensuring the security of the channel, as a Squad channel should only be open to its members. This made Firebase a great choice, since it offers a very flexible security JSON-based rules system that can be quickly set to cover this very use case. For instance, we would simply define the rule as follows:
That’s it.
Chat Interactivity and Rewards
With the Squad chat system set up, the next step was to extend its use and really make it a hub for the Squad. In addition to having it as a resource for the Squad to interact and navigate the game, we decided to incorporate a resources sharing mechanism into the chat tab itself. For example, when players invest their in-game currency into getting Elbow Grease (House Flip’s fuel for completing house renovations), a bonus amount is automatically made available to their Squad teammates, who would collect it from the chat. This means Squad members are encouraged to engage in the community, regularly check the chat to get awesome rewards, and in turn, be more inclined to participate in the conversation.
This is where the flexibility that Firebase Realtime Database offers really shines. All we need to do to add this is to add special messages. These would be messages sent by our system whenever there are rewards to be shared that would have information like the reward amount and type in the payload.
What Next?
Hopefully you can see why we ventured forth to build our own chat system considering our goal of delivering an integral guild feature using many of the advantages of the Firebase toolsets. In our next post, FUN-GI’s game development engineer, Osman Kaan Demiroz, will discuss how he hooked up the front end in Unity with all of these goodies from Firebase Realtime Database.