Chickens Must Die.Technical docs / Godot client

Godot 4 / Colyseus client

Client Network Protocol

The contract the Godot client expects from the authoritative Colyseus server: connection lifecycle, join options, state collections, realtime messages, and known integration limits.

01 / Client requirements

The client repository does not contain the backend. To enter the game scene, the Colyseus server must expose the expected endpoint, room, state collections, and messages.

Development endpoint: NetConfig.COLYSEUS_URL currently points to http://172.22.111.106:8080 in development. This is an environment-specific address, not a public production endpoint.
  • Run at the endpoint configured by NetConfig.COLYSEUS_URL.
  • Expose a room named my_room.
  • Accept join options nickname and playerColor.
  • Publish the players and seeds state collections.
  • Handle move and chat_send messages.
  • Send the application-level messages described below.

02 / Connection lifecycle

NetworkManager tracks the current connection state. Room lifecycle signals determine when the client can enter or leave the game scene.

State Meaning
DISCONNECTED No active room; join_game is available.
CONNECTING A join_or_create attempt is in progress.
CONNECTED Messages can be sent; is_in_room == true.
RECONNECTING The transport dropped and the SDK is attempting to reconnect.
LEAVING The client called room.leave().
8SDK reconnect attempts
250–3000 msReconnect delay range; starts at 250 ms
10SDK queued-message limit

The application wrapper does not send new messages while in RECONNECTING, even though the SDK has a message queue.

Lifecycle signals

Signal Client behavior
joined_room Safe point to transition into game.tscn.
reconnecting(code, reason) Notifies the application that the transport was interrupted.
reconnected Notifies the application that the connection has been restored.
game_session_ended The room was left; return to the menu.
connection_error(code, message) Room error displayed on the join screen.

03 / Join options

The join form sends a nickname and the selected visual variant:

{
  "nickname": "Player One",
  "playerColor": "chicken_1"
}
Value Displayed variant
chicken_1 White Chicken
chicken_2 Black Chicken
chicken_3 Dark Brown Chicken
chicken_4 Light Brown Chicken
Validation boundary. The client only checks that the nickname is not empty after strip_edges(). Length, allowed characters, uniqueness, and moderation must be enforced by the server.

04 / Room state

The client expects the following minimum shape of the room state. Values shown below are illustrative:

{
  "players": {
    "session-id-1": {
      "nickname": "Player One",
      "playerColor": "chicken_1",
      "x": 120.0,
      "y": 240.0,
      "mass": 5.0
    }
  },
  "seeds": {
    "seed-id-1": {
      "x": 360.0,
      "y": 180.0
    }
  }
}

players

Field Expected type Client usage
Collection key string Session identifier; distinguishes the local player.
nickname string Label above the character.
playerColor string Sprite animation prefix.
x, y number Target position or state used for correction.
mass number > 0 Player scale, collider, and camera.

seeds

Field Expected type Client usage
Collection key string Stable instance identifier.
x, y number Visual seed position.
Server-owned: The client does not locally predict seed spawning, collection, or collisions. Removing a seed from synchronized state removes its node. Safe seed placement and whether growth fits at the player’s position are backend rules.

05 / Client → server

move

Sent immediately after a direction change and as a heartbeat every 0.05 s.

{
  "seq": 42,
  "clientTime": 12345678,
  "input": {
    "left": false,
    "right": true,
    "up": false,
    "down": true
  }
}
  • seq increases from 1 during the lifetime of the player component.
  • clientTime is obtained using Time.get_ticks_msec(); it is not Unix time.
  • Input represents player intent, not a trusted position.
  • Client direction components are -1/0/1. Diagonal movement should be normalized using the same rules in the server simulation.

chat_send

{
  "text": "Hello!"
}

The client trims leading and trailing whitespace and rejects an empty message. Message length limits, rate limiting, filtering, and authorization are server responsibilities.

06 / Server → client

Message Minimum payload Current client behavior
chat_message {sentAt, nickname, text} Adds a message to the chat and scrolls to the bottom.
chat_error {code} Displays the error code for 3 seconds.
player_eaten {predatorSessionId} The local predator plays the eating sound.
game_config Any payload Emits a signal; no consumer in the current code.
tick_sync Any payload Emits a signal; no consumer in the current code.
__playground_message_types Any payload Only logs the payload.

chat_message example

{
  "sentAt": 1789053000000,
  "nickname": "Player One",
  "text": "Hello!"
}

sentAt must be a Unix timestamp in milliseconds. The client converts it to the system's local timezone and displays [HH:MM].

Current implementation: game_config and tick_sync are forwarded as signals, but client gameplay does not currently consume them. Do not mistake the presence of the signals for completed configuration or tick synchronization on the client.

07 / Simulation parity

The current client movement speed is 100 px/s and the map uses 16 × 16 px tiles. When local simulation is enabled, the backend should match the following behavior:

  • Convert direction flags into a movement vector.
  • Normalize diagonal movement.
  • Resolve movement along X, then Y, if collisions are expected to behave identically.
  • Publish authoritative position state regularly to the client.
Configuration is not yet driven by the server: The constants should eventually arrive through game_config. The signal already exists, but the client still uses local values.

08 / Known integration limitations

  • Joining and leaving: A join failure clears the room and restores DISCONNECTED. The wrapper does not expose matchmaking cancellation; the form and BACK stay disabled until the attempt ends. If leave times out while the room still reports a connection, the manager retains control and restores CONNECTED so LEAVE can be retried. There is no API to forcibly close the transport.
  • Reconnect UX: Reconnect signals do not yet drive a status screen, gameplay freeze, or a failure path after all attempts are exhausted.
  • Session features: No room selection, matchmaking, authentication token, or session restoration after an application restart.
  • Input acknowledgements: The client does not yet use seq to replay inputs or acknowledge the last processed packet.
  • Reconciliation: RECONCILIATION_ENABLED is off by default; the current algorithm only corrects position while idle.
  • Local collision behavior: With reconciliation disabled, local and remote interpolation set global_position without checking local collisions. The server must remain authoritative.
  • Secure deployment: The production endpoint needs a secure transport appropriate to the hosting environment. An HTTPS page should not connect to an insecure HTTP/WS endpoint.

09 / Backend checklist

  1. Create the my_room room handler.
  2. Validate and sanitize join options.
  3. Assign a collision-free starting position.
  4. Maintain the players and seeds schema collections.
  5. Process move on a fixed tick.
  6. Enforce chat_send frequency and length limits.
  7. Broadcast chat_message, chat_error, and player_eaten.
  8. Enforce the 800 × 608 map bounds and matching collision rectangles.
  9. Test reconnect, leave, and abrupt client shutdown.
  10. Version the contract before introducing incompatible changes.

For the server’s documented validation and synchronized schema, see the server protocol reference.