pymud 0.20.4__tar.gz → 0.21.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. {pymud-0.20.4 → pymud-0.21.0}/PKG-INFO +118 -5
  2. {pymud-0.20.4 → pymud-0.21.0}/README.md +114 -1
  3. {pymud-0.20.4 → pymud-0.21.0}/pyproject.toml +9 -6
  4. pymud-0.21.0/src/pymud/__init__.py +17 -0
  5. pymud-0.21.0/src/pymud/decorators.py +234 -0
  6. {pymud-0.20.4 → pymud-0.21.0}/src/pymud/dialogs.py +37 -31
  7. {pymud-0.20.4 → pymud-0.21.0}/src/pymud/extras.py +7 -135
  8. pymud-0.21.0/src/pymud/i18n.py +63 -0
  9. pymud-0.21.0/src/pymud/lang/i18n_chs.py +227 -0
  10. pymud-0.21.0/src/pymud/lang/i18n_eng.py +851 -0
  11. {pymud-0.20.4 → pymud-0.21.0}/src/pymud/logger.py +9 -4
  12. pymud-0.21.0/src/pymud/main.py +221 -0
  13. {pymud-0.20.4 → pymud-0.21.0}/src/pymud/modules.py +104 -31
  14. {pymud-0.20.4 → pymud-0.21.0}/src/pymud/objects.py +102 -98
  15. pymud-0.21.0/src/pymud/pkuxkx.py +281 -0
  16. {pymud-0.20.4 → pymud-0.21.0}/src/pymud/protocol.py +15 -13
  17. {pymud-0.20.4 → pymud-0.21.0}/src/pymud/pymud.py +80 -75
  18. {pymud-0.20.4 → pymud-0.21.0}/src/pymud/session.py +582 -356
  19. {pymud-0.20.4 → pymud-0.21.0}/src/pymud/settings.py +15 -2
  20. {pymud-0.20.4 → pymud-0.21.0}/src/pymud.egg-info/PKG-INFO +118 -5
  21. {pymud-0.20.4 → pymud-0.21.0}/src/pymud.egg-info/SOURCES.txt +5 -1
  22. {pymud-0.20.4 → pymud-0.21.0}/src/pymud.egg-info/requires.txt +1 -1
  23. pymud-0.20.4/src/pymud/__init__.py +0 -12
  24. pymud-0.20.4/src/pymud/main.py +0 -142
  25. pymud-0.20.4/src/pymud/pkuxkx.py +0 -156
  26. {pymud-0.20.4 → pymud-0.21.0}/LICENSE.txt +0 -0
  27. {pymud-0.20.4 → pymud-0.21.0}/setup.cfg +0 -0
  28. {pymud-0.20.4 → pymud-0.21.0}/src/pymud/__main__.py +0 -0
  29. {pymud-0.20.4 → pymud-0.21.0}/src/pymud.egg-info/dependency_links.txt +0 -0
  30. {pymud-0.20.4 → pymud-0.21.0}/src/pymud.egg-info/entry_points.txt +0 -0
  31. {pymud-0.20.4 → pymud-0.21.0}/src/pymud.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pymud
3
- Version: 0.20.4
3
+ Version: 0.21.0
4
4
  Summary: a MUD Client written in Python
5
5
  Author-email: "newstart@pkuxkx" <crapex@hotmail.com>
6
6
  Maintainer-email: "newstart@pkuxkx" <crapex@hotmail.com>
@@ -10,16 +10,16 @@ Project-URL: Bug Reports, https://github.com/crapex/pymud/issues
10
10
  Project-URL: Source, https://github.com/crapex/pymud/
11
11
  Project-URL: document, https://pymud.readthedocs.io/
12
12
  Keywords: MUD,multi-user dungeon,client
13
- Classifier: Development Status :: 5 - Production/Stable
13
+ Classifier: Development Status :: 3 - Alpha
14
14
  Classifier: Intended Audience :: End Users/Desktop
15
15
  Classifier: Topic :: Games/Entertainment :: Multi-User Dungeons (MUD)
16
16
  Classifier: Programming Language :: Python :: 3
17
- Classifier: Programming Language :: Python :: 3.7
18
17
  Classifier: Programming Language :: Python :: 3.8
19
18
  Classifier: Programming Language :: Python :: 3.9
20
19
  Classifier: Programming Language :: Python :: 3.10
21
20
  Classifier: Programming Language :: Python :: 3.11
22
21
  Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Programming Language :: Python :: 3.13
23
23
  Classifier: Programming Language :: Python :: 3 :: Only
24
24
  Requires-Python: >=3.7
25
25
  Description-Content-Type: text/markdown
@@ -27,7 +27,7 @@ License-File: LICENSE.txt
27
27
  Requires-Dist: wcwidth
28
28
  Requires-Dist: pyperclip
29
29
  Requires-Dist: pygments
30
- Requires-Dist: prompt-toolkit
30
+ Requires-Dist: prompt-toolkit>=3.0.51
31
31
  Dynamic: license-file
32
32
 
33
33
  # PyMUD - Python原生MUD客户端
@@ -37,12 +37,15 @@ Dynamic: license-file
37
37
  ### 源代码地址: https://github.com/crapex/pymud
38
38
  ### 帮助文档地址: https://pymud.readthedocs.org
39
39
  ### PyPi项目地址: https://pypi.org/project/pymud
