MUDLIST 游戏列表互联功能的实现:DNS_MASTER

在开启了互联的MUD游戏中,使用 mudlist all 可以看到其它游戏列表,使用 ic xxx 可以和其它MUD聊天,这些功能就是基础的MUD互联。 file MUD互联的核心是socket通信,通信协议是UDP,如果你对socket基础还没有掌握,请先看基础教程中的socket 介绍及游戏开发实战

目前国内主流MUD中的互联标准都是源自东方故事2 MUD的DNS_MASTER,功能实现基本包括以下几个部分:

  1. DNS_MASTER 守护进程:创建socket服务并实现MUD互联
  2. PING 服务模块:包括ping_q和ping_a,实现游戏基本信息的请求与发送
  3. MUDLIST 服务模块:包括mudlist_q和mudlist_a,实现游戏列表的请求与发送
  4. GCHANNEL 服务模块:处理互联MUD聊天消息

这些文件全部在/adm/daemons/network目录下,服务模块在/adm/daemons/network/services目录下,除了以上文件,还有remote_q.c、remote_a.c、rwho_q.c、rwho_a.c等是额外提供功能的服务模块,这里不做说明。

MUD互联不需要你和所有的游戏一个个的联,只需要和几个站点互联就够,这几个站点就像当于DNS节点服务器,所有和节点MUD连接的都会被收录,同时你也可以从节点服务器获取已和这个节点连接的MUD列表实现和其它MUD互联。节点服务器配置一般是在/adm/etc/config这个文件中,如:

# 和本系统相联系的MUD服务器(端口為PORTUDP)
mudlist1 : 118.190.104.241 5556     #炎黄群侠传
mudlist2 : 43.252.229.138 4004      #異想世界
mudlist3 : 210.59.236.38 4004       #重生的世界
# mudlist4 : 118.190.104.241 5556   #mud.ren
# mudlist5 : 118.190.104.241 5556   #mud.ren

也有的MUD是配置在/include/net/config.h文件中,如:

#define LISTNODES ([ \
"revival world"                 :       "210.59.236.38 4004", \
"Time Space Dreamland"          :      "60.249.26.195 4004", \
"illusory.of.time"              :       "220.134.153.8 7004", \
"The Dream Of Seven"            :       "140.134.36.89 7004",\
"Mud.ren"                       :       "118.190.104.241 5556",\
])

注意配置的端口不是游戏端口,而是socket连接的udp端口,这个一般默认是游戏端口+4,比如游戏端口是5555,DNS_MASTER会自动用5559为端口创建socket服务。当然并不是所有MUD都默认是+4端口,也有+2或+1的,炎黄群侠传因为开发需求设置的是+1,即互联端口是5556。

DNS_MASTER 守护进程

如果你需要自动互联,需要把DNS_MASTER放到preload中自动启动,当DNS_MASTER启动后,会进入以下流程:

  1. startup_udp() 启动当前MUD的UDP服务以准备和其它MUD互联,默认以游戏端口+4为socket通信端口
  2. init_database() 初始化mudlist数据库并向节点MUD发送mudlist_q请求
  3. 向指定的DNS节点发送ping_a请求,把自己站点的资料发送给节点MUD,同时发送ping_q请求获取对应节点站点信息
  4. 向指定的DNS节点发送mudlist_q请求,获取节点的mudlist列表,并使用mudlist_a服务处理获取的mudlist
  5. 通过refresh_database()定期向节点发送mudlist_q请求更新mudlist列表
  6. 通过do_pings()定期向互联的mudlist发送ping_q请求更新互联MUD的资料

当你启动DNS_MASTER守护进程后,你的MUD服务器也成为一个节点,别的MUD也可以向你的MUD发送互联请求。

为了保障各个MUD互联的消息能正确识别,在消息格式有基本的规范,基本格式为@@@func||msg@@@,以下为示例:

