Skip to lesson
Game Hacking Academy
Preparing lesson text…
Exit reader mode
Voice and speed

Preparing read-aloud controls…

Lesson 9.6 Listening edition

Clients, Handshakes, and Chat Automation

See a complete protocol client perform Wesnoth's local handshake, read framed messages, and respond to one chat command.

About 24 minutes

Section: What we are building.

Run wesnothd.exe on your own computer, connect a client named ChatBot, and make it answer \wave with Hello! in the lobby.

This is not a toy protocol. It uses the exact flow we reversed from Wesnoth 1.14.9:

Lesson diagram

Keep transport, decoding, session meaning, and behavior as separate layers. One incoming message should travel through the pipeline before any reply is built:

Turn a lobby command into a framed reply

This separation lets a malformed frame fail before it reaches chat behavior, and it lets the command handler work with events instead of raw network bytes:

What each layer passes on.

Section: Connect with timeouts.

Before reading protocol bytes, the client needs a connection that cannot silently drift to another host or wait forever for a stalled local server. connect_local accepts one socket address, checks that it is the course loopback endpoint, then sets finite connect, read, and write waits:

Code example. The surrounding prose explains this example; the full lesson contains the exact code.

In brief: A timeout bounds how long the bot can wait; a verified endpoint bounds whom it talks to.

Section: Read and write exact frames.

Lesson 9.4’s encode_wesnoth_frame performs the gzip compression and adds the four-byte big-endian length. write_all matters because one write may send only part of a buffer.

Labelled memory cells

The two helpers implement the strip in opposite directions. send_wml frames text and writes all bytes; read_frame reads the four-byte length, checks the cap, then reads that many payload bytes before a decoder sees them. A short T C P, transmission control protocol, read is normal, so both paths use the exact-read/write operations:

Code example. The surrounding prose explains this example; the full lesson contains the exact code.

Code example. The surrounding prose explains this example; the full lesson contains the exact code.

read_exact handles T C P fragmentation. It does not assume one receive call equals one Wesnoth message.

Section: Handle early server replies.

The opening negotiation is special, so collect its replies until a short quiet period. The historical capture received 41 bytes.

Alternative: Treat the connection like a conversation: inspect the reply before deciding which question is appropriate next.

Lesson diagram

This quiet-period reader is only for the unframed negotiation reply. It collects successive T C P reads until the server closes or pauses briefly, while the size cap prevents an unexpected reply from growing forever. After login, read_frame uses the protocol’s length field instead:

Code example. The surrounding prose explains this example; the full lesson contains the exact code.

Keep this helper for negotiation only. Once the session is in the lobby, use the frame reader.

Section: Perform the Wesnoth 1.14.9 login.

The parser and frame writer now have a concrete job. The course server first expects four zero negotiation bytes, then a version message and a login message in compressed W M L frames. log_in sends them in that order and reads each reply before advancing; a nickname is validated before it enters W M L:

Code example. The code’s comments explain: The first message is not compressed or length-prefixed.

If the server rejects the version, compare the decompressed frame with the one produced by the official 1.14.9 client. Do not randomly change compressed bytes; fix the W M L and recompress it.

Section: Answer \wave.

Once the login succeeds, the client announces itself and loops over framed server messages. A decoded \wave event will produce the reply described above; ordinary messages leave the connection running:

Code example. The surrounding prose explains this example; the full lesson contains the exact code.

Section: Prove the bot works.

Start wesnothd.exe.

Run the client with address 127.0.0.1:15000 and nickname ChatBot.

Join localhost:15000 from the normal Wesnoth client.

Type \wave in the lobby.

Confirm Hello! appears from ChatBot.

That visible lobby response proves the real negotiation, version, login, gzip framing, Simple W M L, receive loop, and command logic all work together.

Section: Keep it well behaved.

Limit message length, respond at most once per command frame, add a short send rate limit, and exit cleanly when the local server closes. A parser error should print the frame size and stop; it should not enter an automatic reconnect storm.

Narration: A reply rate limit prevents one repeated command from filling the lobby with messages.

Section: Run the complete bot.

After building the workspace, start the course wesnothd.exe on port 15000 and run:

Terminal window

Code example. The surrounding prose explains this example; the full lesson contains the exact code.

The full client is wesnoth_chatbot.rs. The framing/parser it imports is wesnoth_protocol.rs. Together they implement the real loopback connection, timeouts, four-zero negotiation, version frame, login frame, lobby receive loop, \wave recognition, and Hello! reply.

Additional detail: Complete lab source: wesnoth_chatbot.rs.

Code example. The surrounding prose explains this example; the full lesson contains the exact code.

The reusable gzip/W M L framing stays in one tested protocol module; this file owns the session state. That split is intentional: byte framing should not know what \wave means, and chat behavior should not reimplement gzip.

Silent video demonstration: An external client answering Wesnoth chat. The original external-client demonstration shows a chat command receiving a reply. The visible exchange depends on the earlier connection, negotiation, login, frame decoding, and command handling; a valid message alone is not a complete client.

This bot owns its own server connection. Lesson 9.7 puts a relay between the official client and the same local server, so we can observe an existing conversation before choosing one bounded change.