GMCP/MSP/MSSP/MXP/ZMP/MSDP协议详解与MUD推荐配置

如果你对MUD开发有一定的深入,就会注意到运行时配置中有GMCP/MSP/MSSP/MXP/ZMP/MSDP这些,而还有一些相关的apply和efun,它是干啥的?下面开始科普这些协议,特别是如果你在开发移动端APP,一定要深入了解。

现代MUD协议架构

核心原则: 现代MUD开发采用GMCP作为主力协议,保留MSSP用于服务器列表,MSP用于音效支持

enable gmcp : 1    # 唯一核心协议
enable mssp : 1    # 服务器列表必需
enable msp : 1     # 可选(音效需求)
enable mxp : 0     # 淘汰
enable zmp : 0     # 淘汰
enable msdp : 0    # 淘汰

这样如果你开发移动端app,就可以只用GMCP传数据,用MSP控制app不同环境的音效(也可以直接用GMCP来控制音效),用MSSP显示服务器状态,一切都变的优雅简洁。


协议详解与实现

GMCP (Generic Mud Communication Protocol)

协议代码: 201 (0xC9)

功能描述: 现代JSON数据交换协议,用于客户端与服务器之间的结构化数据传输,是MXP、MSDP、ZMP的现代替代品

相关EFUNs:

  • int has_gmcp(object ob) - 检查玩家是否启用GMCP
  • void send_gmcp(string message) - 发送GMCP消息到客户端

相关APPLYs:

  • void gmcp_enable() - GMCP启用时调用
  • void gmcp(string message) - 收到GMCP数据时调用

完整示例:

// 角色状态同步
void send_character_status() {
    mapping data = ([
        "vitals": ([
            "hp": this_player()->query("hp"),
            "max_hp": this_player()->query("max_hp"),
            "mp": this_player()->query("mp"),
            "max_mp": this_player()->query("max_mp")
        ]),
        "combat": ([
            "in_combat": this_player()->query("in_combat"),
            "target": this_player()->query("target")
        ])
    ]);

    if (has_gmcp(this_player())) {
        this_player()->send_gmcp("Char.Status " + json_encode(data));
    }
}

// 房间信息同步
void send_room_info(object player) {
    object env = environment(player);
    if (!env || !has_gmcp(player)) return;

    mapping data = ([
        "name": env->query("short"),
        "description": env->query("long"),
        "exits": keys(env->query("exits")),
        "items": keys(env->query("items") || ([]))
    ]);

    player->send_gmcp("Room.Info " + json_encode(data));
}

// 接收客户端GMCP请求
void gmcp(string message) {
    string cmd, data;

    if (sscanf(message, "%s %s", cmd, data) != 2) {
        cmd = message;
        data = "";
    }

    switch (cmd) {
        case "Core.Hello":
            write("欢迎!GMCP已连接。\n");
            send_initial_data();
            break;
        case "Char.Request":
            send_character_status();
            break;
        case "Room.Request":
            send_room_info(this_player());
            break;
    }
}

MSSP (Mud Server Status Protocol)

协议代码: 70 (0x46)

功能描述: 服务器状态广播协议,用于MUD列表网站获取服务器信息

相关APPLY:

  • mapping get_mud_stats() - 返回服务器统计信息

官方MSSP变量规范:

必需字段:

  • NAME - MUD名称
  • PLAYERS - 当前在线玩家数
  • UPTIME - MUD启动的Unix时间戳

通用字段:

  • CHARSET - 字符集
  • CODEBASE - 代码库版本
  • CONTACT - 联系邮箱
  • CRAWL_DELAY - 爬虫延迟时间
  • CREATED - 创建时间
  • DISCORD - Discord链接
  • HOSTNAME - 主机名
  • ICON - 图标URL
  • IP - IP地址
  • IPV6 - IPv6地址
  • LANGUAGE - 语言
  • LOCATION - 地理位置
  • MINIMUM_AGE - 最小年龄限制
  • PORT - 端口号
  • REFERRAL - 推荐链接
  • SSL - SSL端口
  • WEBSITE - 网站地址

分类字段:

  • FAMILY - 系列(如:DikuMUD, LPMud, MOO等)
  • GENRE - 类型(如:Fantasy, Sci-Fi, Historical等)
  • GAMEPLAY - 游戏性(如:Adventure, Hack and Slash, Player versus Player等)
  • STATUS - 状态(如:Alpha, Beta, Live)
  • GAMESYSTEM - 游戏系统
  • INTERMUD - 互联MUD协议
  • SUBGENRE - 子类型

世界数据字段:

  • AREAS - 区域数量
  • HELPFILES - 帮助文件数量
  • MOBILES - NPC数量
  • OBJECTS - 物品数量
  • ROOMS - 房间数量
  • CLASSES - 职业数量
  • LEVELS - 等级上限
  • RACES - 种族数量
  • SKILLS - 技能数量

