Protobuf Protocol
Flaggi uses Protocol Buffers v3 for all network serialization. Proto definitions live in shared/src/main/proto/ and generate Java classes in the flaggi.proto package.
Proto files
Section titled “Proto files”| File | Direction | Purpose |
|---|---|---|
client-messages.proto | Client → Server | Input, commands, invites |
server-messages.proto | Server → Client | State updates, game events |
Client messages
Section titled “Client messages”ClientMessage (TCP wrapper)
Section titled “ClientMessage (TCP wrapper)”Every TCP message from the client is wrapped in a ClientMessage:
message ClientMessage { string uuid = 1; oneof payload { Ping ping = 2; ClientHello hello = 3; ClientCommand command = 4; ClientInvite invite = 5; ClientInviteResponse invite_response = 6; }}The wrapper lets the server read one envelope and then dispatch by payload type.
ClientStateUpdate (UDP)
Section titled “ClientStateUpdate (UDP)”Sent every tick over UDP - not wrapped in ClientMessage:
message ClientStateUpdate { string player_uuid = 1; string game_uuid = 2; ClientMouseInput mouse = 3; repeated ClientKey held_keys = 4;}Key enums
Section titled “Key enums”enum ClientKey { KEY_UP = 0; KEY_DOWN = 1; KEY_LEFT = 2; KEY_RIGHT = 3; KEY_SHOOT = 4;}
enum ClientCommandType { GET_IDLE_CLIENT_LIST = 0;}Server messages
Section titled “Server messages”ServerMessage (TCP wrapper)
Section titled “ServerMessage (TCP wrapper)”message ServerMessage { oneof payload { Pong pong = 1; ServerHello hello = 2; ServerCommand command = 3; ServerInvite invite = 4; IdleClientList idle_client_list = 5; ServerJoinGame join_game = 6; ServerEndGame end_game = 7; }}This is the server-side mirror of ClientMessage.
ServerStateUpdate (UDP)
Section titled “ServerStateUpdate (UDP)”message ServerStateUpdate { ServerGameObject me = 1; repeated ServerGameObject other = 2; int32 tick = 3;}me is personalized for the receiving player, while other contains the rest of the visible world.
ServerGameObject
Section titled “ServerGameObject”The core game object transferred over the wire:
message ServerGameObject { int32 x = 1; int32 y = 2; int32 coll_x = 3; int32 coll_y = 4; int32 coll_width = 5; int32 coll_height = 6; GameObjectType type = 7; PlayerSkin skin = 8; PlayerAnimation animation = 9; bool facing_left = 10; double hp = 11; int32 flag_count = 12; string username = 13;}Why this shape?
Section titled “Why this shape?”The protocol keeps the game state simple to consume:
- the client gets a ready-to-render snapshot every tick
- the server does not send unnecessary internal state
- each object can be updated, filtered, or extended independently
Evolving the protocol
Section titled “Evolving the protocol”When changing a .proto file:
- Add new fields instead of renumbering old ones.
- Avoid reusing removed field numbers.
- Keep client and server in sync.
- Rebuild the shared module to regenerate Java classes.
Game object enums
Section titled “Game object enums”enum GameObjectType { PLAYER = 0; TREE = 1; FLAG = 2; BULLET = 3;}
enum PlayerSkin { SKIN_BLUE = 0; SKIN_RED = 1; SKIN_JESTER = 2; SKIN_VENOM = 3;}
enum PlayerAnimation { ANIM_IDLE = 0; ANIM_WALK_UP = 1; ANIM_WALK_DOWN = 2; ANIM_WALK_SIDE = 3; ANIM_WALK_DIAGONAL = 4;}Regenerating proto classes
Section titled “Regenerating proto classes”After editing .proto files, rebuild the shared module:
./gradlew :shared:buildThe protobuf Gradle plugin (configured in buildSrc/java-common.gradle.kts) runs protoc 3.25.1 and generates Java classes into the build output.