40
- ### 使用交流QQ群:554672580
40
+ ### 由deepwiki自动生成的项目理解文档地址: https://deepwiki.com/crapex/pymud
41
+ ### PyMUD用户shanghua写的入门教程文档:https://www.pkuxkx.net/forum/forum.php?mod=viewthread&tid=49999&forumuid=12067
42
+ ### 交流QQ群:554672580
41
43
 
42
44
 
43
45
  ### 北大侠客行Mud (www.pkuxkx.net),最好的中文Mud游戏!
44
46
  ### PyMUD是我为了更好的玩北大侠客行,特意自行开发的MUD客户端。PyMUD具有以下特点:
45
47
  + 原生Python开发,除prompt-toolkit及其依赖库(wcwidth, pygment, pyperclip)外,不需要其他第三方库支持
48
+ + 原生Python的asyncio实现的通信协议处理,支持async/await语法在脚本中直接应用,脚本实现的同步异步两种模式由你自己选择
46
49
  + 基于控制台的全屏UI界面设计,支持鼠标操作(Android上支持触摸屏操作)
47
50
  + 支持分屏显示,在数据快速滚动的时候,上半屏保持不动,以确保不错过信息
48
51
  + 解决了99%情况下,北大侠客行中文对不齐,也就是看不清字符画的问题(因为我没有走遍所有地方,不敢保证100%)
@@ -63,6 +66,116 @@ Dynamic: license-file
63
66
 
64
67
  ## 版本更新信息
65
68
 
