IN THIS ARTICLE
We’ve updated our SDKs, and this code is now deprecated.
Good news is we’ve written a comprehensive guide to building a multiplayer game. Check it out!
This is part one of our two part series on developing an app with a client-server model. You can read the series overview here, or hop on over to Part One:
Building the Client Side for an iOS Game with Objective-C. This two part series on building an iOS app with a client-server model was developed by our two summer interns, Taylor Kimmett and Ajan Jayant.
Problem:
How can I create a server that can manage the state of games and players, and communicate those states to clients in such a way that is independent to the client’s platform?
Solution:
- C# game server
- Strongly typed to help manage/understand potentially complex game systems
- Relatively easy incorporation of multiple threads and event-driven callbacks for processing requests
- PubNub
- Real-time message passing
- Given the set of request types available to interface with the server, the game client can run on any platform supported by a PubNub SDK
- Game can scale to arbitrary number of users (consider fan-in issue)
- Implementing client code to communicate with server may be simplified by using PubNub as opposed to using native Networking APIs for different platforms (understanding how a single general API works as opposed to learning the intricacies of many)
- Greatly improves ability to do early stage testing and rapid development because there is no need to run the server on a hosted platform. Especially useful for multi-developer teams working on separate computers where a locally hosted server might not be sufficient for development.
- REST-esque model
- Most ubiquitous model for any kind of web service: any developer familiar with web services will have an immediate basic understanding of what I’m doing if I need to bring them on board for help, etc.
**NOTE: Since we wrote this tutorial, we’ve released a new, completely-redesigned version of our iOS SDK (4.0). We rebuilt the entire codebase and took advantage of new features from Apple, simplifying and streamlining the SDK.
The code from this tutorial still works great, but we recommend checking out our new SDK. We’ve included a migration guide to help you move from 3.x to 4.0, and a getting started guide to help you create a simple Hello World application in minutes.**
Apply it:
A developer probably wouldn’t apply this to an app they’ve already built, but rather use this as a model/guide for developing a similar kind of app in the future.
Here’s what we did
First, it’s best to take a couple cues from existing games that you’ve already played, at least to get a general idea of how the architecture of a game looks. Virtually every major multiplayer game relies on some kind of server or servers to manage the state of players and other game elements.
To give a brief introduction to our server, we’ve come up with a relatively simple model since poker doesn’t have too much overhead in terms of setting up a game. Our server is written in C# and consists of two primary units that actually handle messages sent from the client:
- Server– handles messages not specific to a certain game
- Responsibilities:
- User creation
- User login
- Brokering access to games
- Responsibilities:
- GameManager– maintains all aspects of a single game, can be thought of conceptually as a poker table
- Responsibilities:
- Manage all game logic
- Process player actions (call, raise, fold, etc.)
- Update clients when game’s state changes (basically when a player acts)
- Inform players when it’s their turn
- Draw and deal cards
- Determine winner
- Responsibilities:
We have other components to represent decks of cards, individual cards, players, etc. but delving into those probably wouldn’t be useful because they’re very specific to a card game. But mentioning them brings up the topic of object oriented design and best practices for designing and managing possibly complex (especially in the case of games) systems.
Having a strongly typed language like C# gives you a much better sense of how components communicate and work with each other. A strongly typed language can also make it easier to visualize or otherwise reason about your project since games often consist of real world concepts, such as cards or poker tables, which can be represented logically by classes.
Client—Server Communication
We’re using PubNub to actually transfer our messages between clients and the server, so there isn’t necessarily a strict request/response model as with a normal REST service. Instead, we simply emulate the request/response model with different types of messages sent through PubNub:
All of the code that makes up a simple server is in the snippet above—no web servers, no worrying about hosted domains or port forwarding, just subscribe to handle incoming requests and publish to issue a response back to the client.
When you’re designing your game and figuring out how all of the pieces need to fit together, you probably don’t want to worry about all of the issues associated with writing a REST service and then trying to get it hosted to a point where you and anyone else working with you can sufficiently implement and test new features.
Another reason we’re using PubNub is because it ends up making life easier for our client developer because he doesn’t need to figure out how to consume and interact with a traditional REST service using native networking APIs for iOS, he just needs to know how to use the much simpler PubNub SDK for Objective-C. If we wanted to port the client app to other platforms we would see PubNub’s benefits multiply as we don’t have to learn the idiosyncrasies of yet another client-side networking API.
PubNub’s C# game server is really just a command line application that just loops and waits for a ‘quit’ command from the console. You might be thinking that blocking code execution to wait for console input is a bad idea for a server, but since all of the PubNub callbacks are asynchronous, the system simply spawns a new thread to handle and respond to the request.
To give you an idea of how our model works, take a look at the sequence of events that occur when a user tries to login:
Does your game actually work?
The last thing you want to see is players of your game quit because it just doesn’t work how it’s supposed to. That’s why you should probably do some testing, at least to make sure the core features are working properly in all possible scenarios. To give an example, we’re using an external library to evaluate the strength of players’ poker hands, but that library requires cards to be represented in a specific format that doesn’t necessarily match up with how we normally represent cards.
So we made sure to test our code that translates our card representations into a form that the hand evaluator can read, because no one wants to have a full house and lose to high card two because you didn’t do enough testing.
C# Game Server Wrap up
Even though you may not necessarily be making a poker game, or even a card game in general, you can still apply the general principles we discussed here to help you build a multiplayer game relatively quickly. You may not be able to build your game out with 100% of the features you want in two weeks, but you should be able to have a pretty solid core with at least basic functionality.
If you happen to be using PubNub for your game, that’ll also make it very easy for you to scale up in case your game grows in popularity, or if you want or need to incorporate features that PubNub is very good at, like broadcasting to many users at once, or client-client messaging without getting your server application involved.
All the code you need to get started right away is in the GitHub repository below.