I’m working on a turn based multiplayer strategy game.
I have started to develop a server-client architecture.
My idea is that the main game-state should live on a server and the players should only have access a subset of that data locally (only what they should be able to see.) and the rules of the game should also be enforced on the server.
My current approach is to give all game objects a unique ID property.
So the clients will be able to tell the server something like:
I want to attack unit 352 with attack-ability 799.
Anyone spotting issues with this approach?
Are there better ways of keeping the clients and server in sync?
I’ve been working on a turn-based game as well that is client/server.
All objects have a unique ID that are stored in the DB. I only push to the client what the client absolutely needs. I also verify that the information the client sends is valid for that user. So if they say Unit 352 is attacking, I first check that user actually owns that unit.
If the attack-ability is fixed to the unit, then I don’t rely on the client to tell me the that information, I look that up on the server side.
Basically, I don’t trust ANYTHING the client sends until it’s verified to minimize cheating. The game actually runs on the server and the “Game” is just a thin client to interface to it.
When you are designing multiplayer games you need to think about how much data you are transmitting over the network.
Games like Call Of Duty suffer from problems of lag, one of the things that I hated about the game was you could sneak up behind someone and empty a full clip into their back, and nothing would happen because they had moved but their position had not been updated on your machine.
Solving this problem is absolutely key if you want a good multiplayer experience.
In the case you stated, it is possible that the target of the attack has moved , but the attacker’s machine has not picked up the move yet.
My solution is to process everything locally , then have the server broadcast the results.
So in your case I would resolve the attack on the local machine and transmit the results to the server
Instead of the server getting “unit 327 wants to attack unit 7763” , I would set it up so what the server gets is “unit 327 attacked unit 7763 and did 2 damage”
You’re talking about a real-time Mutli-Player game. He is doing turn-based. Completely different.
Relying on the client to tell you what happens is what allows cheaters to cheat.
I’ve never done a real-time game, so I don’t know if my approach would be correct, but if I were to give it a go, I would only transmit actions from the player to the server and return the results. i.e. Player moved forward, I would then return their updated position. Player fired a shot, I would keep track of that shot on the server and return the results of that shot. I would also push changes to the game as they are needed. So the game would be in a specific state at the start and only the changes to that state would be pushed down to the client.
Nice! Thats how I was thinking about it too. That the client should be a glorified input prompt pretty much.
Did you use some networking frameworks or libraries or did you roll your own?
When you determine what information they can have, roughly what does that system look like?
I realized that if this ID is a basic incrementing index some strategic information could be derived from it. I’m not too worried about it yet but at some point I should probably switch to some more random looking ID, maybe I can just salt and hash it?
Yes I guess these points are more relevant for real-time games.
But interesting stuff, I never thought about it before. Is this the reason why aim bots and similar were plaguing many real time games, because the clients have all(?) information available locally?
Yes, you could use a GUID for the ID’s (which I do) so that someone can’t just start passing random numbers to try and cheat.
GUID does take up a bit more space, but it’s something I can live with in my game. It also means if I need to scale the game up in SQL I can do replication, etc… without worrying about collisions, etc…
I have a REST API that I wrote and use the built in .NET stuff for doing the communication.
I use Newtonsoft JSON serializer and I tell it which properties of the object I want to send. The client has the full object, but only certain data gets populated.
So I might have a Unit Object that has 100 different properties, but I might only send the ID, Name, X and Y, and a few other stats. I don’t need to send things like the Data and Time when the object was created, etc… Basically just data needed for display purposes and interaction.
The board game arena website solves this problem and is detailed here:
That looks like an engine for making board games on-line? How does that help with MonoGame?
They have details of their architecture in the documentation. It explains how they solve the issues which the original poster is asking about.
Actually I should have been more specific with the link:
There are slides here on what they do for client/server etc:
Yeah, just substitute Browser for MonoGame App and it’s pretty close to what I do, however, that’s not a real-time game like they claim. It’s turn based. Real-Time would be constant communication with the server and would require a different implementation than they have.
At the end of a round I send a list of “Here is what happened” so that my Game can process those and do animations, show text, play sounds, etc…
I have what I call “Abilities” that inherit from
IAbility and implement a few methods, for instance:
public bool CanBeActivated(GameState gameState)
In that method the ability classes (
PlayCard etc) can look at the current game state and figure out if they can be activated at that time.
The problem is that the clients will not have access to the full game state so I need a way client side to check if abilities can be activated (just for the sake of graying out buttons etc, the server will make sure nothing illegal happens of course).
One way to do it would be to call said method on the server every time before the Ability objects gets sent out and “bake” that data so to speak. Eg. by adding a property to
public bool CanBeActivatedBaked or something like that. But it just seems a little inelegant to me.
Any other ideas?