69
+ ### 0.21.0 开发中,最新更新2025-05-18
70
+
71
+ + 功能新增: 各类对象的group属性,新增组、子组概念,用于快速成组操作对象。组可以包括子组,子组可以再包括子组。
72
+ 组名以点号.分隔,例如:group1.subgroup1.subsubgroup1。组的层级没有限制。
73
+ 组的概念可以用于快速处理多个对象,例如启用/禁用一组对象、删除一组对象等。例如,以下几个组的关系:
74
+ - mygroup1
75
+ - mygroup1.subgroup1 # 属于 mygroup1的子组
76
+ - mygroup1.subgroup2 # 属于 mygroup1的子组
77
+ - mygroup1.subgroup2.subsubgroup1 # 属于 mygroup1.subgroup2的子组,也同样属于更高层级mygroup1的子组
78
+ - mygroup2
79
+ - mygroup2.subgroup1 # 属于 mygroup2的子组
80
+
81
+ + 功能新增: 新增了deleteGroup函数,用于删除指定的对象组。可同时指定组名、是否包含子组名、有效类型范围。函数定义和示例代码如下:
82
+
83
+ ``` Python
84
+ def deleteGroup(self, group: str, subgroup = True, types: Union[Type, Union[Tuple, List]] = (Alias, Trigger, Command, Timer, GMCPTrigger)):
85
+ pass
86
+ # 各参数含义:
87
+ # group: 要删除的组名,可以是完整的组名,也可以是部分组名。例如:"group1" 或 "group1.subgroup1" 等。
88
+ # subgroup: 是否包含子组。如果为True,则删除指定组及其所有子组的对象。如果为False,则仅删除指定组的对象,不包括子组。
89
+ # types: 要删除的对象类型范围。可以是单个类型,也可以是类型的元组或列表。例如:Trigger, Alias, Command, Timer, GMCPTrigger 等。
90
+ # 示例代码:
91
+ # 删除所有属于group1的Trigger和Alias对象,包括子组如 group1.subgroup1 和 group1.subgroup2 等
92
+ self.session.deleteGroup("group1", True, [Trigger, Alias])
93
+ # 删除所有属于group1的Trigger对象,但不包括子组
94
+ self.session.deleteGroup("group1", False, [Trigger])
95
+ ```
96
+
97
+ + 功能新增: 对 #trigger, #alias, #timer, #gmcp, #command, #t+, #t- 等命令新增了组处理选项,用于对整组对象进行处理。各命令的语法格式类似。
98
+ 处理组时,组名应以大于号>或者等于号=开头,紧跟组名(无空格)。当使用>时,表示操作针对当前组及所有所属子组,当使用=时,表示操作仅针对当前组。
99
+ 例如下面代码:
100
+
101
+ ```
102
+ #t+ >group1 表示启用所有属于group1以及其子组的所有可管理对象,包括Trigger、Alias、Command、Timer、GMCPTrigger
103
+ #t- =group1.subgroup1 表示禁用所有仅属于group1.subgroup1的Trigger、Alias、Command、Timer、GMCPTrigger等对象
104
+ #tri >group1 off 表示禁用所有属于group1以及其子组的Trigger对象
105
+ #ali =group1.subgroup1 on 表示启用所有仅属于group1.subgroup1的Alias对象
106
+ ```
107
+
108
+ + 功能新增: 调整了enableGroup处理,可以通过组名支持子组操作,也可以指定有效类型范围。例如下面代码:
109
+ ``` Python
110
+ class MyTestConfig(IConfig):
111
+ def __init__(self, session, *args, **kwargs):
112
+ self._objs = [
113
+ Trigger(session, "tri1", group = "group1"),
114
+ Trigger(session, "tri2", group = "group1.subgroup1"),
115
+ Trigger(session, "tri3", group = "group1.subgroup2"),
116
+ Alias(session, "alias1", group = "group1"),
117
+ Alias(session, "alias2", group = "group1.subgroup1"),
118
+ Timer(session, 5, group = "group1.subgroup1")
119
+ ]
120
+
121
+ #以下调用可以同时禁用上述6个对象,因为 group1.subgroup1 和 group1.subgroup2 都属于 group1 的子组
122
+ session.enableGroup("group1", False)
123
+ #以下调用可以同时仅启用触发器tri1和别名alias1,因为通过subgroup参数限定了不传递到子组
124
+ session.enableGroup("group1", True, subgroup = False)
125
+ # 以下调用可以同时禁用对应发器和别名,但不禁用定时器,因为通过types参数指定了有效范围:
126
+ session.enableGroup("group1.subgroup1", False, types = [Trigger, Alias])
127
+
128
+ ```
129
+
130
+ + 功能新增: 增加了多处异常追踪提示。在模块或插件的脚本中发生错误时,均会打印错误追踪信息,方便定位错误。
131
+ + 功能新增: 新增 #echo 命令,类似于 #test 命令,但该命令只会模拟收到服务器数据,直接激发各匹配触发器,但不显示触发测试结果。
132
+ + 功能新增: #load / #unload 现在支持当前会话对插件的临时启用和禁用,实现方式为调用插件里的PLUGIN_SESSION_CREATE和PLUGIN_SESSION_DESTROYE函数。群文件的moving.py插件写法可以支持。
133
+ + 功能调整: 各会话变量保存的.mud文件,统一移到save子目录下。原来当前目录下的.mud文件,在对应会话重新加载时会自动移动,无需人工处理。
134
+ + 功能新增: 增加了国际化(i18n)支持,原生开发语言为中文简体,目前使用AI翻译生成了英文。应用语言通过Settings中新增的language配置来控制,默认为"chs",可以在pymud.cfg中覆盖该配置。其值目前可以为"chs"、"eng"。自行翻译的语言可以在pymud/lang目录下下新增语言文件,文件名为i18n_加语言代码,例如"i18n_chs.py"表示可以使用"chs"语言,其中使用Python字典方式定义了所有需动态显示的文本内容。
135
+ + 功能新增: 新增了使用元类型及装饰器来管理Pymud对象,包括Alias, Trigger, Timer, GMCPTrigger四种可以使用对应的装饰器,@alias, @trigger, @timer, @gmcp来直接在标记函数上创建。可以参考本版本中的pkuxkx.py文件写法和注意事项。
136
+ + 功能新增: 新增了两个装饰器,@exception和@async_exception,用于捕获异常并调用session.error进行显示。@exception用于捕获同步异常,@async_exception用于捕获异步异常。参考如下:
137
+ ``` Python
138
+ from pymud import Command, Trigger, IConfig, exception, async_exception
139
+
140
+ class MyCustomCommand(Command, IConfig):
141
+ @exception
142
+ def a_sync_routine(self, args: list[str]):
143
+ # 这里的代码抛出的异常会被self.session.error捕获并显示
144
+ something_that_may_raise_an_exception()
145
+
146
+ @async_exception
147
+ async def execute(self, args: list[str]):
148
+ # 这里的代码抛出的异常会被self.session.error捕获并显示
149
+ await something_that_may_raise_another_exception()
150
+
151
+ # 上述代码相当于以下代码
152
+ class MyCustomCommand(Command, IConfig):
153
+ def a_sync_routine(self, args: list[str]):
154
+ try:
155
+ something_that_may_raise_an_exception()
156
+ except Exception as e:
157
+ self.session.error(error_msg_of_e)
158
+
159
+ async def execute(self, args: list[str]):
160
+ try:
161
+ await something_that_may_raise_another_exception()
162
+ except Exception as e:
163
+ self.session.error(error_msg_of_e)
164
+ ```
165
+ + 问题修复: 修复了Alias和Command执行时的优先级判断。之前未进行优先级判断,因此遇到能同时匹配的多个时,不一定优先级高的被触发。现在对Alias和Command进行了优先级判断,优先级高的先触发。
166
+ + 问题修复: 修复Alias中的keepEval参数和oneShot参数。keepEval参数支持多个匹配成功的别名同时生效,oneShot参数支持一个匹配成功的别名生效后,后续的匹配不再生效。
167
+ + 问题修复: 修复Command中的keepEval参数。以往同时匹配生效的Command会覆盖后续Command和Alias,当前会持续匹配。
168
+ + 功能增强: 对几乎所有函数的参数进行了类型标注,增加了类型检查,提高了代码的可读性和可维护性,也便于自行编写脚本时的提示。
169
+ + 功能增强: 为Session类型增加了commandHistory属性,用于查询发送到服务器的命令历史。保存的命令历史的数量由pymud.cfg中的client["history_records"]控制,默认为500。当该值为0时,不会保存命令历史。为-1时,会保存所有命令历史。
170
+ + 功能调整: #help命令时,增加了上下两行分隔符显示,以便明显区分帮助输出和游戏输出。
171
+ + 功能增强: 当前pymud界面中显示的版本号会自动从pyproject.toml中读取,以确保版本号的准确性和唯一性。
172
+ + 问题修复: 修复了代码中的部分编码错误。新版Python中能容忍一些错误,但老版本不行。经修复,当前代码支持的Python版本已测试3.8确保可用,3.7版理论可用,但未经测试。建议使用3.10或更高版本的Python。
173
+ + 问题修复: 删除了extras.py中多余的MenuItem类型定义,该定义与prompt_toolkit中的MenuItem定义冲突。
174
+ + 问题修复: 调整了众多代码中未检查对象是否为None即调用、使用的局部变量可能未经过初始化和赋值路径等的情况,保证程序运行的健壮性。
175
+ + 问题修复: 修复了#test命令的帮助内容错误。实际#show命令不触发脚本,仅测试;而#test会触发脚本。
176
+ + 问题修复: 修复了协议处理中MSDP编码解码处理错误的问题;修复了协议处理中默认encoding不传递导致某些情况下报解码错误的问题。
177
+ + 示例更新: 更新了包中自带的pkuxkx.py,增加了@alias, @trigger, @timer, @gmcp的示例以及状态窗口的示例。
178
+
66
179
  ### 0.20.4 (2025-03-30)
