network module¶
Network package.
I’m too lazy to write more.
network.builders¶
Builders package.
These builders are used to build packets based on their nature. For instance, the player builder will only build player-related packets. The base builder is the base of all builders.
network.builders.base_builder¶
Module name: base_builder
network.builders.player_builder¶
Module name: player_builder
- class game.network.builders.player_builder.PlayerBuilder¶
Bases:
objectClass for the player packet builder.
- BROKEN_TILE_X = 'broken_tile_x'¶
- BROKEN_TILE_Y = 'broken_tile_y'¶
- HEALTH_KEY = 'health'¶
- LERP_KEY = 'lerp'¶
- NAME_KEY = 'name'¶
- PREV_X_POS_KEY = 'previous_x'¶
- PREV_Y_POS_KEY = 'previous_y'¶
- X_POS_KEY = 'x'¶
- Y_POS_KEY = 'y'¶
- static compress_player(player: dict) bytes¶
Compress a player dict into small, compact bytes object. TODO: Use UUIDs instead of names
- static decompress_player(bytes_obj: bytes) dict¶
Decompress a player bytes object back to a player dict.
- static get_compressed_player_packet(command_id: int, player) bytes¶
Return a compressed update player packet from the attributes of the given player object.
network.packet¶
Module name: packet
This module defines a set of methods for hashing, compressing and altering data packets.
- class game.network.packet.Compressor¶
Bases:
objectClass for compressing objects. Used for sending and receiving game data from the client/server.
- class game.network.packet.Hasher¶
Bases:
objectClass for hashing packets. Used for sending and receiving protocol commands from the client/server.
- class game.network.packet.Packet¶
Bases:
objectClass for determining the properties of the packet header.
- DATA_SIZE = 2¶
- game.network.packet.fill(data: bytes) bytes¶
Fill the packet with empty data if its size is not a multiple of BUFFER_SIZE.
network.protocol¶
Module name: protocol
- class game.network.protocol.Protocol¶
Bases:
objectClass for defining the protocol along with its request and response constants.
Client-server connection process:
The interactions between the client and the server are not entirely API-based. Here are the interactions between the two in chronological order:
The client asks for recognition by the server, and the server sends a response back to the client - this ensures that the client is valid
The client requests the server’s map data, and the server sends a response to indicate the start of the map’s data. Then, the map data itself is sent, along with a response to indicate the end of the data stream
The client requests to join the server, the latter sending back a response, after which the client sends their local player’s in-game name and listening for any potential errors from the server (name already taken, server full, etc).
The server requests the client’s local player state to be added, and at which point the client sends the requested data - the server finally responds to confirm that the data was well received
The client then requests the global game state, which the server subsequently sends - this is to ensure the client-side knows about all the other players on the server
Client-server update process:
The update process between the client and server allows for the server’s game state to be synchronised with the clients’ throughout the lifespan of the connection. As mentioned prior to this section, the API-based architecture does not necessarily apply. The server will repeatedly send to all clients, at a strict defined rate, its current game state. Here are the different update tasks in order:
If the client requests to disconnect from the server, the server will receive the request and disconnect the client
The client will first request for the global game state, which the server will provide
The server will then request right after the client’s local game state, which the client will provide
The client and server follow a strict delay in TPS (Ticks Per Second), allowing for only a limited amount of calls in a short time frame.
The idea of client predictions and server reconciliation are convoluted features to implement, and though I am eager to explore those ideas further, the genre that this game falls under makes these particular features very complex to add. It’s very fast-paced which requires sending thousands upon thousands of data packets, just to keep track of a single player’s position and movements (as opposed to slower-paced games where player movement is limited). This means the API-based architecture cannot be completely applied. The aforementioned features may be implemented in the future, but for now it’s no longer a priority.
- BUFFER_SIZE = 32¶
- CPACKET_MAGIC = 'CGPKT'¶
- DISCONNECT_REQ = 'BYEBYE'¶
- ENCODING = 'utf-8'¶
- GLGAME_EOS = 'OKGOTGLOBALGAMESTATE'¶
- GLGAME_REQ = 'CANISENDGLOBALGAMESTATE'¶
- GLGAME_RES = 'YESSENDGLOBALGAMESTATE'¶
- HIT_REQ = 'HIT'¶
- HIT_RES = 'GOTHIT'¶
- LCGAME_EOS = 'OKGOTLOCALGAMESTATE'¶
- LCGAME_REQ = 'CANISENDLOCALGAMESTATE'¶
- LCGAME_RES = 'YESSENDLOCALGAMESTATE'¶
- MAPDATA_EOS = 'MAPREADY'¶
- MAPDATA_REQ = 'MAPDATA'¶
- MAPDATA_RES = 'DATAMAP'¶
- MAXPLAYERS_ERR = 'REACHEDMAXPLAYERS'¶
- NAMEALREXIST_ERR = 'USERNAMEALREADYEXISTS'¶
- PACKETRECV_RES = 'PACKETRECEIVED'¶
- PACKET_EOS = 'PACKETEND'¶
- PLAYERJOIN_REQ = 'IWANTTOJOIN'¶
- PLAYERJOIN_RES = 'OKGIVEMEYOURNAME'¶
- PLAYEROBJ_RES = 'HEREISPLAYER'¶
- RECOGNITION_REQ = 'TILEGAME'¶
- RECOGNITION_RES = 'GAMETILE'¶
- SPACKET_MAGIC = 'SGPKT'¶