When running `evennia start -l &`, the subprocess gets suspended by the OS due to TTY constraints. Explicitly passing `stdin/stdout/stderr` to DEVNULL prevents this hanging state without altering Foreground & Daemon behavior.
Implement RFC 6455 Sec-WebSocket-Protocol negotiation for Evennia's
WebSocket server, following the MUD Standards WebSocket specification
(https://mudstandards.org/websocket/).
New subprotocols:
- json.mudstandards.org: JSON envelope format with structured OOB
- gmcp.mudstandards.org: GMCP over WebSocket (TEXT + BINARY frames)
- terminal.mudstandards.org: Raw ANSI/UTF-8 in BINARY frames
Architecture:
Wire format strategy pattern via composition. A single WebSocketClient
delegates encoding/decoding to a WireFormat instance selected during
onConnect(). Adding a new format means adding a single file to the
wire_formats/ package with zero changes to webclient.py.
Backward compatibility:
Clients that send no Sec-WebSocket-Protocol header (including the
built-in Evennia webclient) get v1.evennia.com format automatically.
Existing behavior is fully preserved.
Additional changes:
- Extract shared GMCP encode/decode into gmcp_utils.py (used by both
telnet and websocket GMCP paths)
- Add WEBSOCKET_SUBPROTOCOLS setting for server-side format control
- Built-in JS webclient now sends Sec-WebSocket-Protocol: v1.evennia.com
- Comprehensive test suite for all wire formats (~870 lines)
Upstream is O(n^2) time complexity due to nested loop. Diff includes O(1) dict look up with short filter. Symbol_map is already built during `XYMap.parse()`.
1. `__name___` triple-underscore typo.
2. Broken f-string in `Trait.__init__`. `type(trait_data)` is literal text, not interpolated.
3. `type() in (float, int)` rejects subclasses of int/float. `isinstance(value, (int, float))` is safer.