67
180
  + 功能调整: 为插件功能新增了 PLUGIN_PYMUD_DESTROY 方法,用于在插件被卸载时,进行一些清理工作。
68
181
  + 功能调整: 将插件的 PLUGIN_PYMUD_START 方法的调用,从插件加载时刻移动到事件循环启动之后,这样在加载时,可以使用 asyncio.create_task或 asyncio.ensure_future 来执行一些异步操作
@@ -5,12 +5,15 @@
5
5
  ### 源代码地址: https://github.com/crapex/pymud
6
6
  ### 帮助文档地址: https://pymud.readthedocs.org
7
7
  ### PyPi项目地址: https://pypi.org/project/pymud
8
- ### 使用交流QQ群:554672580
8
+ ### 由deepwiki自动生成的项目理解文档地址: https://deepwiki.com/crapex/pymud
9
+ ### PyMUD用户shanghua写的入门教程文档:https://www.pkuxkx.net/forum/forum.php?mod=viewthread&tid=49999&forumuid=12067
10
+ ### 交流QQ群:554672580
9
11
 
10
12
 
11
13
  ### 北大侠客行Mud (www.pkuxkx.net),最好的中文Mud游戏!
12
14
  ### PyMUD是我为了更好的玩北大侠客行,特意自行开发的MUD客户端。PyMUD具有以下特点:
13
15
  + 原生Python开发,除prompt-toolkit及其依赖库(wcwidth, pygment, pyperclip)外,不需要其他第三方库支持
16
+ + 原生Python的asyncio实现的通信协议处理,支持async/await语法在脚本中直接应用,脚本实现的同步异步两种模式由你自己选择
14
17
  + 基于控制台的全屏UI界面设计,支持鼠标操作(Android上支持触摸屏操作)
15
18
  + 支持分屏显示,在数据快速滚动的时候,上半屏保持不动,以确保不错过信息
16
19
  + 解决了99%情况下,北大侠客行中文对不齐,也就是看不清字符画的问题(因为我没有走遍所有地方,不敢保证100%)
@@ -31,6 +34,116 @@
31
34
 
32
35
  ## 版本更新信息
33
36
 
