Source code for evennia.server.portal.wire_formats.gmcp_standard

"""
GMCP MUD Standards wire format (gmcp.mudstandards.org).

This implements the GMCP subprotocol from the MUD Standards WebSocket
proposal (https://mudstandards.org/websocket/).

Per the standard:
    - BINARY frames contain regular ANSI in- and output (UTF-8 encoded)
    - TEXT frames contain UTF-8 encoded GMCP commands in the standard
      format: "Package.Name json_payload"

This is a good match for MUD clients that natively speak GMCP, such as
Mudlet, as it maps directly to their existing GMCP handling without
the extra JSON envelope layer.
"""

from evennia.server.portal.gmcp_utils import decode_gmcp, encode_gmcp

from .base import WireFormat


[docs] class GmcpStandardFormat(WireFormat): """ GMCP-native wire format over WebSocket. Wire format: BINARY frames: Raw ANSI text (UTF-8), used for game text I/O. TEXT frames: GMCP commands in standard format "Package.Name json_payload" Text handling: Outgoing text retains ANSI escape codes (no HTML conversion). Text is sent as BINARY frames. OOB: Supported via TEXT frames carrying GMCP messages. The GMCP format is: "Package.Name optional_json_payload" """ name = "gmcp.mudstandards.org" supports_oob = True
[docs] def decode_incoming(self, payload, is_binary, protocol_flags=None): """ Decode incoming WebSocket message. BINARY frames are raw text input. TEXT frames are GMCP messages. Args: payload (bytes): The raw frame payload. is_binary (bool): True for BINARY frames, False for TEXT. protocol_flags (dict, optional): Not used. Returns: dict or None: kwargs for data_in(). """ if is_binary: # BINARY frame = raw text input try: text = payload.decode("utf-8").strip() except UnicodeDecodeError: return None if not text: return None return {"text": [[text], {}]} else: # TEXT frame = GMCP command try: gmcp_data = payload.decode("utf-8") except UnicodeDecodeError: return None return decode_gmcp(gmcp_data)
[docs] def encode_default(self, cmdname, *args, protocol_flags=None, **kwargs): """ Encode an OOB command as a GMCP message in a TEXT frame. Args: cmdname (str): The OOB command name. *args: Command arguments. protocol_flags (dict, optional): Not used. **kwargs: Command keyword arguments. Returns: tuple or None: (gmcp_bytes, False) for TEXT frame, or None if cmdname is "options". """ if cmdname == "options": return None kwargs.pop("options", None) gmcp_string = encode_gmcp(cmdname, *args, **kwargs) return (gmcp_string.encode("utf-8"), False)