协议支持字段:

  • ANSI - ANSI颜色支持
  • UTF-8 - UTF-8编码支持
  • VT100 - VT100终端支持
  • XTERM_256_COLORS - XTERM 256色支持
  • XTERM_TRUE_COLORS - XTERM真彩色支持

完整示例:

// 在master.c中实现 - 严格遵循官方MSSP规范
mapping get_mud_stats() {
    return ([
        // 必需字段
        "NAME": "炎黄群侠传",
        "PLAYERS": sprintf("%d", sizeof(users())),
        "UPTIME": sprintf("%d", uptime()),

        // 通用字段
        "CHARSET": "UTF-8",
        "CODEBASE": "FluffOS " + __VERSION__,
        "CONTACT": "admin@mud.ren",
        "CREATED": "2020-01-01",
        "HOSTNAME": "mud.ren",
        "IP": "123.456.789.012",
        "LANGUAGE": "Chinese",
        "LOCATION": "China",
        "MINIMUM_AGE": "16",
        "PORT": "4000",
        "WEBSITE": "https://mud.ren",

        // 分类字段
        "FAMILY": "LPMud",
        "GENRE": "Fantasy",
        "GAMEPLAY": "Roleplaying",
        "STATUS": "Live",

        // 世界数据字段
        "AREAS": "100",
        "HELPFILES": "500",
        "MOBILES": "2000",
        "OBJECTS": "10000",
        "ROOMS": "3000",
        "CLASSES": "8",
        "LEVELS": "100",
        "RACES": "5",
        "SKILLS": "200",

        // 协议支持字段
        "ANSI": "1",
        "UTF-8": "1",
        "VT100": "1",
        "XTERM_256_COLORS": "1"
    ]);
}

MSP (Mud Sound Protocol)

协议代码: 90 (0x5A)

功能描述: 音效和背景音乐播放协议,支持音量、循环等控制

相关EFUNs:

  • int has_msp(object ob) - 检查玩家是否启用MSP
  • void telnet_msp_oob(string command) - 发送MSP命令

协议格式规范: MSP命令使用以下格式:

!!TYPE(filename V=音量 L=循环 P=优先级 C=继续 T=类型 U=URL)
参数详解: 参数 适用类型 取值范围 默认值 说明
filename SOUND/MUSIC 字符串 - 音频文件路径,支持通配符,"Off"停止播放
V (Volume) SOUND/MUSIC 0-100 100 音量控制,0静音,100最大音量
L (Loops) SOUND/MUSIC -1, 正整数 1 循环次数,-1表示无限循环
P (Priority) SOUND 0-100 50 优先级,数值高的音效会覆盖低优先级的
C (Continue) MUSIC 0/1 1 是否继续播放,0停止当前音乐,1继续
T (Type) SOUND/MUSIC 字符串 - 音频类型标识,区分不同类别的音效
U (URL) SOUND/MUSIC URL字符串 - 音频文件下载地址,可设置默认URL

标准命令格式:

  • 音效: !!SOUND(filename V=0-100 L=1/-1 P=0-100 T=type U=url)
  • 音乐: !!MUSIC(filename V=0-100 L=1/-1 C=0/1 T=type U=url)
  • 停止: !!SOUND(Off)!!MUSIC(Off)

完整示例:

// 播放音效
void play_sound(object player, string sound_file, int volume, int priority) {
    if (has_msp(player)) {
        player->telnet_msp_oob(sprintf("!!SOUND(%s V=%d L=1 P=%d)\r\n", 
            sound_file, volume, priority));
    }
}

// 播放背景音乐
void play_music(object player, string music_file, int volume, int loops) {
    if (has_msp(player)) {
        player->telnet_msp_oob(sprintf("!!MUSIC(%s V=%d L=%d C=1)\r\n", 
            music_file, volume, loops));
    }
}

// 停止音乐
void stop_music(object player) {
    if (has_msp(player)) {
        player->telnet_msp_oob("!!MUSIC(Off)\r\n");
    }
}

// 高级音效系统示例
void play_ambient_sound(object player, string sound_type) {
    mapping ambient_sounds = ([
        "forest": "ambient/forest.wav",
        "cave": "ambient/cave.wav", 
        "village": "ambient/village.wav",
        "combat": "ambient/battle.wav"
    ]);

    string sound_file = ambient_sounds[sound_type];
    if (sound_file && has_msp(player)) {
        // 环境音效:低音量,无限循环,低优先级
        player->telnet_msp_oob(sprintf("!!MUSIC(%s V=30 L=-1 C=1)\r\n", sound_file));
    }
}

