The purpose of these Dev Logs will be to share with everyone the creation process for Steampunk Panic. A way to look behind the curtain, so to say. Some of these Dev Logs will be simple, others will give plenty of in-depth explanation for how things work or why things were done the way they were.
Leaderboard Server, Done!
These past few weeks, I’ve been wrapping up the server code for Steampunk Panic to handle a global leaderboard for each game difficulty mode. I have worked on leaderboard features before on other products for other game studios, but this was the first time I had to roll my own and handle every aspect. The process was super fun and I’m pleased with the result!
Steampunk Panic is all about chasing the high score and doing better than last time. You can always compete against your own score, but some will like to climb a leaderboard to see how far they can go, and now you can.
I opted for a global leaderboard to start with, but can easily create leaderboards per country or any other type of segmentation that I want. It’s as easy as pointing at a new leaderboard name and running with it. The only reason why I would want to separate users is if the user count gets massive. So, when Steampunk Panic launches, I’ll be keeping track of the leaderboard sizes to determine the next step to take.
For those curious, if the leaderboards get out of hand, I will have the following options:
1) Create leaderboard “buckets” which would be assigned to players. I could have 10 leaderboards, and every new player gets assigned to a leaderboard when they first log in. This would distribute everyone evenly, so if I have 100,000 players, each leaderboard could have 10,000 ranks.
2) Go with timed leaderboards. Right now, the leaderboards are for lifetime scores. But if there is a large number of players, I might need to reset the leaderboard every week. Players who drop out and no longer play will be weeded out from the leaderboard in this manner, with each new week providing players a chance to climb again. The disadvantage of this method is that there is no reward. Steampunk Panic has no premium currency, it has nothing to unlock. What would be the point of climbing the leaderboard that week, if your progress is just going to be wiped?
3) Like the buckets idea, I start segmenting players into countries or geolocations. The game no longer has a global leaderboard and you are competing with local players. This could be fun … but I would prefer to keep it global.
I had to make a decision: Do I use the platform’s build-in leaderboard support (GameCenter for iOS, Google Play Games service for Android)? Or do I go with a cross-platform leaderboard?
There are benefits to using the platform’s leaderboard support, especially if there is a friend list built in, letting you compete against your friends or the world. But it’s also easy to cheat these leaderboards, as all you need to do is submit a score to Apple or Google and their services just accept that as a valid score. This is how leaderboard get filled with tons of fake, impossible scores.
So, I opted for my own leaderboard approach that is cross-platform and handled by my servers. Fake scores won’t be able to be submitted because of score validation I do on my end, so when you load up the leaderboard, you should be guaranteed real scores!
Players will be ranked, based upon the game mode they played. Everyone playing the Easy mode will be ranked against scores submitted in the Easy mode. This seems fair, as the last thing I want is for someone to plateau on Easy mode at 150,000 points or something and still be at the bottom, since Hard and Expert modes provide way more points.
The leaderboard will show the top 15 players in that mode, as well as the 15 players who are near your current rank. For example, if you are rank #52, you’ll see rank #1-15 on the top section of the leaderboard, and ranks #35-50 on the bottom section. This allows you to see how close you are to climbing the next few ranks, as well as seeing how close you are to losing your current rank.
So, score validation… how does it work? To start, your game client communicates with the server to get some randomized, unique data for your specific game mode that you’re starting. The server locks this info down and your game client spins up the new game. Your game client also knows what your high score is for that mode.
As you are playing the game, a replay of your input is being generated. At the end of the game, your game client will look at your high score and that game’s score and, if you have a new high score, it’s time for score validation on the server!
The server receives your replay input data and the expected score, then spins up a new game on the server, also loading in the unique data it has saved off for that game. It will replay the game with the input data sent and verify that the score on the server is the same that the player said they got. If it is, the leaderboard is updated, the score is saved on the player’s server data. If the score is different, there is a chance that the data was modified before being sent to the server, so it will fail.
Now, in order for this to work, the server uses a deterministic random number generator that will generate the same number sequence, no matter the device or platform. This number generator is also used on the game client, so they will always be in sync.
Since this is a very important part, many tests were created to validate the score validation code. I created test code that would generate a new game and play from 1 to 100,000 hits, skipping over every 10 hits (so, 1, 10, 20, 30, 40, etc.). This would generate 10,000 games, all using the same number seed for the game. I would do this for 100, and then 500 different number seed. Then I could just generate 1,000 games, with 1,000 different seeds, with ending with 1 to 1,000 hits (chosen at random). Every one of these games would be played by an AI, processing all of these games over the span of a few minutes and then validating them. Every game validation passed, with replay data matching the replay data’s replay data that is generated. So, I feel pretty confident that this is pretty solid.
I also tested failures as well, and invalid replays, also with thousands of iterations.
Score validation via replay data is extremely quick, so the server should be able to handle hundreds of replays a second without batting an eye. I expect 1-2 replays a second to roll in, maybe jumping up to 10 per second if lots of users are playing. The great thing is that validation only happens if it is a new high score. If your high score is 90,000, I’m not going to waste time validating your 33 point game, it won’t affect the leaderboard!
In order to submit a score to the leaderboard, you need a name. So, the first time you start the game, you’ll be asked to pick a leaderboard name. There are rules in place for names:
1) 3-20 characters long
2) No special characters
3) Nothing profane
4) Needs to be available
The first two rules are easy to enforce with simple code. Profane names, however, is a little more difficult. I am not going to be able to cover every profane name or situation, but I am able to cover a lot of common situations. I am using a profanity filter to handle this on the server. But, there will be names that pass through.
So, every day, I have the server compile a list of all new names and an email is generated for me. I can browse it quickly to see if anything jumps out and, if so, I can mark a name as profane, which will trigger a rename. On my end, when I mark a player name for rename, it will generate a new user name (Player ######) and rename the player on all leaderboards. Then, the next time the player logs in, they will presented with the rename dialog and, once renamed, all leaderboards will also have that name renamed again. I don’t expect to be doing this often, but I wanted the feature to be there, just incase someone in the top 15 on the leaderboard (who will be seen by everyone) has a horrible name.
In the future, I might add a report name button on the leaderboard, letting players police the board themselves. After being flagged a couple times, I might see the name in a daily report so that I can review it. If it’s in need of a rename, then I do it. Otherwise, I mark it as safe and it’s good to go. I would never auto-mark a name for rename, it would always need to be reviewed before a final decision is made. I wouldn’t want the button feature to be abused.
Wrapping up Android work!
Monetization will be talked about soon, as well as an update on new concept art and the art direction for the game.
We’ll need to pick some music for the game and start designing UI elements (the menu, leaderboard screen, dialogs, etc.) that fit the art deco steampunk aesthetic.
I can’t wait to share more of this process with you in the next couple Dev Logs!