pymud 0.20.0a4__py3-none-any.whl → 0.20.1__py3-none-any.whl
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.
- pymud/__init__.py +2 -1
- pymud/dialogs.py +11 -6
- pymud/extras.py +32 -75
- pymud/logger.py +9 -3
- pymud/modules.py +188 -0
- pymud/objects.py +37 -20
- pymud/pymud.py +43 -8
- pymud/session.py +192 -116
- pymud/settings.py +2 -2
- {pymud-0.20.0a4.dist-info → pymud-0.20.1.dist-info}/METADATA +26 -15
- pymud-0.20.1.dist-info/RECORD +19 -0
- {pymud-0.20.0a4.dist-info → pymud-0.20.1.dist-info}/WHEEL +1 -1
- pymud-0.20.0a4.dist-info/RECORD +0 -18
- {pymud-0.20.0a4.dist-info → pymud-0.20.1.dist-info}/LICENSE.txt +0 -0
- {pymud-0.20.0a4.dist-info → pymud-0.20.1.dist-info}/entry_points.txt +0 -0
- {pymud-0.20.0a4.dist-info → pymud-0.20.1.dist-info}/top_level.txt +0 -0
pymud/session.py
CHANGED
@@ -4,10 +4,11 @@ from collections import OrderedDict
|
|
4
4
|
import logging, queue
|
5
5
|
from logging import FileHandler
|
6
6
|
from logging.handlers import QueueHandler, QueueListener
|
7
|
-
|
7
|
+
from wcwidth import wcswidth, wcwidth
|
8
8
|
from .logger import Logger
|
9
|
-
from .extras import SessionBuffer, DotDict
|
9
|
+
from .extras import SessionBuffer, DotDict
|
10
10
|
from .protocol import MudClientProtocol
|
11
|
+
from .modules import ModuleInfo
|
11
12
|
from .objects import BaseObject, Trigger, Alias, Command, Timer, SimpleAlias, SimpleTrigger, SimpleTimer, GMCPTrigger, CodeBlock, CodeLine
|
12
13
|
from .settings import Settings
|
13
14
|
|
@@ -99,6 +100,7 @@ class Session:
|
|
99
100
|
"ig" : "ignore",
|
100
101
|
"t+" : "ignore",
|
101
102
|
"t-" : "ignore",
|
103
|
+
"show": "test",
|
102
104
|
}
|
103
105
|
|
104
106
|
def __init__(self, app, name, host, port, encoding = None, after_connect = None, loop = None, **kwargs):
|
@@ -256,11 +258,6 @@ class Session:
|
|
256
258
|
if self.connected:
|
257
259
|
self.write_eof()
|
258
260
|
|
259
|
-
# 两次保存,删掉一次
|
260
|
-
# # 断开时自动保存变量数据
|
261
|
-
# if Settings.client["var_autosave"]:
|
262
|
-
# self.handle_save()
|
263
|
-
|
264
261
|
def onDisconnected(self, protocol):
|
265
262
|
"当从服务器连接断开时执行的操作。包括保存变量(若设置)、打印断开时间、执行自定义事件(若设置)等。"
|
266
263
|
# 断开时自动保存变量数据
|
@@ -562,7 +559,7 @@ class Session:
|
|
562
559
|
|
563
560
|
半数的数量由 Settings.client['buffer_lines'] 确定,默认为5000行。
|
564
561
|
"""
|
565
|
-
if (self._line_count >= 2 * Settings.client["buffer_lines"]) and self.buffer.document.is_cursor_at_the_end:
|
562
|
+
if (Settings.client["buffer_lines"] > 0) and (self._line_count >= 2 * Settings.client["buffer_lines"]) and self.buffer.document.is_cursor_at_the_end:
|
566
563
|
self._line_count = self.buffer.clear_half()
|
567
564
|
|
568
565
|
def feed_data(self, data) -> None:
|
@@ -657,24 +654,25 @@ class Session:
|
|
657
654
|
self.display_line = raw_line
|
658
655
|
|
659
656
|
if not self._ignore:
|
660
|
-
|
657
|
+
# 修改实现,形成列表时即排除非使能状态触发器,加快响应速度
|
658
|
+
#all_tris = list(self._triggers.values())
|
659
|
+
all_tris = [tri for tri in self._triggers.values() if isinstance(tri, Trigger) and tri.enabled]
|
661
660
|
all_tris.sort(key = lambda tri: tri.priority)
|
662
661
|
|
663
662
|
for tri in all_tris:
|
664
|
-
if
|
665
|
-
|
666
|
-
|
667
|
-
|
668
|
-
state = tri.match(tri_line, docallback = True)
|
663
|
+
if tri.raw:
|
664
|
+
state = tri.match(raw_line, docallback = True)
|
665
|
+
else:
|
666
|
+
state = tri.match(tri_line, docallback = True)
|
669
667
|
|
670
|
-
|
671
|
-
|
672
|
-
|
668
|
+
if state.result == Trigger.SUCCESS:
|
669
|
+
if tri.oneShot: # 仅执行一次的trigger,匹配成功后,删除该Trigger(从触发器列表中移除)
|
670
|
+
self._triggers.pop(tri.id)
|
673
671
|
|
674
|
-
|
675
|
-
|
676
|
-
|
677
|
-
|
672
|
+
if not tri.keepEval: # 非持续匹配的trigger,匹配成功后停止检测后续Trigger
|
673
|
+
break
|
674
|
+
else:
|
675
|
+
pass
|
678
676
|
|
679
677
|
# 将数据写入缓存添加到此处
|
680
678
|
if len(self.display_line) > 0:
|
@@ -768,7 +766,7 @@ class Session:
|
|
768
766
|
lines = line.split(self.seperator)
|
769
767
|
for ln in lines:
|
770
768
|
if Settings.client["echo_input"]:
|
771
|
-
self.writetobuffer(f"\x1b[32m{ln}\x1b[0m")
|
769
|
+
self.writetobuffer(f"\x1b[32m{ln}\x1b[0m", True)
|
772
770
|
else:
|
773
771
|
self.log.log(f"\x1b[32m{ln}\x1b[0m\n")
|
774
772
|
|
@@ -777,7 +775,7 @@ class Session:
|
|
777
775
|
|
778
776
|
else:
|
779
777
|
if Settings.client["echo_input"]:
|
780
|
-
self.writetobuffer(f"\x1b[32m{line}\x1b[0m")
|
778
|
+
self.writetobuffer(f"\x1b[32m{line}\x1b[0m", True)
|
781
779
|
else:
|
782
780
|
self.log.log(f"\x1b[32m{line}\x1b[0m\n")
|
783
781
|
|
@@ -808,7 +806,7 @@ class Session:
|
|
808
806
|
return await awaitable
|
809
807
|
|
810
808
|
def exec(self, cmd: str, name = None, *args, **kwargs):
|
811
|
-
"""
|
809
|
+
r"""
|
812
810
|
在名称为name的会话中使用exec_command执行MUD命令。当不指定name时,在当前会话中执行。
|
813
811
|
|
814
812
|
- exec 与 writeline 都会向服务器写入数据。其差异在于,exec执行的内容,会先经过Alias处理和Command处理,实际向远程发送内容与cmd可以不一致。
|
@@ -1284,6 +1282,8 @@ class Session:
|
|
1284
1282
|
"""
|
1285
1283
|
从会话中移除一个对象,可直接删除 Alias, Trigger, GMCPTrigger, Command, Timer 或它们的子类本身
|
1286
1284
|
|
1285
|
+
** 注 ** 现在 delObject 和 delObjects 使用结果相同,都可以清除单个对象、对个对象的list, tuple或dict, 可以有效防止代码写错
|
1286
|
+
|
1287
1287
|
:param obj: 要删除的多个特定对象组成的元组、列表或者字典,可以为 Alias, Trigger, GMCPTrigger, Command, Timer 或其子类
|
1288
1288
|
|
1289
1289
|
示例:
|
@@ -1320,10 +1320,15 @@ class Session:
|
|
1320
1320
|
elif isinstance(obj, GMCPTrigger):
|
1321
1321
|
self._gmcp.pop(obj.id, None)
|
1322
1322
|
|
1323
|
+
elif isinstance(obj, (list, tuple, dict)):
|
1324
|
+
self.delObjects(obj)
|
1325
|
+
|
1323
1326
|
def delObjects(self, objs):
|
1324
1327
|
"""
|
1325
1328
|
从会话中移除一组对象,可直接删除多个 Alias, Trigger, GMCPTrigger, Command, Timer
|
1326
1329
|
|
1330
|
+
** 注 ** 现在 delObject 和 delObjects 使用结果相同,都可以清除单个对象、对个对象的list, tuple或dict, 可以有效防止代码写错
|
1331
|
+
|
1327
1332
|
:param objs: 要删除的一组对象的元组、列表或者字典(保持兼容性),其中对象可以为 Alias, Trigger, GMCPTrigger, Command, Timer 或它们的子类
|
1328
1333
|
|
1329
1334
|
示例:
|
@@ -1355,6 +1360,9 @@ class Session:
|
|
1355
1360
|
for key, item in objs.items():
|
1356
1361
|
self.delObject(item)
|
1357
1362
|
|
1363
|
+
elif isinstance(objs, BaseObject):
|
1364
|
+
self.delObject(objs)
|
1365
|
+
|
1358
1366
|
def addAliases(self, alis):
|
1359
1367
|
"""
|
1360
1368
|
向会话中增加多个别名
|
@@ -1956,7 +1964,7 @@ class Session:
|
|
1956
1964
|
else:
|
1957
1965
|
vars_simple[k] = v
|
1958
1966
|
|
1959
|
-
width = self.application.get_width()
|
1967
|
+
width = self.application.get_width() - 2 # 保留2个字符,防止 > 导致换行
|
1960
1968
|
|
1961
1969
|
title = f" VARIABLE LIST IN SESSION {self.name} "
|
1962
1970
|
left = (width - len(title)) // 2
|
@@ -1964,6 +1972,7 @@ class Session:
|
|
1964
1972
|
self.writetobuffer("="*left + title + "="*right, newline = True)
|
1965
1973
|
|
1966
1974
|
# print vars in simple, 每个变量占40格,一行可以多个变量
|
1975
|
+
# 这里可以考虑调整一下,默认40, 但如果一个变量值太长,则选择占两个位置
|
1967
1976
|
var_count = len(vars_simple)
|
1968
1977
|
var_per_line = (width - 2) // 40
|
1969
1978
|
lines = math.ceil(var_count / var_per_line)
|
@@ -1979,14 +1988,18 @@ class Session:
|
|
1979
1988
|
self.writetobuffer(" " * left_space)
|
1980
1989
|
line_vars = var_keys[start:end]
|
1981
1990
|
for var in line_vars:
|
1982
|
-
|
1991
|
+
repr = vars_simple[var].__repr__()
|
1992
|
+
vwidth = 22 - (wcswidth(repr) - len(repr))
|
1993
|
+
self.writetobuffer("{0} = {1}".format(var.rjust(20), repr.ljust(vwidth)))
|
1994
|
+
#self.writetobuffer("{0:>18} = {1:<19}".format(var, vars_simple[var].__repr__()))
|
1983
1995
|
|
1984
1996
|
self.writetobuffer("", newline = True)
|
1985
1997
|
|
1986
1998
|
# print vars in complex, 每个变量占1行
|
1987
|
-
|
1999
|
+
var_keys = sorted(vars_complex.keys())
|
2000
|
+
for key in var_keys:
|
1988
2001
|
self.writetobuffer(" " * left_space)
|
1989
|
-
self.writetobuffer("{0:>
|
2002
|
+
self.writetobuffer("{0:>20} = {1}".format(key, vars_complex[key].__repr__()), newline = True)
|
1990
2003
|
|
1991
2004
|
self.writetobuffer("="*width, newline = True)
|
1992
2005
|
|
@@ -2039,7 +2052,7 @@ class Session:
|
|
2039
2052
|
else:
|
2040
2053
|
vars_simple[k] = v
|
2041
2054
|
|
2042
|
-
width = self.application.get_width()
|
2055
|
+
width = self.application.get_width() - 2 # 保留2个字符,防止 > 导致换行
|
2043
2056
|
|
2044
2057
|
title = f" GLOBAL VARIABLES LIST "
|
2045
2058
|
left = (width - len(title)) // 2
|
@@ -2062,21 +2075,23 @@ class Session:
|
|
2062
2075
|
self.writetobuffer(" " * left_space)
|
2063
2076
|
line_vars = var_keys[start:end]
|
2064
2077
|
for var in line_vars:
|
2065
|
-
|
2078
|
+
repr = vars_simple[var].__repr__()
|
2079
|
+
vwidth = 22 - (wcswidth(repr) - len(repr))
|
2080
|
+
self.writetobuffer("{0} = {1}".format(var.rjust(20), repr.ljust(vwidth)))
|
2066
2081
|
|
2067
2082
|
self.writetobuffer("", newline = True)
|
2068
2083
|
|
2069
2084
|
# print vars in complex, 每个变量占1行
|
2070
2085
|
for k, v in vars_complex.items():
|
2071
2086
|
self.writetobuffer(" " * left_space)
|
2072
|
-
self.writetobuffer("{0:>
|
2087
|
+
self.writetobuffer("{0:>20} = {1}".format(k, v.__repr__()), newline = True)
|
2073
2088
|
|
2074
2089
|
self.writetobuffer("="*width, newline = True)
|
2075
2090
|
|
2076
2091
|
elif len(args) == 1:
|
2077
2092
|
var = args[0]
|
2078
2093
|
if var in self.application.globals.keys():
|
2079
|
-
self.info("{0:>
|
2094
|
+
self.info("{0:>20} = {1:<22}".format(var, self.application.get_globals(var).__repr__()), "全局变量")
|
2080
2095
|
else:
|
2081
2096
|
self.info("全局空间不存在名称为 {} 的变量".format(var), "全局变量")
|
2082
2097
|
|
@@ -2151,7 +2166,7 @@ class Session:
|
|
2151
2166
|
self.info("创建Timer {} 成功: {}".format(ti.id, ti.__repr__()))
|
2152
2167
|
|
2153
2168
|
def handle_alias(self, code: CodeLine = None, *args, **kwargs):
|
2154
|
-
"""
|
2169
|
+
r"""
|
2155
2170
|
嵌入命令 #alias / #ali 的执行函数,操作别名。该命令可以不带参数、带一个参数或者两个参数。
|
2156
2171
|
该函数不应该在代码中直接调用。
|
2157
2172
|
|
@@ -2541,6 +2556,7 @@ class Session:
|
|
2541
2556
|
self._variables.clear()
|
2542
2557
|
self._tasks.clear()
|
2543
2558
|
|
2559
|
+
|
2544
2560
|
def load_module(self, module_names):
|
2545
2561
|
"""
|
2546
2562
|
模块加载函数。
|
@@ -2564,33 +2580,12 @@ class Session:
|
|
2564
2580
|
"加载指定名称模块"
|
2565
2581
|
try:
|
2566
2582
|
if module_name not in self._modules.keys():
|
2567
|
-
|
2568
|
-
if hasattr(mod, 'Configuration'):
|
2569
|
-
config = mod.Configuration(self)
|
2570
|
-
self._modules[module_name] = {"module": mod, "config": config}
|
2571
|
-
self.info(f"主配置模块 {module_name} 加载完成.")
|
2572
|
-
else:
|
2573
|
-
self._modules[module_name] = {"module": mod, "config": None}
|
2574
|
-
self.info(f"子配置模块 {module_name} 加载完成.")
|
2583
|
+
self._modules[module_name] = ModuleInfo(module_name, self)
|
2575
2584
|
|
2576
2585
|
else:
|
2577
|
-
mod = self._modules[module_name]
|
2578
|
-
|
2579
|
-
|
2580
|
-
if hasattr(config, "__unload__") or hasattr(config, "unload"):
|
2581
|
-
unload = getattr(config, "__unload__", None) or getattr(config, "unload", None)
|
2582
|
-
if callable(unload):
|
2583
|
-
unload()
|
2584
|
-
|
2585
|
-
del config
|
2586
|
-
mod = importlib.reload(mod)
|
2587
|
-
if hasattr(mod, 'Configuration'):
|
2588
|
-
config = mod.Configuration(self)
|
2589
|
-
self._modules[module_name] = {"module": mod, "config": config}
|
2590
|
-
self.info(f"主配置模块 {module_name} 重新加载完成.")
|
2591
|
-
else:
|
2592
|
-
self._modules[module_name] = {"module": mod, "config": None}
|
2593
|
-
self.info(f"子配置模块 {module_name} 重新加载完成.")
|
2586
|
+
mod = self._modules[module_name]
|
2587
|
+
if isinstance(mod, ModuleInfo):
|
2588
|
+
mod.reload()
|
2594
2589
|
|
2595
2590
|
except Exception as e:
|
2596
2591
|
import traceback
|
@@ -2618,18 +2613,9 @@ class Session:
|
|
2618
2613
|
def _unload_module(self, module_name):
|
2619
2614
|
"卸载指定名称模块。卸载支持需要模块的Configuration实现 __unload__ 或 unload 方法"
|
2620
2615
|
if module_name in self._modules.keys():
|
2621
|
-
mod = self._modules
|
2622
|
-
|
2623
|
-
|
2624
|
-
if hasattr(config, "__unload__") or hasattr(config, "unload"):
|
2625
|
-
unload = getattr(config, "__unload__", None) or getattr(config, "unload", None)
|
2626
|
-
if callable(unload):
|
2627
|
-
unload()
|
2628
|
-
|
2629
|
-
del config
|
2630
|
-
del mod
|
2631
|
-
self._modules.pop(module_name)
|
2632
|
-
self.info(f"配置模块 {module_name} 已成功卸载.")
|
2616
|
+
mod = self._modules.pop(module_name)
|
2617
|
+
if isinstance(mod, ModuleInfo):
|
2618
|
+
mod.unload()
|
2633
2619
|
|
2634
2620
|
else:
|
2635
2621
|
self.warning(f"指定模块名称 {module_name} 并未加载.")
|
@@ -2643,9 +2629,9 @@ class Session:
|
|
2643
2629
|
:param module_names: 要重新加载的模块清单。为元组/列表时,卸载指定名称的系列模块,当名称为字符串时,卸载单个模块。当不指定时,重新加载所有已加载模块。
|
2644
2630
|
"""
|
2645
2631
|
if module_names is None:
|
2646
|
-
self.
|
2647
|
-
|
2648
|
-
|
2632
|
+
for name, module in self._modules.items():
|
2633
|
+
if isinstance(module, ModuleInfo):
|
2634
|
+
module.reload()
|
2649
2635
|
|
2650
2636
|
self.info(f"所有配置模块全部重新加载完成.")
|
2651
2637
|
|
@@ -2653,14 +2639,17 @@ class Session:
|
|
2653
2639
|
for mod in module_names:
|
2654
2640
|
mod = mod.strip()
|
2655
2641
|
if mod in self._modules.keys():
|
2656
|
-
self.
|
2642
|
+
module = self._modules[mod]
|
2643
|
+
if isinstance(module, ModuleInfo):
|
2644
|
+
module.reload()
|
2657
2645
|
else:
|
2658
2646
|
self.warning(f"指定模块名称 {mod} 并未加载,无法重新加载.")
|
2659
2647
|
|
2660
2648
|
elif isinstance(module_names, str):
|
2661
2649
|
if module_names in self._modules.keys():
|
2662
|
-
|
2663
|
-
|
2650
|
+
module = self._modules[module_names]
|
2651
|
+
if isinstance(module, ModuleInfo):
|
2652
|
+
module.reload()
|
2664
2653
|
else:
|
2665
2654
|
self.warning(f"指定模块名称 {module_names} 并未加载,无法重新加载.")
|
2666
2655
|
|
@@ -2744,7 +2733,7 @@ class Session:
|
|
2744
2733
|
|
2745
2734
|
elif mod in self.plugins.keys():
|
2746
2735
|
self.application.reload_plugin(self.plugins[mod])
|
2747
|
-
|
2736
|
+
self.info(f'插件 {mod} 重新加载完成!')
|
2748
2737
|
else:
|
2749
2738
|
self.warning(f"指定名称 {mod} 既未找到模块,也未找到插件,重新加载失败..")
|
2750
2739
|
|
@@ -2798,12 +2787,29 @@ class Session:
|
|
2798
2787
|
- #reload
|
2799
2788
|
'''
|
2800
2789
|
|
2801
|
-
|
2802
|
-
|
2803
|
-
|
2804
|
-
|
2805
|
-
|
2790
|
+
args = code.code[2:]
|
2791
|
+
|
2792
|
+
if len(args) == 0:
|
2793
|
+
count = len(self._modules.keys())
|
2794
|
+
if count == 0:
|
2795
|
+
self.info("当前会话并未加载任何模块。", "MODULES")
|
2796
|
+
else:
|
2797
|
+
self.info(f"当前会话已加载 {count} 个模块,包括(按加载顺序排列):{list(self._modules.keys())}", "MODULES")
|
2806
2798
|
|
2799
|
+
elif len(args) >= 1:
|
2800
|
+
modules = ",".join(args).split(",")
|
2801
|
+
for mod in modules:
|
2802
|
+
if mod in self._modules.keys():
|
2803
|
+
module = self._modules[mod]
|
2804
|
+
if isinstance(module, ModuleInfo):
|
2805
|
+
if module.ismainmodule:
|
2806
|
+
self.info(f"模块 {module.name} 中包含的配置包括: {', '.join(module.config.keys())}")
|
2807
|
+
else:
|
2808
|
+
self.info(f"模块 {module.name} 为子模块,不包含配置。")
|
2809
|
+
|
2810
|
+
else:
|
2811
|
+
self.info(f"本会话中不存在指定名称 {mod} 的模块,可能是尚未加载到本会话中")
|
2812
|
+
|
2807
2813
|
def handle_reset(self, code: CodeLine = None, *args, **kwargs):
|
2808
2814
|
'''
|
2809
2815
|
嵌入命令 #reset 的执行函数,复位全部脚本。该命令不带参数。
|
@@ -2823,7 +2829,8 @@ class Session:
|
|
2823
2829
|
|
2824
2830
|
def handle_save(self, code: CodeLine = None, *args, **kwargs):
|
2825
2831
|
'''
|
2826
|
-
嵌入命令 #save
|
2832
|
+
嵌入命令 #save 的执行函数,保存当前会话变量(系统变量和临时变量除外)至文件。该命令不带参数。
|
2833
|
+
系统变量包括 %line, %copy 和 %raw 三个,临时变量是指变量名已下划线开头的变量
|
2827
2834
|
该函数不应该在代码中直接调用。
|
2828
2835
|
|
2829
2836
|
使用:
|
@@ -2844,10 +2851,10 @@ class Session:
|
|
2844
2851
|
with open(file, "wb") as fp:
|
2845
2852
|
saved = dict()
|
2846
2853
|
saved.update(self._variables)
|
2847
|
-
|
2848
|
-
|
2849
|
-
|
2850
|
-
|
2854
|
+
keys = list(saved.keys())
|
2855
|
+
for key in keys:
|
2856
|
+
if key.startswith("_"):
|
2857
|
+
saved.pop(key)
|
2851
2858
|
saved.pop("%line", None)
|
2852
2859
|
saved.pop("%raw", None)
|
2853
2860
|
saved.pop("%copy", None)
|
@@ -2867,19 +2874,26 @@ class Session:
|
|
2867
2874
|
|
2868
2875
|
def handle_test(self, code: CodeLine = None, *args, **kwargs):
|
2869
2876
|
'''
|
2870
|
-
嵌入命令 #test 的执行函数,触发器测试命令。类似于zmud的#show命令。
|
2877
|
+
嵌入命令 #test / #show 的执行函数,触发器测试命令。类似于zmud的#show命令。
|
2871
2878
|
该函数不应该在代码中直接调用。
|
2872
2879
|
|
2873
2880
|
使用:
|
2874
|
-
- #test {some_text}: 测试服务器收到{some_text}
|
2881
|
+
- #test {some_text}: 测试服务器收到{some_text}时的触发器响应情况。此时,触发器不会真的响应。
|
2882
|
+
- #tt {some_test}: 与#test 的差异是,若存在匹配的触发器,无论其是否被使能,该触发器均会实际响应。
|
2875
2883
|
|
2876
2884
|
示例:
|
2877
|
-
- ``#test 你深深吸了口气,站了起来。`` :
|
2885
|
+
- ``#test 你深深吸了口气,站了起来。`` : 模拟服务器收到“你深深吸了口气,站了起来。”时的情况进行触发测试(仅显示触发测试情况)
|
2878
2886
|
- ``#test %copy``: 复制一句话,模拟服务器再次收到复制的这句内容时的情况进行触发器测试
|
2887
|
+
- ``#test 你深深吸了口气,站了起来。`` : 模拟服务器收到“你深深吸了口气,站了起来。”时的情况进行触发测试(会实际导致触发器动作)
|
2879
2888
|
|
2880
2889
|
注意:
|
2881
|
-
- #test
|
2890
|
+
- #test命令测试触发器时,触发器不会真的响应。
|
2891
|
+
- #tt命令测试触发器时,触发器无论是否使能,均会真的响应。
|
2882
2892
|
'''
|
2893
|
+
cmd = code.code[1].lower()
|
2894
|
+
docallback = False
|
2895
|
+
if cmd == "test":
|
2896
|
+
docallback = True
|
2883
2897
|
|
2884
2898
|
new_cmd_text, new_code = code.expand(self, *args, **kwargs)
|
2885
2899
|
line = new_cmd_text[6:] # 取出#test 之后的所有内容
|
@@ -2890,32 +2904,82 @@ class Session:
|
|
2890
2904
|
lines = []
|
2891
2905
|
lines.append(line)
|
2892
2906
|
|
2907
|
+
info_all = []
|
2908
|
+
info_enabled = [] # 组织好每一行显示的内容之后,统一输出,不逐行info
|
2909
|
+
info_disabled = []
|
2910
|
+
triggered = 0
|
2911
|
+
triggered_enabled = 0
|
2912
|
+
triggered_disabled = 0
|
2913
|
+
|
2914
|
+
|
2915
|
+
tris_enabled = [tri for tri in self._triggers.values() if isinstance(tri, Trigger) and tri.enabled]
|
2916
|
+
tris_enabled.sort(key = lambda tri: tri.priority)
|
2917
|
+
|
2918
|
+
tris_disabled = [tri for tri in self._triggers.values() if isinstance(tri, Trigger) and not tri.enabled]
|
2919
|
+
tris_disabled.sort(key = lambda tri: tri.priority)
|
2920
|
+
|
2893
2921
|
for raw_line in lines:
|
2894
|
-
#raw_line = "".join(args)
|
2895
2922
|
tri_line = self.getPlainText(raw_line)
|
2923
|
+
|
2924
|
+
block = False
|
2925
|
+
for tri in tris_enabled:
|
2926
|
+
if tri.raw:
|
2927
|
+
state = tri.match(raw_line, docallback = docallback)
|
2928
|
+
else:
|
2929
|
+
state = tri.match(tri_line, docallback = docallback)
|
2930
|
+
|
2931
|
+
if state.result == Trigger.SUCCESS:
|
2932
|
+
triggered_enabled += 1
|
2933
|
+
if not block:
|
2934
|
+
triggered += 1
|
2935
|
+
info_enabled.append(f" {Settings.INFO_STYLE}{tri.__detailed__()} 正常触发。{Settings.CLR_STYLE}")
|
2936
|
+
info_enabled.append(f" {Settings.INFO_STYLE}捕获:{state.wildcards}{Settings.CLR_STYLE}")
|
2937
|
+
|
2938
|
+
if not tri.keepEval: # 非持续匹配的trigger,匹配成功后停止检测后续Trigger
|
2939
|
+
info_enabled.append(f" {Settings.WARN_STYLE}该触发器未开启keepEval, 会阻止后续触发器。{Settings.CLR_STYLE}")
|
2940
|
+
block = True
|
2941
|
+
else:
|
2942
|
+
info_enabled.append(f" {Settings.WARN_STYLE}{tri.__detailed__()} 可以触发,但由于优先级与keepEval设定,触发器不会触发。{Settings.CLR_STYLE}")
|
2943
|
+
|
2944
|
+
|
2945
|
+
for tri in tris_disabled:
|
2946
|
+
if tri.raw:
|
2947
|
+
state = tri.match(raw_line, docallback = docallback)
|
2948
|
+
else:
|
2949
|
+
state = tri.match(tri_line, docallback = docallback)
|
2896
2950
|
|
2897
|
-
|
2898
|
-
|
2951
|
+
if state.result == Trigger.SUCCESS:
|
2952
|
+
triggered_disabled += 1
|
2953
|
+
info_disabled.append(f" {Settings.INFO_STYLE}{tri.__detailed__()} 可以匹配触发。{Settings.CLR_STYLE}")
|
2899
2954
|
|
2900
|
-
|
2901
|
-
|
2902
|
-
if tri.raw:
|
2903
|
-
state = tri.match(raw_line, docallback = True)
|
2904
|
-
else:
|
2905
|
-
state = tri.match(tri_line, docallback = True)
|
2955
|
+
if triggered_enabled + triggered_disabled == 0:
|
2956
|
+
info_all.append("")
|
2906
2957
|
|
2907
|
-
|
2908
|
-
|
2909
|
-
|
2910
|
-
|
2958
|
+
if triggered_enabled == 0:
|
2959
|
+
info_enabled.insert(0, f"使能的触发器中,没有可以触发的。")
|
2960
|
+
elif triggered < triggered_enabled:
|
2961
|
+
info_enabled.insert(0, f"使能的触发器中,共有 {triggered_enabled} 个可以触发,实际触发 {triggered} 个,另有 {triggered_enabled - triggered} 个由于 keepEval 原因实际不会触发。")
|
2962
|
+
else:
|
2963
|
+
info_enabled.insert(0, f"使能的触发器中,共有 {triggered_enabled} 个全部可以被正常触发。")
|
2911
2964
|
|
2912
|
-
|
2913
|
-
|
2914
|
-
|
2915
|
-
|
2965
|
+
if triggered_disabled > 0:
|
2966
|
+
info_disabled.insert(0, f"未使能的触发器中,共有 {triggered_disabled} 个可以匹配。")
|
2967
|
+
else:
|
2968
|
+
info_disabled.insert(0, f"未使能触发器,没有可以匹配的。")
|
2969
|
+
|
2970
|
+
if triggered_enabled + triggered_disabled == 0:
|
2971
|
+
info_all.append(f"PYMUD 触发器测试: {'响应模式' if docallback else '测试模式'}")
|
2972
|
+
info_all.append(f" 测试内容: {line}")
|
2973
|
+
info_all.append(f" 测试结果: 没有可以匹配的触发器。")
|
2974
|
+
else:
|
2975
|
+
info_all.append(f"PYMUD 触发器测试: {'响应模式' if docallback else '测试模式'}")
|
2976
|
+
info_all.append(f" 测试内容: {line}")
|
2977
|
+
info_all.append(f" 测试结果: 有{triggered}个触发器可以被正常触发,一共有{triggered_enabled + triggered_disabled}个满足匹配触发要求。")
|
2978
|
+
info_all.extend(info_enabled)
|
2979
|
+
info_all.extend(info_disabled)
|
2916
2980
|
|
2917
|
-
|
2918
|
-
|
2981
|
+
self.info("\n".join(info_all), "PYMUD 触发器测试")
|
2982
|
+
#self.info("PYMUD 触发器测试 完毕")
|
2919
2983
|
|
2920
2984
|
def handle_plugins(self, code: CodeLine = None, *args, **kwargs):
|
2921
2985
|
'''
|
@@ -2946,7 +3010,7 @@ class Session:
|
|
2946
3010
|
if name in self.plugins.keys():
|
2947
3011
|
plugin = self.plugins[name]
|
2948
3012
|
self.info(f"{plugin.desc['DESCRIPTION']}, 版本 {plugin.desc['VERSION']} 作者 {plugin.desc['AUTHOR']} 发布日期 {plugin.desc['RELEASE_DATE']}", f"PLUGIN {name}")
|
2949
|
-
self.writetobuffer(plugin.help)
|
3013
|
+
self.writetobuffer(plugin.help, True)
|
2950
3014
|
|
2951
3015
|
def handle_replace(self, code: CodeLine = None, *args, **kwargs):
|
2952
3016
|
'''
|
@@ -3066,7 +3130,8 @@ class Session:
|
|
3066
3130
|
new_lines.append("{}{}".format(style, line))
|
3067
3131
|
|
3068
3132
|
msg = Settings.client["newline"].join(new_lines)
|
3069
|
-
|
3133
|
+
|
3134
|
+
# 将颜色跨行显示移动到了MudFormatProcessor中,此处无需再处理(不行,还得恢复)
|
3070
3135
|
self.writetobuffer("{}[{}] {}{}".format(style, title, msg, Settings.CLR_STYLE), newline = True)
|
3071
3136
|
|
3072
3137
|
def info(self, msg, title = "PYMUD INFO", style = Settings.INFO_STYLE):
|
@@ -3125,8 +3190,8 @@ class Session:
|
|
3125
3190
|
|
3126
3191
|
示例:
|
3127
3192
|
- ``#log`` : 在当前会话窗口列出所有记录器状态
|
3128
|
-
- ``#log start`` : 启动本会话默认记录器(记录器名为会话名)。该记录器以纯文本模式,将后续所有屏幕输出、键盘键入、命令输入等记录到 name.log 文件的后端
|
3129
|
-
- ``#log start -r`` : 启动本会话默认记录器。该记录器以raw模式,将后续所有屏幕输出、键盘键入、命令输入等记录到 name.log 文件的后端
|
3193
|
+
- ``#log start`` : 启动本会话默认记录器(记录器名为会话名)。该记录器以纯文本模式,将后续所有屏幕输出、键盘键入、命令输入等记录到 log 目录下 name.log 文件的后端
|
3194
|
+
- ``#log start -r`` : 启动本会话默认记录器。该记录器以raw模式,将后续所有屏幕输出、键盘键入、命令输入等记录到 log 目录下 name.log 文件的后端
|
3130
3195
|
- ``#log start chat`` : 启动名为 chat 的记录器。该记录器以纯文本模式,记录代码中调用过该记录器 .log 进行记录的信息
|
3131
3196
|
- ``#log stop`` : 停止本会话默认记录器(记录器名为会话名)。
|
3132
3197
|
|
@@ -3184,8 +3249,19 @@ class Session:
|
|
3184
3249
|
elif (args[0] == "show"):
|
3185
3250
|
if len(args) > 1 and not args[1].startswith('-'):
|
3186
3251
|
file = args[1]
|
3187
|
-
|
3188
|
-
|
3252
|
+
if os.path.exists(file):
|
3253
|
+
filepath = os.path.abspath(file)
|
3254
|
+
#self.info(f'file {filepath} exists, will be shown.')
|
3255
|
+
self.application.logFileShown = filepath
|
3256
|
+
self.application.showLogInTab()
|
3257
|
+
elif os.path.exists(os.path.join('./log', file)):
|
3258
|
+
filepath = os.path.abspath(os.path.join('./log', file))
|
3259
|
+
#self.info(f'file {filepath} exists, will be shown.')
|
3260
|
+
self.application.logFileShown = filepath
|
3261
|
+
self.application.showLogInTab()
|
3262
|
+
else:
|
3263
|
+
self.warning(f'指定记录文件 {file} 不存在!')
|
3264
|
+
|
3189
3265
|
else:
|
3190
3266
|
self.application.show_logSelectDialog()
|
3191
3267
|
|
pymud/settings.py
CHANGED
@@ -11,9 +11,9 @@ class Settings:
|
|
11
11
|
"APP 名称, 默认PYMUD"
|
12
12
|
__appdesc__ = "a MUD client written in Python"
|
13
13
|
"APP 简要描述"
|
14
|
-
__version__ = "0.20.
|
14
|
+
__version__ = "0.20.1"
|
15
15
|
"APP 当前版本"
|
16
|
-
__release__ = "2024-
|
16
|
+
__release__ = "2024-11-16"
|
17
17
|
"APP 当前版本发布日期"
|
18
18
|
__author__ = "本牛(newstart)@北侠"
|
19
19
|
"APP 作者"
|