Start the listener
0.0.0.0:5050 using SO_REUSEADDR, so the port is immediately available again if you restart. It accepts one connection at a time (server.listen(1)).
Once the game connects you will see:
Shell commands
The listener translates a small set of cross-platform commands before sending them to the remote host.| Command | Description |
|---|---|
ls | List files in the current directory (maps to dir on Windows) |
cd <path> | Change directory — the session tracks state across commands |
cat <file> | View a file’s contents (maps to type on Windows) |
pwd | Print the current working path |
download <file> | Transfer a file to downloads/ (relative to listener’s cwd) on the operator machine |
quit | End the session and close the connection |
File download workflow
Game packages the file
The game reads the file, base64-encodes it, and sends it wrapped in a protocol envelope:
Listener decodes and saves
The listener detects the The directory is created automatically if it does not exist.
[FILE_BEGIN:...] tag, calls base64.b64decode, and writes the file to a downloads/ subdirectory relative to wherever you ran listener.py from:The
downloads/ directory is created automatically on first use. The listener uses a 65536-byte receive buffer for large file transfers.Prompt and directory tracking
The game sends[PATH: /current/dir] tags with every response. The listener strips these tags from displayed output and uses the path to update your prompt:
operator@{dirname} $ where {dirname} is the last component of the remote path.
Heartbeat filtering
The game sends[HEARTBEAT] packets every 15 seconds to keep the connection alive. These packets are automatically stripped from all output — you will never see them in your terminal.
Response timeout
The listener waits up to 10 seconds for a response after sending a command. If no data arrives within that window, it prints a timeout notice and returns you to the prompt without dropping the connection.Reconnection behavior
The listener runs an outerwhile True loop. When the connection drops (game exits, network interruption, etc.), the listener closes the old socket and immediately starts waiting for the next connection on the same port:
listener.py between game sessions.