samedi 15 juin 2019

How to design partial client side prediction if client stores only partial state?

tl;dr: if we keep the true state secret and only expose parts of it that should be visible to the requesting user via a "state view", how can we implement client side prediction (of things that could be predicted) considering that state updates operate on the "real full state", not state views? (without duplicating update code for state views)

Consider having a server "domain state" class that keeps track of players' scores and coin counts:

class SeverState(object):
    scores: Dict[str, int]
    coins: Dict[str, int]

we would like each client to know other players' scores, but keep the coin count secret, and have some derivative state (possibly using secret data) therefore we expose only a "view" of the server state:

class ServerStateVeiw(object):
    scores: Dict[str, int]
    my_wealth: int
    richest_id: int

def get_state_view(state: ServerState, player_id: int):
    return ServerStateVeiw(
        state.scores, state.coins[player_id], argmax(state.coins))

players can take certain actions to change the game state

def export_rpc(f):
    @wraps(f)
    def wrapper(context):
         new_state = f(context.player_id, context.game_state)
         return get_state_view(new_state)
    rpc.register(wrapper)
    return wrapper

@export_rpc
def grab_a_coin(state: ServerState, player_id: int):
    updated_coin_counts = state.coins[player_id].increment()
    return ServerState(coins=updated_coin_counts, scores=state.scores)

@export_rpc
def buy_score(state: ServerState, player_id: int): ...

Of course we can not know who is the richest player after taking a turn (doing grab_a_coin) without server telling us, but we definitely should have enough data at that point to know our own wealth and scores of others (assuming they did not change).

Assume that we can share the entirely of our codebase with the client. I wonder what are patterns for not repeating yourself in a situation like that: how can we let the user predict their updated state view if our server side code operates on original states (e.g. grab_a_coin function)?

One way is for the ServerStateView to have exactly same fields as ServerState, storing only information available to the user, and "secret fields" raising exceptions upon access or returning UnknownData() instances (e.g. coins would only return an actual number when accessed with current player_id and would not hold any "secret data" whatsoever), e.g. something like coins = SecretDict(player_id = state.coins[player_id]). But this seems

Aucun commentaire:

Enregistrer un commentaire