// 战斗音效系统
void combat_sound(object attacker, object target, string action) {
    mapping sounds = ([
        "hit": "combat/sword_hit.wav",
        "miss": "combat/sword_miss.wav", 
        "dodge": "combat/dodge.wav",
        "block": "combat/block.wav",
        "critical": "combat/critical.wav"
    ]);

    string sound_file = sounds[action];
    if (sound_file && has_msp(attacker)) {
        // 战斗音效:高音量,单次播放,高优先级
        play_sound(attacker, sound_file, 90, 80);
    }
    if (sound_file && has_msp(target)) {
        play_sound(target, sound_file, 90, 80);
    }
}

// 设置默认音频URL
void set_default_audio_url(object player, string url) {
    if (has_msp(player)) {
        player->telnet_msp_oob(sprintf("!!SOUND(Off U=%s)\r\n", url));
    }
}

MXP (Mud eXtension Protocol)

协议代码: 91 (0x5B)

功能描述: 富文本标记协议,支持颜色、链接、图片等HTML/XML样式标记

相关EFUNs:

  • int has_mxp(object ob) - 检查玩家是否启用MXP
  • void act_mxp() - 激活MXP模式

相关APPLYs:

  • void mxp_enable() - MXP启用时调用
  • string mxp_tag(string tag) - 处理MXP标签时调用

完整示例:

// 发送颜色文本
void send_colored_text(object player, string text, string color) {
    if (has_mxp(player)) {
        tell_object(player, sprintf("<COLOR %s>%s</COLOR>", color, text));
    } else {
        tell_object(player, text);
    }
}

// 创建可点击链接
void send_link(object player, string text, string command) {
    if (has_mxp(player)) {
        tell_object(player, sprintf("<A HREF=\"%s\">%s</A>", command, text));
    } else {
        tell_object(player, sprintf("%s (%s)", text, command));
    }
}

// 发送图片
void send_image(object player, string image_url, string alt_text) {
    if (has_mxp(player)) {
        tell_object(player, sprintf("<IMG SRC=\"%s\" ALT=\"%s\">", image_url, alt_text));
    } else {
        tell_object(player, alt_text);
    }
}

// 房间描述增强
void send_enhanced_room_desc(object player, object room) {
    string desc = room->query("long");

    if (has_mxp(player)) {
        // 高亮出口
        mapping exits = room->query("exits");
        string *exit_dirs = keys(exits);

        foreach (string dir in exit_dirs) {
            desc = replace_string(desc, dir, 
                sprintf("<A HREF=\"go %s\"><COLOR GREEN>%s</COLOR></A>", dir, dir));
        }

        // 高亮物品
        object *items = all_inventory(room);
        foreach (object item in items) {
            string item_name = item->query("name");
            if (item_name && strsrch(desc, item_name) != -1) {
                desc = replace_string(desc, item_name,
                    sprintf("<A HREF=\"look %s\"><COLOR CYAN>%s</COLOR></A>", 
                        item_name, item_name));
            }
        }
    }

    tell_object(player, desc);
}

MSDP (Mud Server Data Protocol)

协议代码: 69 (0x45)

功能描述: 键值对数据交换协议,是GMCP的前身,用于角色状态、游戏数据等传输

相关EFUNs:

  • int has_msdp(object ob) - 检查玩家是否启用MSDP
  • void send_msdp_variable(string variable, mixed value) - 发送MSDP变量

相关APPLYs:

  • void msdp_enable() - MSDP启用时调用
  • void msdp(string message) - 收到MSDP数据时调用

完整示例:

// 发送角色属性
void send_character_stats(object player) {
    if (has_msdp(player)) {
        player->send_msdp_variable("HEALTH", player->query("hp"));
        player->send_msdp_variable("HEALTH_MAX", player->query("max_hp"));
        player->send_msdp_variable("MANA", player->query("mp"));
        player->send_msdp_variable("MANA_MAX", player->query("max_mp"));
        player->send_msdp_variable("LEVEL", player->query("level"));
        player->send_msdp_variable("EXPERIENCE", player->query("exp"));
    }
}

// 发送房间信息
void send_room_data(object player) {
    object env = environment(player);
    if (!env || !has_msdp(player)) return;

    player->send_msdp_variable("ROOM_NAME", env->query("short"));
    player->send_msdp_variable("ROOM_DESCRIPTION", env->query("long"));
    player->send_msdp_variable("ROOM_EXITS", implode(keys(env->query("exits")), ","));

    object *items = all_inventory(env) - ({player});
    string *item_names = map_array(items, (: $1->query("short") :));
    player->send_msdp_variable("ROOM_ITEMS", implode(item_names, ","));
}

// 处理客户端MSDP请求
void msdp(string message) {
    string variable, value;

    if (sscanf(message, "%s %s", variable, value) != 2) {
        variable = message;
        value = "";
    }

    switch (variable) {
        case "REPORT":
            send_character_stats(this_player());
            break;
        case "ROOM":
            send_room_data(this_player());
            break;
    }
}