37
+ ### 0.21.0 开发中,最新更新2025-05-18
38
+
39
+ + 功能新增: 各类对象的group属性,新增组、子组概念,用于快速成组操作对象。组可以包括子组,子组可以再包括子组。
40
+ 组名以点号.分隔,例如:group1.subgroup1.subsubgroup1。组的层级没有限制。
41
+ 组的概念可以用于快速处理多个对象,例如启用/禁用一组对象、删除一组对象等。例如,以下几个组的关系:
42
+ - mygroup1
43
+ - mygroup1.subgroup1 # 属于 mygroup1的子组
44
+ - mygroup1.subgroup2 # 属于 mygroup1的子组
45
+ - mygroup1.subgroup2.subsubgroup1 # 属于 mygroup1.subgroup2的子组,也同样属于更高层级mygroup1的子组
46
+ - mygroup2
47
+ - mygroup2.subgroup1 # 属于 mygroup2的子组
48
+
49
+ + 功能新增: 新增了deleteGroup函数,用于删除指定的对象组。可同时指定组名、是否包含子组名、有效类型范围。函数定义和示例代码如下:
50
+
51
+ ``` Python
52
+ def deleteGroup(self, group: str, subgroup = True, types: Union[Type, Union[Tuple, List]] = (Alias, Trigger, Command, Timer, GMCPTrigger)):
53
+ pass
54
+ # 各参数含义:
55
+ # group: 要删除的组名,可以是完整的组名,也可以是部分组名。例如:"group1" 或 "group1.subgroup1" 等。
56
+ # subgroup: 是否包含子组。如果为True,则删除指定组及其所有子组的对象。如果为False,则仅删除指定组的对象,不包括子组。
57
+ # types: 要删除的对象类型范围。可以是单个类型,也可以是类型的元组或列表。例如:Trigger, Alias, Command, Timer, GMCPTrigger 等。
58
+ # 示例代码:
59
+ # 删除所有属于group1的Trigger和Alias对象,包括子组如 group1.subgroup1 和 group1.subgroup2 等
60
+ self.session.deleteGroup("group1", True, [Trigger, Alias])
61
+ # 删除所有属于group1的Trigger对象,但不包括子组
62
+ self.session.deleteGroup("group1", False, [Trigger])
63
+ ```
64
+
65
+ + 功能新增: 对 #trigger, #alias, #timer, #gmcp, #command, #t+, #t- 等命令新增了组处理选项,用于对整组对象进行处理。各命令的语法格式类似。
66
+ 处理组时,组名应以大于号>或者等于号=开头,紧跟组名(无空格)。当使用>时,表示操作针对当前组及所有所属子组,当使用=时,表示操作仅针对当前组。
67
+ 例如下面代码:
68
+
69
+ ```
70
+ #t+ >group1 表示启用所有属于group1以及其子组的所有可管理对象,包括Trigger、Alias、Command、Timer、GMCPTrigger
71
+ #t- =group1.subgroup1 表示禁用所有仅属于group1.subgroup1的Trigger、Alias、Command、Timer、GMCPTrigger等对象
72
+ #tri >group1 off 表示禁用所有属于group1以及其子组的Trigger对象
73
+ #ali =group1.subgroup1 on 表示启用所有仅属于group1.subgroup1的Alias对象
74
+ ```
75
+
76
+ + 功能新增: 调整了enableGroup处理,可以通过组名支持子组操作,也可以指定有效类型范围。例如下面代码:
77
+ ``` Python
78
+ class MyTestConfig(IConfig):
79
+ def __init__(self, session, *args, **kwargs):
80
+ self._objs = [
81
+ Trigger(session, "tri1", group = "group1"),
82
+ Trigger(session, "tri2", group = "group1.subgroup1"),
83
+ Trigger(session, "tri3", group = "group1.subgroup2"),
84
+ Alias(session, "alias1", group = "group1"),
85
+ Alias(session, "alias2", group = "group1.subgroup1"),
86
+ Timer(session, 5, group = "group1.subgroup1")
87
+ ]
88
+
89
+ #以下调用可以同时禁用上述6个对象,因为 group1.subgroup1 和 group1.subgroup2 都属于 group1 的子组
90
+ session.enableGroup("group1", False)
91
+ #以下调用可以同时仅启用触发器tri1和别名alias1,因为通过subgroup参数限定了不传递到子组
92
+ session.enableGroup("group1", True, subgroup = False)
93
+ # 以下调用可以同时禁用对应发器和别名,但不禁用定时器,因为通过types参数指定了有效范围:
94
+ session.enableGroup("group1.subgroup1", False, types = [Trigger, Alias])
95
+
96
+ ```
97
+
98
+ + 功能新增: 增加了多处异常追踪提示。在模块或插件的脚本中发生错误时,均会打印错误追踪信息,方便定位错误。
99
+ + 功能新增: 新增 #echo 命令,类似于 #test 命令,但该命令只会模拟收到服务器数据,直接激发各匹配触发器,但不显示触发测试结果。
100
+ + 功能新增: #load / #unload 现在支持当前会话对插件的临时启用和禁用,实现方式为调用插件里的PLUGIN_SESSION_CREATE和PLUGIN_SESSION_DESTROYE函数。群文件的moving.py插件写法可以支持。
101
+ + 功能调整: 各会话变量保存的.mud文件,统一移到save子目录下。原来当前目录下的.mud文件,在对应会话重新加载时会自动移动,无需人工处理。
102
+ + 功能新增: 增加了国际化(i18n)支持,原生开发语言为中文简体,目前使用AI翻译生成了英文。应用语言通过Settings中新增的language配置来控制,默认为"chs",可以在pymud.cfg中覆盖该配置。其值目前可以为"chs"、"eng"。自行翻译的语言可以在pymud/lang目录下下新增语言文件,文件名为i18n_加语言代码,例如"i18n_chs.py"表示可以使用"chs"语言,其中使用Python字典方式定义了所有需动态显示的文本内容。
103
+ + 功能新增: 新增了使用元类型及装饰器来管理Pymud对象,包括Alias, Trigger, Timer, GMCPTrigger四种可以使用对应的装饰器,@alias, @trigger, @timer, @gmcp来直接在标记函数上创建。可以参考本版本中的pkuxkx.py文件写法和注意事项。
104
+ + 功能新增: 新增了两个装饰器,@exception和@async_exception,用于捕获异常并调用session.error进行显示。@exception用于捕获同步异常,@async_exception用于捕获异步异常。参考如下:
105
+ ``` Python
106
+ from pymud import Command, Trigger, IConfig, exception, async_exception
107
+
108
+ class MyCustomCommand(Command, IConfig):
109
+ @exception
110
+ def a_sync_routine(self, args: list[str]):
111
+ # 这里的代码抛出的异常会被self.session.error捕获并显示
112
+ something_that_may_raise_an_exception()
113
+
114
+ @async_exception
115
+ async def execute(self, args: list[str]):
116
+ # 这里的代码抛出的异常会被self.session.error捕获并显示
117
+ await something_that_may_raise_another_exception()
118
+
119
+ # 上述代码相当于以下代码
120
+ class MyCustomCommand(Command, IConfig):
121
+ def a_sync_routine(self, args: list[str]):
122
+ try:
123
+ something_that_may_raise_an_exception()
124
+ except Exception as e:
125
+ self.session.error(error_msg_of_e)
126
+
127
+ async def execute(self, args: list[str]):
128
+ try:
129
+ await something_that_may_raise_another_exception()
130
+ except Exception as e:
131
+ self.session.error(error_msg_of_e)
132
+ ```
133
+ + 问题修复: 修复了Alias和Command执行时的优先级判断。之前未进行优先级判断,因此遇到能同时匹配的多个时,不一定优先级高的被触发。现在对Alias和Command进行了优先级判断,优先级高的先触发。
134
+ + 问题修复: 修复Alias中的keepEval参数和oneShot参数。keepEval参数支持多个匹配成功的别名同时生效,oneShot参数支持一个匹配成功的别名生效后,后续的匹配不再生效。
135
+ + 问题修复: 修复Command中的keepEval参数。以往同时匹配生效的Command会覆盖后续Command和Alias,当前会持续匹配。
136
+ + 功能增强: 对几乎所有函数的参数进行了类型标注,增加了类型检查,提高了代码的可读性和可维护性,也便于自行编写脚本时的提示。
137
+ + 功能增强: 为Session类型增加了commandHistory属性,用于查询发送到服务器的命令历史。保存的命令历史的数量由pymud.cfg中的client["history_records"]控制,默认为500。当该值为0时,不会保存命令历史。为-1时,会保存所有命令历史。
138
+ + 功能调整: #help命令时,增加了上下两行分隔符显示,以便明显区分帮助输出和游戏输出。
139
+ + 功能增强: 当前pymud界面中显示的版本号会自动从pyproject.toml中读取,以确保版本号的准确性和唯一性。
140
+ + 问题修复: 修复了代码中的部分编码错误。新版Python中能容忍一些错误,但老版本不行。经修复,当前代码支持的Python版本已测试3.8确保可用,3.7版理论可用,但未经测试。建议使用3.10或更高版本的Python。
141
+ + 问题修复: 删除了extras.py中多余的MenuItem类型定义,该定义与prompt_toolkit中的MenuItem定义冲突。
142
+ + 问题修复: 调整了众多代码中未检查对象是否为None即调用、使用的局部变量可能未经过初始化和赋值路径等的情况,保证程序运行的健壮性。
143
+ + 问题修复: 修复了#test命令的帮助内容错误。实际#show命令不触发脚本,仅测试;而#test会触发脚本。
144
+ + 问题修复: 修复了协议处理中MSDP编码解码处理错误的问题;修复了协议处理中默认encoding不传递导致某些情况下报解码错误的问题。
145
+ + 示例更新: 更新了包中自带的pkuxkx.py,增加了@alias, @trigger, @timer, @gmcp的示例以及状态窗口的示例。
146
+
34
147
  ### 0.20.4 (2025-03-30)
