Coverage for /home/kale/kxgames/libraries/kxg/kxg/multiplayer.py : 99%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
""" Listen for an id from the server.
At the beginning of a game, each client receives an IdFactory from the server. This factory are used to give id numbers that are guaranteed to be unique to tokens that created locally. This method checks to see if such a factory has been received. If it hasn't, this method does not block and immediately returns False. If it has, this method returns True after saving the factory internally. At this point it is safe to enter the GameStage. """
# Make sure that this forum is only connected to one actor.
assert len(actors) == 1
# Connect the forum, world, and actors as usual.
# Cache the message and give it an id number the server can reference # in its response. Messages are cached so they can be undone if they # are rejected by the server. The id is necessary so the client forum # (i.e. this object) can associate each response with a cached message.
# Relay the message to a ServerActor running on the server to update # the world on all of the other machines playing the game as well.
# Have the message update the local world like usual.
""" Respond when the server indicates that the client is out of sync.
The server can request a sync when this client sends a message that fails the check() on the server. If the reason for the failure isn't very serious, then the server can decide to send it as usual in the interest of a smooth gameplay experience. When this happens, the server sends out an extra response providing the clients with the information they need to resync themselves. """
# Synchronize the world.
# Synchronize the tokens.
""" Manage the response when the server rejects a message.
An undo is when required this client sends a message that the server refuses to pass on to the other clients playing the game. When this happens, the client must undo the changes that the message made to the world before being sent or crash. Note that unlike sync requests, undo requests are only reported to the client that sent the offending message. """
# Roll back changes that the original message made to the world.
# Give the actors a chance to react to the error. For example, a # GUI actor might inform the user that there are connectivity # issues and that their last action was countermanded.
# An attempt is made to immediately deliver any messages passed into # execute_message(), but sometimes it takes more than one try to send a # message. So in case there are any messages waiting to be sent, the # code below attempts to clear the queue every frame.
# For each message received from the server:
# If the incoming packet is a message, execute it on this client # and, if necessary, synchronize this client's world with the # server's. Messages that were sent from this client will not # reappear here, so we don't need to worry about double-dipping.
# If the incoming packet is a response to a message sent from this # client, find that message in the "sent message cache" and attach # the response to it. The response is handled in the while loop # below (and not right here) to better handle weird cases that can # occur when several messages are sent between server responses.
# Try to clear the sent message cache:
# Don't handle any response until responses for any messages that # were sent after it have been handled. This keeps the world in a # sane state for every response.
break
# If the server requested that a message sync or undo itself, then # do that. Messages coming from any client may need to be synced, # but messages that need to be undone were sent by this client and # rejected by the server.
# Now that the message has been fully handled, pop it off the # cache.
assert self.actor_id_factory is not None
raise NotImplementedError
# For each message received from the connected client:
# Make sure the message wasn't sent by an actor with a different id # than this one. This should absolutely never happen because this # actor gives its id to its client, so if a mismatch is detected # there's probably a bug in the game engine.
# Check the message to make sure it matches the state of the game # world on the server. If the message doesn't pass the check, the # client and server must be out of sync, because the same check was # just passed on the client.
else:
# Decide if it will be enough for the clients to sync themselves, # or if this message shouldn't be relayed at all (and should be # undone on the client that sent it). The message is also given a # chance to store information it can use later to sync the game.
self.world, response)
# Tell the clients how to treat this message. For the client that # sent the message in the first place, the response is sent on its # own. If a sync or an undo is needed, the client will retrieve # the original message from its cache and use it to reconcile its # world with the server's. Otherwise, the client will just clear # the original message from its cache. For all the other clients, # the response is attached to the message, but only if a sync is # needed (otherwise nothing special needs to be done).
# If the message doesn't have an irreparable sync error, execute it # on the server and relay it to all the other clients.
# Deliver any messages waiting to be sent. This has to be done every # frame because it sometimes takes more than one try to send a message.
""" Relay messages from the forum on the server to the client represented by this actor. """
""" Don't ever change the world in response to a message.
This method is defined is called by the game engine to trigger callbacks tied by this actor to particular messages. This is useful for ordinary actors, but remote actors are only meant to shuttle message between clients and should never react to individual messages. """
self.__class__.__name__, self.sync_needed, self.undo_needed)
""" Pickle messages before they are sent over the network, and unpickle them when they are received. Tokens that have been added to the world are serialized using their ID, then replaced with the corresponding token from the remote world when the message is deserialized. """
assert isinstance(message, Message), msg("""\ Both Message and ServerResponse objects can be serialized, but only Messages can contain tokens.""")
assert token.id, msg("""\ Every token should have an id by now. Tokens that are in the world should always have an id, and tokens that are being added to the world should've been assigned an id by Actor.send_message().""")
assert token not in message.tokens_to_add(), msg("""\ Actor.send_message() should've refused to send a message that would add a token that's already in the world.""")
else: assert token in message.tokens_to_add(), msg("""\ Actor.send_message() should've refused to send a message referencing tokens that aren't in the world and aren't being added to the world.""")
|