I'm working on the server/client design for a game similar to Clash of Clans. I've read through dozens of articles and have some general parameters of what I'd like to accomplish.
- Scalable (Probably will use AWS for load balancing and multiple instances and what not)
- Secure - Server is authoritative
- Fast - Make as much code run on client as possible.
So on the note about Fast/Secure. My game will have a save file. For the sake of argument, let's assume that the save file contains an array of buildings
MapBuildings and the player's current cash amount
cash. From my reading, the server should manage the save file. For example, the server will update the cash quantity every few seconds be taking the time difference between the last update, multiply by the cash production rate, then set the cash value. If the player taps "upgrade" on a building, it will send a request to the server "hey, the player upgraded building at (x,y)", then, the server will verify the player has enough cash, subtract it, and return the new cash amount. I also read that using a save file ONLY on the server isn't the best, because then the client will experience more latency because it has to wait for a server response for everything. So the client should have a save file too that's instantly updated, but verified against the server's response. So this is where I'm stuck, verifying and rectifying differences between the server's save file and user's save file. Here's my currently proposed solution, it has some holes, which I'm hoping you can fill in.
- Game is launched, the client's save file is used to initialize the game state. The save file's values are NEVER updated by the client.
- User has $100, and taps "upgrade" on a building (upgrade costs $50). Client checks cash (in game state, not save file), subtracts $50, and upgrades building to the gamestate immediately.
- Cash is now $50
- Client performs tick method, let's say cash production is $1/second. Client will take the time since last tick, and calculate the cash to add. Let's say client does this and now says the player has $51 dollars.
- Client adds "building upgraded" request to the network queue
- The queue is sent to the server every x seconds (I'm thinking 5 or 10 seconds?)
- Server checks if the user has at least $50, they do, so the server subtracts $50 off, adds the upgraded building to the save file, internally calculates how much gold the player should have ($51, based off time) and returns the changed values to the client
- Client receives changed values, overwrites save file (keep in mind, save file wasn't updated by the client), and saves the file to the file system.
- Client then verifies the save file's values according to the game state, if they don't match, they need to be resolved.
Here are the holes I'm struggling with:
- How do I account for latency between the client's calculated cash value and the server's? For example, the client will have generated a small fraction more cash, and the server's value will be x seconds behind, where x is latency. I want this to be really stable, I'll elaborate on this more in the next items.
- How should I compare the game state and the save file? This would require quite a bit of code to make sure they match, is this performance friendly?
- If the game state and save file don't match, should I make the user relaunch the game (to load initial values from save file again), or should I try to over-write the values in the gamestate? This could be challenging, because overwritting the game state could make the game appear really messed up to the user (buildings rapidly changing position, values jumping to different values). I'd lean towards forcing the user to reload, but as state in hole #1, this needs to be rock-solid so that a normal, non-cheating user will rarely experience a force reload dialog.
So, is my analysis model correct? Should I use a different model? How can I change my current model to fix the holes and verify an insync and clean networking interface between server and client? Also, if you have some resources, it'd be great if you can post them.