ZMP (Zenith Mud Protocol)

协议代码: 93 (0x5D)

功能描述: 插件系统协议,允许客户端调用服务器端插件功能

相关EFUNs:

  • int has_zmp(object ob) - 检查玩家是否启用ZMP
  • void send_zmp(string module, string *args) - 发送ZMP命令

相关APPLYs:

  • void zmp_enable() - ZMP启用时调用
  • void zmp_command(string module, string *args) - 收到ZMP命令时调用

完整示例:

// 注册ZMP模块
void zmp_enable() {
    // 通知客户端支持的模块
    send_zmp("core", ({"hello", "1.0"}));
    send_zmp("mapper", ({"init", "1.0"}));
    send_zmp("inventory", ({"init", "1.0"}));
}

// 处理ZMP命令
void zmp_command(string module, string *args) {
    switch (module) {
        case "mapper":
            handle_mapper_command(args);
            break;
        case "inventory":
            handle_inventory_command(args);
            break;
        case "combat":
            handle_combat_command(args);
            break;
    }
}

// 地图插件
void handle_mapper_command(string *args) {
    switch (args[0]) {
        case "get_map":
            send_map_data();
            break;
        case "get_room":
            send_room_info();
            break;
    }
}

void send_map_data() {
    object env = environment(this_player());
    if (!env) return;

    mapping exits = env->query("exits");
    string *exit_data = ({ environment(env)->query("short") });

    foreach (string dir, string dest in exits) {
        exit_data += ({ dir, dest });
    }

    send_zmp("mapper", ({"map_data"}) + exit_data);
}

// 背包插件
void handle_inventory_command(string *args) {
    object *inv = all_inventory(this_player());
    string *items = map_array(inv, (: $1->query("short") :));

    send_zmp("inventory", ({"items"}) + items);
}

// 战斗插件
void handle_combat_command(string *args) {
    switch (args[0]) {
        case "status":
            send_combat_status();
            break;
        case "attack":
            this_player()->force_me("attack " + args[1]);
            break;
    }
}

现代MUD推荐配置

配置原则

现代MUD开发采用"GMCP优先"策略,保持与旧客户端的兼容性

完整配置示例

# config.mud
# 现代MUD标准配置
enable gmcp : 1    # 现代数据交换协议(主力协议)
enable mssp : 1    # 服务器列表必需协议
enable msp : 1     # 音效支持(有音频资源时开启)

# 兼容性配置(根据需求开启)
enable mxp : 0     # 富文本标记(现代Web客户端可替代)
enable zmp : 0     # 插件系统(GMCP可替代)
enable msdp : 0    # 键值对数据(GMCP可替代)

现代项目建议

  • 新项目: 仅启用GMCP + MSSP (+ MSP如有音效)
  • 现有项目: 逐步迁移MSDP/ZMP/MXP功能到GMCP
  • 兼容性: 保持旧协议支持直到用户完成迁移

协议对比与迁移

功能对照表

功能需求 传统协议 GMCP实现 迁移优势
角色状态 MSDP: HEALTH=100 {"hp":100,"max_hp":150} 结构化数据
房间描述 MXP: <color red>房间名 {"name":"房间名","color":"red"} 客户端渲染
地图插件 ZMP: mapper.show {"module":"Map","action":"show"} JSON格式
物品列表 MSDP: ITEMS=sword,shield {"items":[{"name":"剑"}]} 数组支持
战斗状态 MSDP: IN_COMBAT=1 {"combat":{"active":true,"target":"敌人"}} 复杂数据

完整迁移示例

// MSDP到GMCP迁移
// 旧版MSDP
void send_stats_old() {
    send_msdp_variable("HEALTH", this_player()->query("hp"));
    send_msdp_variable("MANA", this_player()->query("mp"));
}

// 新版GMCP
void send_stats_new() {
    mapping data = ([
        "health": this_player()->query("hp"),
        "mana": this_player()->query("mp"),
        "max_health": this_player()->query("max_hp"),
        "max_mana": this_player()->query("max_mp")
    ]);
    send_gmcp("Char.Vitals " + json_encode(data));
}

重要参考资源

协议规范文档

现代MUD开发原则

现代配置 = GMCP(1) + MSSP(1) + MSP(可选)

  • GMCP: 承担所有数据交换功能
  • MSSP: 保持服务器列表兼容性
  • MSP: 音效支持(有音频资源时启用)
  • 其他协议: 保持兼容性,逐步迁移到GMCP

提示:MSP协议也是完全可以用GMCP协议代替的,参考:A Standard for Loading, Playing and Stopping Media Files with MUD Clients over GMCP

京ICP备13031296号-4