Search Unity

Strategies for client caching in authoritative server setups?

Discussion in 'Multiplayer' started by fastgamedev, Jul 30, 2014.

  1. fastgamedev

    fastgamedev

    Joined:
    Mar 27, 2014
    Posts:
    79
    Hi,

    The general problem I am facing is an asynchronous mobile game with an authoritative server setup. The client is allowed to run some game logic in the absence of a network connection. When the network connection is later restored, the client sends to the server its updates since the last sync up. The server can partly or fully accept or reject client updates.

    I haven't built such infrastructure before, so any pointers, references, ideas on such architectures you have would be much appreciated. Right now my thinking is to keep a cache of player actions on the client, which can be accepted or rolled back by the server. But the devil is in the details. How to do this elegantly and efficiently in C# and Unity?

    Thanks!

    P.S. All actions are verified by the server and in case of inconsistencies are not applied. So for example, let's say on the client you start with 100 coins, then buy a banana (cost 10 coins), then buy an apple (cost 20 coins). You send this action history to the server:
    1. action: buy banana; result: coins = 90
    2. action: buy apple; result: coins = 70
    The server loads your last known state (coins = 100), sequentially applies the actions you sent and verifies the results. In this case everything matches. If instead you hacked the client and sent a different action history:
    1. action: buy banana; result: coins = 90
    2. action: buy apple; result: coins = 1000
    The server would verify the first action, but deny the second. So on the server the players last know state would be updated to (coins = 90), and the client would get a command to rollback action #2.
     
  2. BFGames

    BFGames

    Joined:
    Oct 2, 2012
    Posts:
    1,543
    Well you got the right idea, but without info on your server setup i can't really help.

    What framework are you using? What data are you sending for actions (Bytes forexample) ?

    One thing i can say though, is that the client should never sent the result, only the actions. So in your example you sent buy banana and buy apple, and the server returns the result.
     
  3. fastgamedev

    fastgamedev

    Joined:
    Mar 27, 2014
    Posts:
    79
    Using uLink.
    All sorts of data structures (int, float, dictionaries, etc) are exchanged between client and server via RPC.

    If client doesn't send the results, then the server cannot do partial rollbacks. But maybe they are an overkill, either the client is hacked or it isn't.

    One idea I have is to add a proxy server (inside each client) to the game. Then the client talks to the proxy which in turn talks to the server. The proxy would be responsible for recording the actions and supplying the client with simulated server responses when the network is down. The proxy would be responsible for syncing action cache with the server and if necessary rolling back the client. This makes the design modular with the client having no idea who it's talking to, server or proxy.
     
  4. BFGames

    BFGames

    Joined:
    Oct 2, 2012
    Posts:
    1,543
    Well they could just switch of the internet and then they know who they are talking to ;)

    Don't think there is a bullet proof way to do this as long as you let them play 'offline' and choose what should be sent to the server afterwards.

    Another problem is that if you have a coin or banana pick up item on your server, then two offline players will both pick it up, but only one will get it (If you check with time-stamps when you sent actions) and the other one will become frustrated.
     
  5. fastgamedev

    fastgamedev

    Joined:
    Mar 27, 2014
    Posts:
    79
    > Well they could just switch of the internet and then they know who they are talking to

    LOL, yes. I meant code-wise the client is independent of proxy.

    > Don't think there is a bullet proof way to do this as long as you let them play 'offline' and choose what should be sent to the server afterwards.

    The server verifies all the results, so fooling it is not possible.

    > Another problem is that if you have a coin or banana pick up item on your server, then two offline players will both pick it up, but only one will get it (If you check with time-stamps when you sent actions) and the other one will become frustrated.

    Yes, this would be a problem in a multi-player game, but I am not building one. I am making a networked single-player game, think Hay Day.

    So you haven't seen any info on such architectures either?
     
  6. BFGames

    BFGames

    Joined:
    Oct 2, 2012
    Posts:
    1,543
    Ah well then i see no reason for only sending the actions and not results?

    If the server gets the messages in the right order it should be rather easy to see if its valid or not.

    So lets say you say you walk to a banana which you pick up at a position. If you are offline you will cache the action (Lets call it action A) and then locally accept that you picked the banana adding one banana to the client. Then you create a banana bomb which costs 10 bananas (the exact amount you have now) which is action B, then you add one banana bomb to the client.

    Now lets say that the client hacked it with a fake pick up banana message.

    When you switch you internet back on the it should be possible to see on the server if there is a banana at the position or if the move from last known position to the banana is impossible, if it is then you ignore the message and updates the client with actual amount of bananas. Now the Action B, since you only have 9 bananas on the server, cannot be valid create a banana bomb, so you update the client with the right amount of bombs, and so on with all actions.

    This will however only work if the messages are saved in correct order. But that should be rather easy as you can just send them with time stamps and then sort them on the server. (Using TCP could also automatically do the job).

    Overall the server will play through all your actions in lightning speed to check if they are valid or not and correct anything not in order. If the player did not cheat then they should not notice any changes as such.

    I have not worked with such a setup before, but cannot see why it would not work.
     
  7. fastgamedev

    fastgamedev

    Joined:
    Mar 27, 2014
    Posts:
    79
    Yes, we are on the same page. Conceptually it's not a hard idea. But the devil is going to be in the details. There needs to be some kind of C# code that sits between the client and the server, records actions, passes them on to the server, receives responses, resolves conflicts. I was hoping to find this code and not have to reinvent the wheel.
     
  8. BFGames

    BFGames

    Joined:
    Oct 2, 2012
    Posts:
    1,543
    Send a message with an enum (byte) which defines the ActionType and a Dictionary<byte, object>, which will hold enums (byte) for InformationTypes like position, time-stamp etc.

    When the server receives the message then check what type the ActionType sent is (in a switch or something like that) and then make a handler method for each action. When the ActionType handler is found check if the dictionary holds all the required information (in a try/catch). If it does extract it and use the information to check if the action is valid or not and respond to the client accordingly.

    You can simple create a class/struct client side which holds the ActionType enum and the dictionary and then store them somewhere. And then send them when you are online again.
     
    Last edited: Jul 31, 2014