35
148
  + 功能调整: 为插件功能新增了 PLUGIN_PYMUD_DESTROY 方法,用于在插件被卸载时,进行一些清理工作。
36
149
  + 功能调整: 将插件的 PLUGIN_PYMUD_START 方法的调用,从插件加载时刻移动到事件循环启动之后,这样在加载时,可以使用 asyncio.create_task或 asyncio.ensure_future 来执行一些异步操作
@@ -1,7 +1,7 @@
1
1
  [project]
2
2
 
3
3
  name = "pymud" # Required
4
- version = "0.20.4" # Required
4
+ version = "0.21.0" # Required
5
5
  description = "a MUD Client written in Python" # Optional
6
6
  readme = "README.md" # Optional
7
7
  requires-python = ">=3.7"
@@ -22,23 +22,26 @@ classifiers = [ # Optional
22
22
  # 3 - Alpha
23
23
  # 4 - Beta
24
24
  # 5 - Production/Stable
25
- "Development Status :: 5 - Production/Stable",
26
- # "Development Status :: 3 - Alpha",
25
+ #"Development Status :: 5 - Production/Stable",
26
+ "Development Status :: 3 - Alpha",
27
27
  "Intended Audience :: End Users/Desktop",
28
28
  "Topic :: Games/Entertainment :: Multi-User Dungeons (MUD)",
29
29
  # "License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
30
30
  "Programming Language :: Python :: 3",
31
- "Programming Language :: Python :: 3.7",
32
31
  "Programming Language :: Python :: 3.8",
33
32
  "Programming Language :: Python :: 3.9",
34
33
  "Programming Language :: Python :: 3.10",
35
34
  "Programming Language :: Python :: 3.11",
36
35
  "Programming Language :: Python :: 3.12",
36
+ "Programming Language :: Python :: 3.13",
37
37
  "Programming Language :: Python :: 3 :: Only",
38
38
  ]
39
39
 