// startup
@@@startup||MUDNAME:中华英雄||NAME:CHINA||VERSION:CHINA 3.1||MUDLIB:CHINA||HOST:AY130524203511Z||PORT:5000||PORTUDP:5004||TIME:Sat Jul 24 13:20:25 2021||USERS:136||TCP:all||UPTIME:3028232@@@
// ping_q
@@@ping_q||NAME:Revival World||PORTUDP:4004@@@
// ping_a
@@@ping_a||MUDNAME:異想世界||NAME:Break World||VERSION:異想世界 1.0||DRIVER:fluffos v2019.20210429-38-gece2acf3||MUDLIB:異想世界||LOCATION:Taiwan||HOST:cloudserver||PORT:4000||PORTUDP:4004||TIME:Sat Jul 24 13:40:14 2021||ENCODING:BIG5||MUDGROUP:台灣泥巴聯盟||USERS:46||TCP:all@@@
// mudlist_q
@@@mudlist_q||NAME:CHINA||PORTUDP:5004@@@
// mudlist_a
@@@mudlist_a||12:|NAME:Revival World|HOST:mud.revivalworld.org|HOSTADDRESS:210.59.236.38|PORT:4000|PORTUDP:4004@@@
@@@mudlist_a||9:|NAME:XKX|HOST:AY1307281039526545e1Z|HOSTADDRESS:112.124.8.59|PORT:5678|PORTUDP:5682|MUDLIB:XiaKeXing||10:|NAME:Revival World|HOST:mud.revivalworld.org|HOSTADDRESS:210.59.236.38|PORT:4000|PORTUDP:4004|MUDLIB:Revival World||11:|NAME:Bastard|HOST:mud.hu|HOSTADDRESS:91.205.173.162|PORT:2222|PORTUDP:2230|MUDLIB:Bastard@@@
@@@mudlist_a||15:|NAME:Lonely World|HOST:muds.cn|HOSTADDRESS:122.227.23.184|PORT:3000|PORTUDP:3004|MUDLIB:Lonely World||16:|NAME:DarkeFOStest|HOST:darke.triciroc.com|HOSTADDRESS:206.212.236.197|PORT:5259|PORTUDP:5267|MUDLIB:DarkeLIB||17:|NAME:ElveszettVilag|HOST:dezso|HOSTADDRESS:78.131.8.19|PORT:6666|PORTUDP:6674|MUDLIB:Elveszett Vilag Mudlib@@@
// gchannel
@@@gchannel||NAME:YHMUD||PORTUDP:5556||USRNAME:Mudren||CNAME:小泥人||MSG:hi||CHANNEL:ic@@@

指定的func主要是ping_qping_amudlist_qmudlist_a,而startup作用和ping_a一样,在intermud2等互联中优化掉了。而消息体msg内容在不同请求下不同,但所有消息必须有PORTUDP说明自己MUD的互联端口,否则对方MUD可能无法正常的响应请求。

在DNS_MASTER文件中使用void send_udp(string host, int port, mixed msg)向互联MUD发送消息,使用void read_callback(int sock, mixed msg, string addr)处理收到的消息。当收到XXX_q消息请求时,需要使用XXX_a来做应答处理。

PING_Q 和 PING_A 服务

当DNS_MASTER的void read_callback(int sock, mixed msg, string addr)函数收到类似 @@@ping_q||NAME:Revival World||PORTUDP:4004@@@这样的msg时,会调用ping_q服务的void incoming_request(mapping info)方法处理,在这个方法中使用DNS_MASTER的void send_udp(string host, int port, mixed msg)方法回复一个@@ping_a||......的消息,在消息中包括MUD的基本消息。

而DNS_MASTER收到ping_a消息后会调用ping_a服务的void incoming_request(mapping info)方法处理,在这个方法中判断后调用 DNS_MASTER的void set_mud_info(string name, mapping minfo)把获取的MUD资料加到mud列表中。

MUDLIST_A 和 MUDLIST_Q 服务

DNS_MASTER会定期调用mudlist_q服务的void send_mudlist_q(string host, string port)方法向节点发送@@@mudlist_q||NAME:CHINA||PORTUDP:5004@@@请求更新mudlist。节点的DNS_MASTER收到mudlist_q消息后会调用mudlist_q服务的void incoming_request(mapping info)方法,在这个方法中使用DNS_MASTER的void send_udp(string host, int port, mixed msg)方法回复@@mudlist_a||......的消息,在消息中包括节点中的mudlist。

当DNS_MASTER的read_callback收到类似@@@mudlist_a||...@@@消息后,会调用mudlist_a服务的void incoming_request(mapping info)方法处理,在这个方法中判断后调用 DNS_MASTER的void set_mud_info(string name, mapping minfo)把获取的MUD资料加到mud列表中。

GCHANNEL 服务

在CHANNEL_D聊天守护进程中可以调用gchannel服务的void send_msg(string channel, string id, string name, string msg, int emoted, mixed filter)发送网际消息,消息格式类似@@@gchannel||NAME:YHMUD||PORTUDP:5556||USRNAME:Mudren||CNAME:小泥人||MSG:hi||CHANNEL:ic@@@

当DNS_MASTER的read_callback收到gchannel消息后,会调用gchannel服务的void incoming_request(mapping info)方法处理,并通过CHANNEL_D聊天守护进程发送给玩家。

除了国内MUD使用的DNS_MASTER,还有intermud-2(i2d)和Intermud-3,i2d是对DNS_MASTER的优化和简化,具体代码可参考mudcore框架中的CORE_INTERMUD_D,而关于Intermud-3主要是国外MUD使用的互联标准,资料可参考:http://lpmuds.net/intermud.html

京ICP备13031296号-4