Pymud
a MUD client written in Python
Install / Use
/learn @crapex/PymudREADME
English Version [中文版本]
PyMUD - Python原生MUD客户端
简介
- 官方网站: https://www.pymud.cn
- 官方文档: https://www.pymud.cn/doc
- 官方论坛: https://bbs.pymud.cn
- 源代码地址: https://github.com/crapex/pymud
- PyPi项目地址: https://pypi.org/project/pymud
- 由deepwiki自动生成的项目理解文档地址: https://deepwiki.com/crapex/pymud
- PyMUD用户shanghua写的入门教程文档:https://www.pkuxkx.net/forum/forum.php?mod=viewthread&tid=49999&forumuid=12067
- 交流QQ群:554672580
北大侠客行Mud (www.pkuxkx.net),最好的中文Mud游戏!
PyMUD是我为了更好的玩北大侠客行,特意自行开发的MUD客户端。PyMUD具有以下特点:
- 原生Python开发,除
prompt-toolkit <https://python-prompt-toolkit.readthedocs.io>及其依赖库 wcwidth, pygment, pyperclip 外,不需要其他第三方库支持 - 原生Python的asyncio实现的通信协议处理,支持async/await语法在脚本中直接应用,脚本实现的同步异步两种模式由你自己选择
- 基于控制台的全屏UI界面设计,支持鼠标操作(Android上支持触摸屏操作),极低资源需求,在单核1GB内存的Linux VPS上也可流畅运行
- 支持分屏显示,在数据快速滚动的时候,上半屏保持不动,以确保不错过信息
- 解决了99%情况下,北大侠客行中文对不齐,也就是看不清字符画的问题
- 真正的支持多session会话,支持命令或鼠标切换会话
- 原生支持多种服务器端编码方式,不论是GBK、BIG5、还是UTF-8
- 支持NWAS、MTTS协商,支持GMCP、MSDP、MSSP协议
- 一次脚本开发,多平台运行。只要能在该平台上运行python,就可以运行PyMUD客户端
- 脚本所有语法均采用Python原生语法,因此你只要会用Python,就可以自己写脚本,免去了再去学习lua、熟悉各类APP的使用的难处
- 全开源代码,因此脚本也可以很方便的使用visual studio code等工具进行调试,可以设置断点、查看变量等
- Python拥有极为强大的文字处理能力,用于处理文本的MUD最为合适
- Python拥有极为丰富的第三方库,能支持的第三方库,就能在PyMUD中支持
- 多语言支持框架已搭好,目前提供中文、英文支持,可以自己增加翻译后的其他语言版本
- 为北侠版提供了基于web的网页客户端界面插件,界面上可以直接操作角色,直接多端同步显示数据、状态,fullme图片(见QQ群文件)。
- 我自己还在玩,所以本客户端会持续进行更新:)
哪些人适合使用PyMUD
- 比较熟悉Python语言,会使用Python写代码的 -> PyMUD是纯Python原生开发,不会有其他客户端对Python的支持能比得过PyMUD
- 虽不太熟悉Python语言,但有想法想学习Python语言的 -> 正好使用PyMUD玩北侠写脚本的过程中学习Python语言
- 觉得还有些功能现在所有客户端都没有的 -> 你有需求,我来增加,就是这么方便
- 觉得也想自己整一个定制客户端玩玩的 -> PyMUD完全开源,且除ui框架外全部都是一行一行代码自己写的,可以直接参考PyMUD的设计
版本更新信息
0.22.1a2 测试版 (2026-01-03)
- 功能新增: 可以通过.cfg文件指定 "auto_chars" 来定义启动pymud时自动打开的会话。
- 问题修复: 修复GMCPTrigger类型enabled属性不生效问题。
- 问题修复: 修复添加/删除系统时钟回调时,可能会导致的异常问题。
- 问题修复: 修复在增加系统时钟回调时,如果回调函数代码错误产生异常,会导致系统时钟停顿的问题。
0.22.1 (2025-09-01)
- 问题修复: 修复脚本错误的异常提示问题。
0.22.0 (2025-08-23)
- 问题修复: beautify 对齐恢复成以往的实现方式,即统一在右侧添加字符。
- 问题修复: 修复了 #var 命令中,使用中文变量名时,= 显示不对齐的问题。
- 问题修复: 修复了当使用多重继承创建脚本,同时继承 Command 和 IConfig 时,装饰器无法使用的问题。现在仅需一次 super() 调用即可解决。
- 问题修复: 修复了使用unload/reload时,有时候不显示卸载成功的问题。现在可以正常的报出卸载中的错误了。
- 问题修复: 现在可以正常的使用 remain_last_input 配置保留命令行输入了(感谢 @cantus 提供的代码)。
- 功能新增: client 新增配置 split_ratio,用于设置分屏比例。默认值为0.5,即上下分屏比例为50%。另外,可以通过快捷键 Shift + ↑/↓ 来动态调整分屏比例 (感谢 @cantus 提供的代码)。
- 功能新增: 现在上箭头在光标处于最右侧时,也是优先使用自动补完了。若无自动补完,则进行历史命令切换。
- 功能新增: 按键ESC可以直接清除命令行中的全部内容(受限于终端对按键的处理,需要连续按三次ESC按键才能生效)。
- 功能新增: 现在Tab按键也具有自动补完功能了。
- 功能新增: 为IConfigBase接口新增了info, warning, error方法,以后继承 IConfig 的类型,可以直接 self.info 了。
- 功能新增: 现在 @alias, @trigger, @timer, @gmcp, @exception 等装饰器可以直接装饰在async def的异步函数上了。同步的,所有继承自 BaseObject 对象的类型,包括 Trigger, Alias, Timer, GMCPTrigger 等, 其onSuccess, onFailure等回调可以直接赋值为异步函数。
- 功能调整: 移除了顶部菜单栏最右侧阻挡事件响应的空白菜单。原因是有时焦点位于此空白菜单时,单击窗口焦点不能正常移动到命令栏,会造成误解。
- 功能新增: 在 @exception 输出异常信息时,会定位标记了 @exception 并产生异常的函数及所在文件。
- 功能新增: 为 Session 类型新增了一个 wait_triggers 方法,可以简化等待多个触发器的处理代码。
- 弃用预告: 由于 @exception 装饰器可以直接对异步函数使用, @async_exception 装饰器将在下一版本移除。
0.21.8 (2025-08-08)
- 功能新增: 现在可以通过调用 exec 系列函数来调用 #session 命令了。
- 功能新增: 现在 #close 命令可以带参数了。可以使用会话名指定关闭哪个会话,不指定时默认关闭当前会话。可以使用 -f 或 --force 参数强制关闭会话,此时即使会话连接状态,也不弹出确认对话框。
0.21.7 (2025-08-02)
- 问题修复: 删除了插件加载的冗余错误代码。
- 问题修复: 修复了插件加载报错时的错误提示语句不显示的问题。
- 功能新增: 针对应用退出时的资源释放和清理进行了完善,确保插件中申请的资源可以正常卸载。
- 功能新增: 可以通过pymud.cfg在client字段中的cursor字段来设置光标形状。支持的光标包括: UNDERLINE, BEAM, BLOCK, BLINKING_BLOCK, BLINKING_UNDERLINE, BLINKING_BEAM。默认为闪烁竖线 BLINKING_BEAM。
0.21.6 (2025-06-29)
- 问题修复: 修复了连接报错时,异常信息不显示的问题。
- 问题修复: 修复了在脚本中发生同步触发器运行异常时,连接会中断的问题。
- 问题修复: 修复了在初始化时,默认会指定当前目录为脚本目录而不能接受用户如数的问题。
- 功能调整: 在初始化时,原先会根据检测到的系统语言进行语言选择,现增加了人工确认环节,可以手动切换。
- 功能调整: 颜色校正追溯调整为更多行,解决当打印异常追踪行数过多时,红色背景会中断恢复的情况。
- 功能新增: #var命令现在支持查询仅知道开头或者结尾的变量。例如,使用 #var abc* 会仅打印所有以 abc 开头的变量,使用 #var *abc 会仅打印所有以 abc 结尾的变量。
- 问题修复: 修复了个别函数中,部分执行路径无返回值的问题。
0.21.5post2 (2025-06-10)
- 功能完善: 完善了美化功能,已知情况下,基本不会出现断行和不对齐问题了。
- 功能完善: 在向服务器送出单个回车命令后,本地显示也强制换行。在出现『未完待续』情况时,回车后不会再跟在后面显示了,而是会强制从下一行开始。
- 功能完善: 当对行进行双击选择时,背景增加的选择标记(灰色)会按照实际显示的宽度进行匹配,而不是按照原始数据的宽度进行匹配。
0.21.4 (2025-06-08)
- 问题修复: 修复了在多行选择碰到空行时,会导致从头开始全选的问题。
- 问题修复: 修复了从后往前选择时,若再往后选择,会导致起始位置错误的问题。
- 问题修复: 修复了纯文本行单行部分复制时,最后一个字符无法被选中和复制的问题。
- 问题修复: 修复了美化模式下,当服务器使用tab对齐在本地显示中无法对齐的问题。为配合对齐,默认tabstop已修改为8。
- 功能调整: 当上下分屏显示时,上半屏也能显示到最后一行,而不是仅显示到分屏处位置。
0.21.3 (2025-06-02)
- 问题修复: 修复了当缓存行数超过规定值时,由于代码错误导致清屏的问题。
- 功能增强: 增加清除任务时的异常保护,此时产生asyncio.CancelledError异常为正常现象,因此捕获后禁止异常处理。
- 功能增强: 对reset进行了异常提示保护,此时产生异常(大部分为asyncio.CancelledError)为正常现象,因此捕获后禁止异常处理。
0.21.2 (2025-06-01)
- 问题修复: 修复了当自动重连启动时,即使会话关闭了,也会自动重连的问题。
- 实现调整: 重写了专用的会话缓冲、记录缓冲与PyMUD缓冲显示控制器,在prompt_toolkit的原Buffer和BufferControl的基础仅提供了PyMUD所需的基础功能,以降低内存占用。 经测试,当前内存基本稳定,视会话数量和脚本情况差异,维持在几百兆左右(500M以下),且不会有大幅波动。重写后,低配置的VPS也可以稳定运行PyMUD。
0.21.0 (2025-05-20)
-
功能新增: 各类对象的group属性,新增组、子组概念,用于快速成组操作对象。组可以包括子组,子组可以再包括子组。 组名以点号.分隔,例如:group1.subgroup1.subsubgroup1。组的层级没有限制。 组的概念可以用于快速处理多个对象,例如启用/禁用一组对象、删除一组对象等。例如,以下几个组的关系:
- mygroup1
- mygroup1.subgroup1 # 属于 mygroup1的子组
- mygroup1.subgroup2 # 属于 mygroup1的子组
- mygroup1.subgroup2.subsubgroup1 # 属于 mygroup1.subgroup2的子组,也同样属于更高层级mygroup1的子组
- mygroup2
- mygroup2.subgroup1 # 属于 mygroup2的子组
-
功能新增: 新增了deleteGroup函数,用于删除指定的对象组。可同时指定组名、是否包含子组名、有效类型范围。函数定义和示例代码如下:
def deleteGroup(self, group: str, subgroup = True, types: Union[Type, Union[Tuple, List]] = (Alias, Trigger, Command, Timer, GMCPTrigger)): pass # 各参数含义: # group: 要删除的组名,可以是完整的组名,也可以是部分组名。例如:"group1" 或 "group1.subgroup1" 等。 # subgroup: 是否包含子组。如果为True,则删除指定组及其所有子组的对象。如果为False,则仅删除指定组的对象,不包括子组。 # types: 要删除的对象类型范围。可以是单个类型,也可以是类型的元组或列表。例如:Trigger, Alias, Command, Timer, GMCPTrigger 等。 # 示例代码: # 删除所有属于group1的Trigger和Alias对象,包括子组如 group1.subgroup1 和 group1.subgroup2 等 self.session.deleteGroup("group1", True, [Trigger, Alias]) # 删除所有属于group1的Trigger对象,但不包括子组 self.session.deleteGroup("group1", False, [Trigger]) -
功能新增: 对 #trigger, #alias, #timer, #gmcp, #command, #t+, #t- 等命令新增了组处理选项,用于对整组对象进行处理。各命令的语法格式类似。 处理组时,组名应以大于号>或者等于号=开头,紧跟组名(无空格)。当使用>时,表示操作针对当前组及所有所属子组,当使用=时,表示操作仅针对当前组。 例如下面代码:
#t+ >group1 表示启用所有属于group1以及其子组的所有可管理对象,包括Trigger、Alias、Command、Timer、GMCPTrigger #t- =group1.subgroup1 表示禁用所有仅属于group1.subgroup1的Trigger、Alias、Command、Timer、GMCPTrigger等对象 #tri >group1 off 表示禁用所有属于group1以及其子组的Trigger对象 #ali =group1.subgroup1 on 表示启用所有仅属于group1.subgroup1的Alias对象 -
功能新增: 调整了enableGroup处理,可以通过组名支持子组操作,也可以指定有效类型范围。例如下面代码:
class MyTestConfig(IConfig): def __init__(self, session, *args, **kwargs): self._objs = [ Trigger(session, "tri1", group = "group1"), Trigger(session, "tri2", group = "group1.subgroup1"), Trigger(session, "tri3", group = "group1.subgroup2"), Alias(session, "alias1", group = "group1"), Alias(session, "alias2", group = "group1.subgroup1"), Timer(session, 5, group = "group1.subgroup1") ] #以下调用可以同时禁用上述6个对象,因为 group1.subgroup1 和 group1.subgroup2 都属于 group1 的子组 session.enableGroup("group1", False) #以下调用可以同时仅启用触发器tri1和别名alias1,因为通过subgroup参数限定了不传递到子组 session.enableGroup("group1", True, subgroup = False) # 以下调用可以同时禁用对应发器和别名,但不禁用定时器,因为通过types参数指定了有效范围: session.enableGroup("group1.subgroup1", False, types = [Trigger, Alias]) -
功能新增: 增加了多处异常追踪提示。在模块或插件的脚本中发生错误时,均会打印错误追踪信息,方便定位错误。
-
功能新增: 新增 #echo 命令,类似于 #test 命令,但该命令只会模拟收到服务器数据,直接激发各匹配触发器,但不显示触发测试结果。
-
功能新增: #load / #unload 现在支持当前会话对插件的临时启用和禁用,实现方式为调用插件里的PLUGIN_SESSION_CREATE和PLUGIN_SESSION_DESTROYE函数。群文件的moving.py插件写法可以支持。
-
功能调整: 各会话变量保存的.mud文件,统一移到save子目录下。原来当前目录下的.mud文件,在对应会话重新加载时会自动移动,无需人工处理。
-
功能新增: 增加了国际化(i18n)支持,原生开发语言为中文简体,目前使用AI翻译生成了英文。应用语言通过Settings中新增的language配置来控制,默认为"chs",可以在pymud.cfg中覆盖该配置。其值目前可以为"chs"、"eng"。自行翻译的语言可以在pymud/lang目录下下新增语言文件,文件名为i18n_加语言代码,例如"i18n_chs.py"表示可以使用"chs"语言,其中使用Python字典方式定义了所有需动态显示的文本内容。
-
功能新增: 新增了使用元类型及装饰器来管理PyMUD对象,包括Alias, Trigger, Timer, GMCPTrigger四种可以使用对应的装饰器,@alias, @trigger, @timer, @gmcp来直接在标记函数上创建。可以参考本版本中的pkuxkx.py文件写法和注意事项。
-
功能新增: 新增了两个装饰器,@exception和@async_exception,用于捕获异常并调用session.error进行显示。@exception用于捕获同步异常,@async_exception用于捕获异步异常。参考如下:
from pymud import Command, Trigger, IConfig, exception, async_exception
class MyCustomCommand(Command, IConfig):
@exception
def a_sync_routine(self, args: list[str]):
# 这里的代码抛出的异常会被self.session.error捕获并显示
something_that_may_raise_an_exception()
@async_exception
async def execute(self, args: list[str]):
# 这里的代码抛出的异常会被self.session.error捕获并显示
await something_that_may_raise_another_exception()
# 上述代码相当于以下代码
class MyCustomCommand(Command, IConfig):
def a_sync_routine(self, args: list[str]):
try:
something_that_may_raise_an_exception()
except Exception as e:
self.session.error(error_msg_of_e)
async def execute(self, args: list[str]):
try:
await something_that_may_raise_another_exception()
except Exception as e:
self.session.error(error_msg_of_e)
- 问题修复: 修复了Alias和Command执行时的优先级判断。之前未进行优先级判断,因此遇到能同时匹配的多个时,不一定优先级高的被触发。现在对Alias和Command进行了优先级判断,优先级高的先触发。
- 问题修复: 修复Alias中的keepEval参数和oneShot参数。keepEval参数支持多个匹配成功的别名同时生效,oneShot参数支持一个匹配成功的别名生效后,后续的匹配不再生效。
- 问题修复: 修复Command中的keepEval参数。以往同时匹配生效的Command会覆盖后续Command和Alias,当前会持续匹配。
- 功能增强: 对几乎所有函数的参数进行了类型标注,增加了类型检查,提高了代码的可读性和可维护性,也便于自行编写脚本时的提示。
- 功能增强: 为Session类型增加了commandHistory属性,用于查询发送到服务器的命令历史。保存的命令历史的数量由pymud.cfg中的client["history_records"]控制,默认为500。当该值为0时,不会保存命令历史。为-1时,会保存所有命令历史。
- 功能调整: #help命令时,增加了上下两行分隔符显示,以便明显区分帮助输出和游戏输出。
- 功能增强: 当