40
- dependencies = [
41
- "wcwidth", "pyperclip", "pygments", "prompt-toolkit"
40
+ dependencies = [
41
+ "wcwidth",
42
+ "pyperclip",
43
+ "pygments",
44
+ "prompt-toolkit>=3.0.51",
42
45
  ]
43
46
 
44
47
  [project.urls] # Optional
@@ -0,0 +1,17 @@
1
+ from .settings import Settings
2
+ from .pymud import PyMudApp
3
+ from .modules import IConfigBase, IConfig, PymudMeta
4
+ from .objects import CodeBlock, Alias, SimpleAlias, Trigger, SimpleTrigger, Command, SimpleCommand, Timer, SimpleTimer, GMCPTrigger
5
+ from .extras import DotDict
6
+ from .session import Session
7
+ from .logger import Logger
8
+ from .main import main
9
+ from .decorators import exception, async_exception, PymudDecorator, alias, trigger, timer, gmcp
10
+
11
+ __all__ = [
12
+ "PymudMeta", "IConfigBase", "IConfig", "PyMudApp", "Settings", "CodeBlock",
13
+ "Alias", "SimpleAlias", "Trigger", "SimpleTrigger",
14
+ "Command", "SimpleCommand", "Timer", "SimpleTimer",
15
+ "GMCPTrigger", "Session", "DotDict", "Logger", "main",
16
+ "exception", "async_exception", "PymudDecorator", "alias", "trigger", "timer", "gmcp",
17
+ ]
@@ -0,0 +1,234 @@
1
+ import sys, functools, traceback
2
+ from typing import Union, Optional, List
3
+
4
+ def print_exception(session, e: Exception):
5
+ """打印异常信息"""
6
+ from .settings import Settings
7
+ from .session import Session
8
+ if isinstance(session, Session):
9
+ # tb = sys.exc_info()[2]
10
+ # frames = traceback.extract_tb(tb)
11
+ # frame = frames[-1]
12
+ # session.error(Settings.gettext("exception_traceback", frame.filename, frame.lineno, frame.name), Settings.gettext("script_error"))
13
+ # if frame.line:
14
+ # session.error(f" {frame.line}", Settings.gettext("script_error"))
15
+
16
+ # session.error(Settings.gettext("exception_message", type(e).__name__, e), Settings.gettext("script_error"))
17
+ # session.error("===========================", Settings.gettext("script_error"))
18
+ session.error(traceback.format_exc(), Settings.gettext("script_error"))
19
+
20
+ def exception(func):
21
+ """方法异常处理装饰器,捕获异常后通过会话的session.error打印相关信息"""
22
+ @functools.wraps(func)
23
+ def wrapper(self, *args, **kwargs):
24
+ from .objects import BaseObject
25
+ from .modules import ModuleInfo, IConfig
26
+ from .session import Session
27
+ from .settings import Settings
28
+ try:
29
+ return func(self, *args, **kwargs)
30
+ except Exception as e:
31
+ # 调用类的错误处理方法
32
+ if isinstance(self, Session):
33
+ session = self
34
+ elif isinstance(self, (BaseObject, IConfig, ModuleInfo)):
35
+ session = self.session
36
+ else:
37
+ session = None
38
+
39
+ if isinstance(session, Session):
40
+ print_exception(session, e)
41
+ #session.error(Settings.gettext("exception_message", e, type(e)))
42
+ #session.error(Settings.gettext("exception_traceback", traceback.format_exc()))
43
+ else:
44
+ raise # 当没有会话时,选择重新抛出异常
45
+ return wrapper
46
+
47
+ def async_exception(func):
48
+ """异步方法异常处理装饰器,捕获异常后通过会话的session.error打印相关信息"""
49
+ @functools.wraps(func)
50
+ async def wrapper(self, *args, **kwargs):
51
+ from .objects import BaseObject
52
+ from .modules import ModuleInfo, IConfig
53
+ from .session import Session
54
+ from .settings import Settings
55
+ try:
56
+ return await func(self, *args, **kwargs)
57
+ except Exception as e:
58
+ if isinstance(self, Session):
59
+ session = self
60
+ elif isinstance(self, (BaseObject, IConfig, ModuleInfo)):
61
+ session = self.session
62
+ else:
63
+ session = None
64
+
65
+ if isinstance(session, Session):
66
+ print_exception(session, e)
67
+
68
+ else:
69
+ raise # 当没有会话时,选择重新抛出异常
70
+ return wrapper
71
+
72
+
73
+ class PymudDecorator:
74
+ """
75
+ 装饰器基类。使用装饰器可以快捷创建各类Pymud基础对象。
76
+
77
+ :param type: 装饰器的类型,用于区分不同的装饰器,为字符串类型。
78
+ :param args: 可变位置参数,用于传递额外的参数。
79
+ :param kwargs: 可变关键字参数,用于传递额外的键值对参数。
80
+ """
81
+ def __init__(self, type: str, *args, **kwargs):
82
+ self.type = type
83
+ self.args = args
84
+ self.kwargs = kwargs
85
+
86
+ def __call__(self, func):
87
+ decos = getattr(func, "__pymud_decorators__", [])
88
+ decos.append(self)
89
+ func.__pymud_decorators__ = decos
90
+
91
+ return func
92
+
93
+ def __repr__(self):
94
+ return f"<{self.__class__.__name__} type = {self.type} args = {self.args} kwargs = {self.kwargs}>"
95
+
96
+
97
+ def alias(
98
+ patterns: Union[List[str], str],
99
+ id: Optional[str] = None,
100
+ group: str = "",
101
+ enabled: bool = True,
102
+ ignoreCase: bool = False,
103
+ isRegExp: bool = True,
104
+ keepEval: bool = False,
105
+ expandVar: bool = True,
106
+ priority: int = 100,
107
+ oneShot: bool = False,
108
+ *args, **kwargs):
109
+ """
110
+ 使用装饰器创建一个别名(Alias)对象。被装饰的函数将在别名成功匹配时调用。
111
+ 被装饰的函数,除第一个参数为类实例本身self之外,另外包括id, line, wildcards三个参数。
112
+ 其中id为别名对象的唯一标识符,line为匹配的文本行,wildcards为匹配的通配符列表。
113
+
114
+ :param patterns: 别名匹配的模式。
115
+ :param id: 别名对象的唯一标识符,不指定时将自动生成唯一标识符。
116
+ :param group: 别名所属的组名,默认为空字符串。
117
+ :param enabled: 别名是否启用,默认为 True。
118
+ :param ignoreCase: 匹配时是否忽略大小写,默认为 False。
119
+ :param isRegExp: 模式是否为正则表达式,默认为 True。
120
+ :param keepEval: 若存在多个可匹配的别名时,是否持续匹配,默认为 False。
121
+ :param expandVar: 是否展开变量,默认为 True。
122
+ :param priority: 别名的优先级,值越小优先级越高,默认为 100。
123
+ :param oneShot: 别名是否只触发一次后自动失效,默认为 False。
124
+ :param args: 可变位置参数,用于传递额外的参数。
125
+ :param kwargs: 可变关键字参数,用于传递额外的键值对参数。
126
+ :return: PymudDecorator 实例,类型为 "alias"。
127
+ """
128
+ # 将传入的参数更新到 kwargs 字典中
129
+ kwargs.update({
130
+ "patterns": patterns,
131
+ "id": id,
132
+ "group": group,
133
+ "enabled": enabled,
134
+ "ignoreCase": ignoreCase,
135
+ "isRegExp": isRegExp,
136
+ "keepEval": keepEval,
137
+ "expandVar": expandVar,
138
+ "priority": priority,
139
+ "oneShot": oneShot})
140
+
141
+ # 如果 id 为 None,则从 kwargs 中移除 "id" 键
142
+ if not id:
143
+ kwargs.pop("id")
144
+
145
+ return PymudDecorator("alias", *args, **kwargs)
146
+
147
+ def trigger(
148
+ patterns: Union[List[str], str],
149
+ id: Optional[str] = None,
150
+ group: str = "",
151
+ enabled: bool = True,
152
+ ignoreCase: bool = False,
153
+ isRegExp: bool = True,
154
+ keepEval: bool = False,
155
+ expandVar: bool = True,
156
+ raw: bool = False,
157
+ priority: int = 100,
158
+ oneShot: bool = False,
159
+ *args, **kwargs):
160
+ """
161
+ 使用装饰器创建一个触发器(Trigger)对象。
162
+
163
+ :param patterns: 触发器匹配的模式。单行模式可以是字符串或正则表达式,多行模式必须是元组或列表,其中每个元素都是字符串或正则表达式。
164
+ :param id: 触发器对象的唯一标识符,不指定时将自动生成唯一标识符。
165
+ :param group: 触发器所属的组名,默认为空字符串。
166
+ :param enabled: 触发器是否启用,默认为 True。
167
+ :param ignoreCase: 匹配时是否忽略大小写,默认为 False。
168
+ :param isRegExp: 模式是否为正则表达式,默认为 True。
169
+ :param keepEval: 若存在多个可匹配的触发器时,是否持续匹配,默认为 False。
170
+ :param expandVar: 是否展开变量,默认为 True。
171
+ :param raw: 是否使用原始匹配方式,默认为 False。原始匹配方式下,不对 VT100 下的 ANSI 颜色进行解码,因此可以匹配颜色;正常匹配仅匹配文本。
172
+ :param priority: 触发器的优先级,值越小优先级越高,默认为 100。
173
+ :param oneShot: 触发器是否只触发一次后自动失效,默认为 False。
174
+ :param args: 可变位置参数,用于传递额外的参数。
175
+ :param kwargs: 可变关键字参数,用于传递额外的键值对参数。
176
+ :return: PymudDecorator 实例,类型为 "trigger"。
177
+ """
178
+ # 将传入的参数更新到 kwargs 字典中
179
+ kwargs.update({
180
+ "patterns": patterns,
181
+ "id": id,
182
+ "group": group,
183
+ "enabled": enabled,
184
+ "ignoreCase": ignoreCase,
185
+ "isRegExp": isRegExp,
186
+ "keepEval": keepEval,
187
+ "expandVar": expandVar,
188
+ "raw": raw,
189
+ "priority": priority,
190
+ "oneShot": oneShot})
191
+ if not id:
192
+ kwargs.pop("id")
193
+ return PymudDecorator("trigger", *args, **kwargs)
194
+
195
+ def timer(timeout: float, id: Optional[str] = None, group: str = "", enabled: bool = True, *args, **kwargs):
196
+ """
197
+ 使用装饰器创建一个定时器(Timer)对象。
198
+
199
+ :param timeout: 定时器超时时间,单位为秒。
200
+ :param id: 定时器对象的唯一标识符,不指定时将自动生成唯一标识符。
201
+ :param group: 定时器所属的组名,默认为空字符串。
202
+ :param enabled: 定时器是否启用,默认为 True。
203
+ :param args: 可变位置参数,用于传递额外的参数。
204
+ :param kwargs: 可变关键字参数,用于传递额外的键值对参数。
205
+ :return: PymudDecorator 实例,类型为 "timer"。
206
+ """
207
+ kwargs.update({
208
+ "timeout": timeout,
209
+ "id": id,
210
+ "group": group,
211
+ "enabled": enabled
212
+ })
213
+ if not id:
214
+ kwargs.pop("id")
215
+ return PymudDecorator("timer", *args, **kwargs)
216
+
217
+ def gmcp(name: str, group: str = "", enabled: bool = True, *args, **kwargs):
218
+ """
219
+ 使用装饰器创建一个GMCP触发器(GMCPTrigger)对象。
220
+
221
+ :param name: GMCP触发器的名称。
222
+ :param group: GMCP触发器所属的组名,默认为空字符串。
223
+ :param enabled: GMCP触发器是否启用,默认为 True。
224
+ :param args: 可变位置参数,用于传递额外的参数。
225
+ :param kwargs: 可变关键字参数,用于传递额外的键值对参数。
226
+ :return: PymudDecorator 实例,类型为 "gmcp"。
227
+ """
228
+ kwargs.update({
229
+ "id": name,
230
+ "group": group,
231
+ "enabled": enabled
232
+ })
233
+
234
+ return PymudDecorator("gmcp", *args, **kwargs)