pymud 0.21.1__py3-none-any.whl → 0.21.2__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 +16 -16
- pymud/__main__.py +3 -3
- pymud/decorators.py +234 -234
- pymud/dialogs.py +166 -166
- pymud/extras.py +974 -918
- pymud/i18n.py +62 -62
- pymud/lang/i18n_chs.py +226 -226
- pymud/lang/i18n_eng.py +850 -850
- pymud/logger.py +167 -167
- pymud/main.py +220 -220
- pymud/modules.py +285 -285
- pymud/objects.py +1032 -1032
- pymud/pkuxkx.py +280 -280
- pymud/protocol.py +1010 -1010
- pymud/pymud.py +1295 -1286
- pymud/session.py +3584 -3578
- pymud/settings.py +196 -196
- {pymud-0.21.1.dist-info → pymud-0.21.2.dist-info}/METADATA +478 -476
- pymud-0.21.2.dist-info/RECORD +23 -0
- {pymud-0.21.1.dist-info → pymud-0.21.2.dist-info}/WHEEL +1 -1
- {pymud-0.21.1.dist-info → pymud-0.21.2.dist-info}/licenses/LICENSE.txt +674 -674
- pymud-0.21.1.dist-info/RECORD +0 -23
- {pymud-0.21.1.dist-info → pymud-0.21.2.dist-info}/entry_points.txt +0 -0
- {pymud-0.21.1.dist-info → pymud-0.21.2.dist-info}/top_level.txt +0 -0
pymud/modules.py
CHANGED
@@ -1,286 +1,286 @@
|
|
1
|
-
|
2
|
-
import importlib, importlib.util, traceback
|
3
|
-
from typing import Any
|
4
|
-
from .settings import Settings
|
5
|
-
from .extras import DotDict
|
6
|
-
from .decorators import exception, async_exception, PymudDecorator, print_exception
|
7
|
-
|
8
|
-
class PymudMeta(type):
|
9
|
-
def __new__(cls, name, bases, attrs):
|
10
|
-
decorator_funcs = {}
|
11
|
-
for name, value in attrs.items():
|
12
|
-
if hasattr(value, "__pymud_decorators__"):
|
13
|
-
decorator_funcs[value.__name__] = getattr(value, "__pymud_decorators__", [])
|
14
|
-
|
15
|
-
attrs["_decorator_funcs"] = decorator_funcs
|
16
|
-
|
17
|
-
return super().__new__(cls, name, bases, attrs)
|
18
|
-
|
19
|
-
class ModuleInfo:
|
20
|
-
"""
|
21
|
-
模块管理类。对加载的模块文件进行管理。该类型由Session类进行管理,无需人工创建和干预。
|
22
|
-
|
23
|
-
有关模块的分类和使用的详细信息,请参见 `脚本 <scripts.html>`_
|
24
|
-
|
25
|
-
:param module_name: 模块的名称, 应与 import xxx 语法中的 xxx 保持一致
|
26
|
-
:param session: 加载/创建本模块的会话
|
27
|
-
|
28
|
-
"""
|
29
|
-
def __init__(self, module_name: str, session):
|
30
|
-
from .session import Session
|
31
|
-
if isinstance(session, Session):
|
32
|
-
self.session = session
|
33
|
-
self._name = module_name
|
34
|
-
self._ismainmodule = False
|
35
|
-
self.load()
|
36
|
-
|
37
|
-
def _load(self, reload = False):
|
38
|
-
result = True
|
39
|
-
if reload:
|
40
|
-
self._module = importlib.reload(self._module)
|
41
|
-
else:
|
42
|
-
self._module = importlib.import_module(self.name)
|
43
|
-
self._config = {}
|
44
|
-
for attr_name in dir(self._module):
|
45
|
-
attr = getattr(self._module, attr_name)
|
46
|
-
if isinstance(attr, type) and attr.__module__ == self._module.__name__:
|
47
|
-
if (attr_name == "Configuration") or issubclass(attr, IConfig):
|
48
|
-
try:
|
49
|
-
self._config[f"{self.name}.{attr_name}"] = attr(self.session, reload = reload)
|
50
|
-
if not reload:
|
51
|
-
self.session.info(Settings.gettext("configuration_created", self.name, attr_name))
|
52
|
-
else:
|
53
|
-
self.session.info(Settings.gettext("configuration_recreated", self.name, attr_name))
|
54
|
-
|
55
|
-
except Exception as e:
|
56
|
-
result = False
|
57
|
-
self.session.error(Settings.gettext("configuration_fail", self.name, attr_name, e))
|
58
|
-
self._ismainmodule = (self._config != {})
|
59
|
-
return result
|
60
|
-
|
61
|
-
def _unload(self):
|
62
|
-
from .objects import BaseObject, Command
|
63
|
-
for key, config in self._config.items():
|
64
|
-
if isinstance(config, Command):
|
65
|
-
# Command 对象在从会话中移除时,自动调用其 unload 系列方法,因此不能产生递归
|
66
|
-
self.session.delObject(config)
|
67
|
-
|
68
|
-
else:
|
69
|
-
|
70
|
-
if hasattr(config, "__unload__"):
|
71
|
-
unload = getattr(config, "__unload__", None)
|
72
|
-
if callable(unload): unload()
|
73
|
-
|
74
|
-
if hasattr(config, "unload"):
|
75
|
-
unload = getattr(config, "unload", None)
|
76
|
-
if callable(unload): unload()
|
77
|
-
|
78
|
-
if isinstance(config, BaseObject):
|
79
|
-
self.session.delObject(config)
|
80
|
-
|
81
|
-
del config
|
82
|
-
self._config.clear()
|
83
|
-
|
84
|
-
def load(self):
|
85
|
-
"加载模块内容"
|
86
|
-
if self._load():
|
87
|
-
self.session.info(f"{Settings.gettext('entity_module' if self.ismainmodule else 'non_entity_module')} {self.name} {Settings.gettext('load_ok')}")
|
88
|
-
else:
|
89
|
-
self.session.info(f"{Settings.gettext('entity_module' if self.ismainmodule else 'non_entity_module')} {self.name} {Settings.gettext('load_fail')}")
|
90
|
-
|
91
|
-
def unload(self):
|
92
|
-
"卸载模块内容"
|
93
|
-
self._unload()
|
94
|
-
self._loaded = False
|
95
|
-
self.session.info(f"{Settings.gettext('entity_module' if self.ismainmodule else 'non_entity_module')} {self.name} {Settings.gettext('unload_ok')}")
|
96
|
-
|
97
|
-
def reload(self):
|
98
|
-
"模块文件更新后调用,重新加载已加载的模块内容"
|
99
|
-
self._unload()
|
100
|
-
self._load(reload = True)
|
101
|
-
self.session.info(f"{Settings.gettext('entity_module' if self.ismainmodule else 'non_entity_module')} {self.name} {Settings.gettext('reload_ok')}")
|
102
|
-
|
103
|
-
@property
|
104
|
-
def name(self):
|
105
|
-
"只读属性,模块名称"
|
106
|
-
return self._name
|
107
|
-
|
108
|
-
@property
|
109
|
-
def module(self):
|
110
|
-
"只读属性,模块文件的 ModuleType 对象"
|
111
|
-
return self._module
|
112
|
-
|
113
|
-
@property
|
114
|
-
def config(self):
|
115
|
-
"只读字典属性,根据模块文件 ModuleType 对象创建的其中名为 Configuration 的类型或继承自 IConfig 的子类型实例(若有)"
|
116
|
-
return self._config
|
117
|
-
|
118
|
-
@property
|
119
|
-
def ismainmodule(self):
|
120
|
-
"只读属性,区分是否主模块(即包含具体config的模块)"
|
121
|
-
return self._ismainmodule
|
122
|
-
|
123
|
-
class IConfigBase(metaclass = PymudMeta):
|
124
|
-
"""
|
125
|
-
用于支持对装饰器写法对象进行管理的基础类。
|
126
|
-
该类型相当于原来的IConfig类,唯一区别时,模块加载时,不会对本类型创建实例对象。
|
127
|
-
主要用于对插件中定义的Command提供装饰器写法支持,因为这些Command是在会话构建时创建,因此不能在模块加载时自动创建,也就不能继承自IConfig。
|
128
|
-
"""
|
129
|
-
def __init__(self, session, *args, **kwargs):
|
130
|
-
from .session import Session
|
131
|
-
from .objects import Alias, Trigger, Timer, GMCPTrigger
|
132
|
-
if isinstance(session, Session):
|
133
|
-
self.session = session
|
134
|
-
self.__inline_objects__ = DotDict()
|
135
|
-
|
136
|
-
if hasattr(self, "_decorator_funcs"):
|
137
|
-
deco_funcs = getattr(self, "_decorator_funcs")
|
138
|
-
for func_name, decorators in deco_funcs.items():
|
139
|
-
func = getattr(self, func_name)
|
140
|
-
for deco in decorators:
|
141
|
-
if isinstance(deco, PymudDecorator):
|
142
|
-
if deco.type == "alias":
|
143
|
-
#patterns = deco.kwargs.pop("patterns")
|
144
|
-
ali = Alias(self.session, *deco.args, **deco.kwargs, onSuccess = func)
|
145
|
-
self.__inline_objects__[ali.id] = ali
|
146
|
-
|
147
|
-
elif deco.type == "trigger":
|
148
|
-
#patterns = deco.kwargs.pop("patterns")
|
149
|
-
tri = Trigger(self.session, *deco.args, **deco.kwargs, onSuccess = func)
|
150
|
-
self.__inline_objects__[tri.id] = tri
|
151
|
-
|
152
|
-
elif deco.type == "timer":
|
153
|
-
tim = Timer(self.session, *deco.args, **deco.kwargs, onSuccess = func)
|
154
|
-
self.__inline_objects__[tim.id] = tim
|
155
|
-
|
156
|
-
elif deco.type == "gmcp":
|
157
|
-
gmcp = GMCPTrigger(self.session, name = deco.kwargs.get("id"), *deco.args, **deco.kwargs, onSuccess = func)
|
158
|
-
self.__inline_objects__[gmcp.id] = gmcp
|
159
|
-
|
160
|
-
def __unload__(self):
|
161
|
-
from .objects import BaseObject
|
162
|
-
if self.session:
|
163
|
-
self.session.delObjects(self.__inline_objects__)
|
164
|
-
if isinstance(self, BaseObject):
|
165
|
-
self.session.delObject(self)
|
166
|
-
|
167
|
-
@property
|
168
|
-
def objs(self) -> DotDict:
|
169
|
-
"返回内联自动创建的对象字典"
|
170
|
-
return self.__inline_objects__
|
171
|
-
|
172
|
-
def obj(self, obj_id: str):
|
173
|
-
"根据对象ID返回内联自动创建的对象"
|
174
|
-
return self.__inline_objects__.get(obj_id, None) # type: ignore
|
175
|
-
|
176
|
-
class IConfig(IConfigBase):
|
177
|
-
"""
|
178
|
-
用于提示PyMUD应用是否自动创建该配置类型的基础类。
|
179
|
-
|
180
|
-
继承 IConfig 类型让应用自动管理该类型,唯一需要的是,构造函数中,仅存在一个必须指定的参数 Session。
|
181
|
-
|
182
|
-
在应用自动创建 IConfig 实例时,除 session 参数外,还会传递一个 reload 参数 (bool类型),表示是首次加载还是重新加载特性。
|
183
|
-
可以从kwargs 中获取该参数,并针对性的设计相应代码。例如,重新加载相关联的其他模块等。
|
184
|
-
"""
|
185
|
-
|
186
|
-
class Plugin:
|
187
|
-
"""
|
188
|
-
插件管理类。对加载的插件文件进行管理。该类型由PyMudApp进行管理,无需人工创建。
|
189
|
-
|
190
|
-
有关插件的详细信息,请参见 `插件 <plugins.html>`_
|
191
|
-
|
192
|
-
:param name: 插件的文件名, 如'myplugin.py'
|
193
|
-
:param location: 插件所在的目录。自动加载的插件包括PyMUD包目录下的plugins目录以及当前目录下的plugins目录
|
194
|
-
|
195
|
-
"""
|
196
|
-
def __init__(self, name, location):
|
197
|
-
self._plugin_file = name
|
198
|
-
self._plugin_loc = location
|
199
|
-
|
200
|
-
self.reload()
|
201
|
-
|
202
|
-
def reload(self):
|
203
|
-
"加载/重新加载插件对象"
|
204
|
-
#del self.modspec, self.mod
|
205
|
-
self.modspec = importlib.util.spec_from_file_location(self._plugin_file[:-3], self._plugin_loc)
|
206
|
-
if self.modspec and self.modspec.loader:
|
207
|
-
self.mod = importlib.util.module_from_spec(self.modspec)
|
208
|
-
self.modspec.loader.exec_module(self.mod)
|
209
|
-
|
210
|
-
self._app_init = self._load_mod_function("PLUGIN_PYMUD_START")
|
211
|
-
self._session_create = self._load_mod_function("PLUGIN_SESSION_CREATE")
|
212
|
-
self._session_destroy = self._load_mod_function("PLUGIN_SESSION_DESTROY")
|
213
|
-
self._app_destroy = self._load_mod_function("PLUGIN_PYMUD_DESTROY")
|
214
|
-
|
215
|
-
else:
|
216
|
-
raise FileNotFoundError(Settings.gettext("exception_plugin_file_not_found", self._plugin_file))
|
217
|
-
|
218
|
-
def _load_mod_function(self, func_name):
|
219
|
-
# 定义一个默认函数,当插件文件中未定义指定名称的函数时,返回该函数
|
220
|
-
# 该函数接受任意数量的位置参数和关键字参数,但不执行任何操作
|
221
|
-
def default_func(*args, **kwargs):
|
222
|
-
pass
|
223
|
-
|
224
|
-
result = default_func
|
225
|
-
if func_name in self.mod.__dict__:
|
226
|
-
func = self.mod.__dict__[func_name]
|
227
|
-
if callable(func):
|
228
|
-
result = func
|
229
|
-
return result
|
230
|
-
|
231
|
-
@property
|
232
|
-
def name(self):
|
233
|
-
"插件名称,由插件文件中的 PLUGIN_NAME 常量定义"
|
234
|
-
return self.mod.__dict__["PLUGIN_NAME"]
|
235
|
-
|
236
|
-
@property
|
237
|
-
def desc(self):
|
238
|
-
"插件描述,由插件文件中的 PLUGIN_DESC 常量定义"
|
239
|
-
return self.mod.__dict__["PLUGIN_DESC"]
|
240
|
-
|
241
|
-
@property
|
242
|
-
def help(self):
|
243
|
-
"插件帮助,由插件文件中的文档字符串定义"
|
244
|
-
return self.mod.__doc__
|
245
|
-
|
246
|
-
def onAppInit(self, app):
|
247
|
-
"""
|
248
|
-
PyMUD应用启动时对插件执行的操作,由插件文件中的 PLUGIN_PYMUD_START 函数定义
|
249
|
-
|
250
|
-
:param app: 启动的 PyMudApp 对象实例
|
251
|
-
"""
|
252
|
-
self._app_init(app)
|
253
|
-
|
254
|
-
def onSessionCreate(self, session):
|
255
|
-
"""
|
256
|
-
新会话创建时对插件执行的操作,由插件文件中的 PLUGIN_SESSION_CREATE 函数定义
|
257
|
-
|
258
|
-
:param session: 新创建的会话对象实例
|
259
|
-
"""
|
260
|
-
try:
|
261
|
-
self._session_create(session)
|
262
|
-
except Exception as e:
|
263
|
-
print_exception(session, e)
|
264
|
-
|
265
|
-
|
266
|
-
def onSessionDestroy(self, session):
|
267
|
-
"""
|
268
|
-
会话关闭时(注意不是断开)对插件执行的操作,由插件文件中的 PLUGIN_SESSION_DESTROY 函数定义
|
269
|
-
|
270
|
-
:param session: 所关闭的会话对象实例
|
271
|
-
"""
|
272
|
-
try:
|
273
|
-
self._session_destroy(session)
|
274
|
-
except Exception as e:
|
275
|
-
print_exception(session, e)
|
276
|
-
|
277
|
-
def onAppDestroy(self, app):
|
278
|
-
"""
|
279
|
-
PyMUD应用关闭时对插件执行的操作,由插件文件中的 PLUGIN_PYMUD_DESTROY 函数定义
|
280
|
-
:param app: 关闭的 PyMudApp 对象实例
|
281
|
-
"""
|
282
|
-
self._app_destroy(app)
|
283
|
-
|
284
|
-
def __getattr__(self, __name: str) -> Any:
|
285
|
-
if hasattr(self.mod, __name):
|
1
|
+
|
2
|
+
import importlib, importlib.util, traceback
|
3
|
+
from typing import Any
|
4
|
+
from .settings import Settings
|
5
|
+
from .extras import DotDict
|
6
|
+
from .decorators import exception, async_exception, PymudDecorator, print_exception
|
7
|
+
|
8
|
+
class PymudMeta(type):
|
9
|
+
def __new__(cls, name, bases, attrs):
|
10
|
+
decorator_funcs = {}
|
11
|
+
for name, value in attrs.items():
|
12
|
+
if hasattr(value, "__pymud_decorators__"):
|
13
|
+
decorator_funcs[value.__name__] = getattr(value, "__pymud_decorators__", [])
|
14
|
+
|
15
|
+
attrs["_decorator_funcs"] = decorator_funcs
|
16
|
+
|
17
|
+
return super().__new__(cls, name, bases, attrs)
|
18
|
+
|
19
|
+
class ModuleInfo:
|
20
|
+
"""
|
21
|
+
模块管理类。对加载的模块文件进行管理。该类型由Session类进行管理,无需人工创建和干预。
|
22
|
+
|
23
|
+
有关模块的分类和使用的详细信息,请参见 `脚本 <scripts.html>`_
|
24
|
+
|
25
|
+
:param module_name: 模块的名称, 应与 import xxx 语法中的 xxx 保持一致
|
26
|
+
:param session: 加载/创建本模块的会话
|
27
|
+
|
28
|
+
"""
|
29
|
+
def __init__(self, module_name: str, session):
|
30
|
+
from .session import Session
|
31
|
+
if isinstance(session, Session):
|
32
|
+
self.session = session
|
33
|
+
self._name = module_name
|
34
|
+
self._ismainmodule = False
|
35
|
+
self.load()
|
36
|
+
|
37
|
+
def _load(self, reload = False):
|
38
|
+
result = True
|
39
|
+
if reload:
|
40
|
+
self._module = importlib.reload(self._module)
|
41
|
+
else:
|
42
|
+
self._module = importlib.import_module(self.name)
|
43
|
+
self._config = {}
|
44
|
+
for attr_name in dir(self._module):
|
45
|
+
attr = getattr(self._module, attr_name)
|
46
|
+
if isinstance(attr, type) and attr.__module__ == self._module.__name__:
|
47
|
+
if (attr_name == "Configuration") or issubclass(attr, IConfig):
|
48
|
+
try:
|
49
|
+
self._config[f"{self.name}.{attr_name}"] = attr(self.session, reload = reload)
|
50
|
+
if not reload:
|
51
|
+
self.session.info(Settings.gettext("configuration_created", self.name, attr_name))
|
52
|
+
else:
|
53
|
+
self.session.info(Settings.gettext("configuration_recreated", self.name, attr_name))
|
54
|
+
|
55
|
+
except Exception as e:
|
56
|
+
result = False
|
57
|
+
self.session.error(Settings.gettext("configuration_fail", self.name, attr_name, e))
|
58
|
+
self._ismainmodule = (self._config != {})
|
59
|
+
return result
|
60
|
+
|
61
|
+
def _unload(self):
|
62
|
+
from .objects import BaseObject, Command
|
63
|
+
for key, config in self._config.items():
|
64
|
+
if isinstance(config, Command):
|
65
|
+
# Command 对象在从会话中移除时,自动调用其 unload 系列方法,因此不能产生递归
|
66
|
+
self.session.delObject(config)
|
67
|
+
|
68
|
+
else:
|
69
|
+
|
70
|
+
if hasattr(config, "__unload__"):
|
71
|
+
unload = getattr(config, "__unload__", None)
|
72
|
+
if callable(unload): unload()
|
73
|
+
|
74
|
+
if hasattr(config, "unload"):
|
75
|
+
unload = getattr(config, "unload", None)
|
76
|
+
if callable(unload): unload()
|
77
|
+
|
78
|
+
if isinstance(config, BaseObject):
|
79
|
+
self.session.delObject(config)
|
80
|
+
|
81
|
+
del config
|
82
|
+
self._config.clear()
|
83
|
+
|
84
|
+
def load(self):
|
85
|
+
"加载模块内容"
|
86
|
+
if self._load():
|
87
|
+
self.session.info(f"{Settings.gettext('entity_module' if self.ismainmodule else 'non_entity_module')} {self.name} {Settings.gettext('load_ok')}")
|
88
|
+
else:
|
89
|
+
self.session.info(f"{Settings.gettext('entity_module' if self.ismainmodule else 'non_entity_module')} {self.name} {Settings.gettext('load_fail')}")
|
90
|
+
|
91
|
+
def unload(self):
|
92
|
+
"卸载模块内容"
|
93
|
+
self._unload()
|
94
|
+
self._loaded = False
|
95
|
+
self.session.info(f"{Settings.gettext('entity_module' if self.ismainmodule else 'non_entity_module')} {self.name} {Settings.gettext('unload_ok')}")
|
96
|
+
|
97
|
+
def reload(self):
|
98
|
+
"模块文件更新后调用,重新加载已加载的模块内容"
|
99
|
+
self._unload()
|
100
|
+
self._load(reload = True)
|
101
|
+
self.session.info(f"{Settings.gettext('entity_module' if self.ismainmodule else 'non_entity_module')} {self.name} {Settings.gettext('reload_ok')}")
|
102
|
+
|
103
|
+
@property
|
104
|
+
def name(self):
|
105
|
+
"只读属性,模块名称"
|
106
|
+
return self._name
|
107
|
+
|
108
|
+
@property
|
109
|
+
def module(self):
|
110
|
+
"只读属性,模块文件的 ModuleType 对象"
|
111
|
+
return self._module
|
112
|
+
|
113
|
+
@property
|
114
|
+
def config(self):
|
115
|
+
"只读字典属性,根据模块文件 ModuleType 对象创建的其中名为 Configuration 的类型或继承自 IConfig 的子类型实例(若有)"
|
116
|
+
return self._config
|
117
|
+
|
118
|
+
@property
|
119
|
+
def ismainmodule(self):
|
120
|
+
"只读属性,区分是否主模块(即包含具体config的模块)"
|
121
|
+
return self._ismainmodule
|
122
|
+
|
123
|
+
class IConfigBase(metaclass = PymudMeta):
|
124
|
+
"""
|
125
|
+
用于支持对装饰器写法对象进行管理的基础类。
|
126
|
+
该类型相当于原来的IConfig类,唯一区别时,模块加载时,不会对本类型创建实例对象。
|
127
|
+
主要用于对插件中定义的Command提供装饰器写法支持,因为这些Command是在会话构建时创建,因此不能在模块加载时自动创建,也就不能继承自IConfig。
|
128
|
+
"""
|
129
|
+
def __init__(self, session, *args, **kwargs):
|
130
|
+
from .session import Session
|
131
|
+
from .objects import Alias, Trigger, Timer, GMCPTrigger
|
132
|
+
if isinstance(session, Session):
|
133
|
+
self.session = session
|
134
|
+
self.__inline_objects__ = DotDict()
|
135
|
+
|
136
|
+
if hasattr(self, "_decorator_funcs"):
|
137
|
+
deco_funcs = getattr(self, "_decorator_funcs")
|
138
|
+
for func_name, decorators in deco_funcs.items():
|
139
|
+
func = getattr(self, func_name)
|
140
|
+
for deco in decorators:
|
141
|
+
if isinstance(deco, PymudDecorator):
|
142
|
+
if deco.type == "alias":
|
143
|
+
#patterns = deco.kwargs.pop("patterns")
|
144
|
+
ali = Alias(self.session, *deco.args, **deco.kwargs, onSuccess = func)
|
145
|
+
self.__inline_objects__[ali.id] = ali
|
146
|
+
|
147
|
+
elif deco.type == "trigger":
|
148
|
+
#patterns = deco.kwargs.pop("patterns")
|
149
|
+
tri = Trigger(self.session, *deco.args, **deco.kwargs, onSuccess = func)
|
150
|
+
self.__inline_objects__[tri.id] = tri
|
151
|
+
|
152
|
+
elif deco.type == "timer":
|
153
|
+
tim = Timer(self.session, *deco.args, **deco.kwargs, onSuccess = func)
|
154
|
+
self.__inline_objects__[tim.id] = tim
|
155
|
+
|
156
|
+
elif deco.type == "gmcp":
|
157
|
+
gmcp = GMCPTrigger(self.session, name = deco.kwargs.get("id"), *deco.args, **deco.kwargs, onSuccess = func)
|
158
|
+
self.__inline_objects__[gmcp.id] = gmcp
|
159
|
+
|
160
|
+
def __unload__(self):
|
161
|
+
from .objects import BaseObject
|
162
|
+
if self.session:
|
163
|
+
self.session.delObjects(self.__inline_objects__)
|
164
|
+
if isinstance(self, BaseObject):
|
165
|
+
self.session.delObject(self)
|
166
|
+
|
167
|
+
@property
|
168
|
+
def objs(self) -> DotDict:
|
169
|
+
"返回内联自动创建的对象字典"
|
170
|
+
return self.__inline_objects__
|
171
|
+
|
172
|
+
def obj(self, obj_id: str):
|
173
|
+
"根据对象ID返回内联自动创建的对象"
|
174
|
+
return self.__inline_objects__.get(obj_id, None) # type: ignore
|
175
|
+
|
176
|
+
class IConfig(IConfigBase):
|
177
|
+
"""
|
178
|
+
用于提示PyMUD应用是否自动创建该配置类型的基础类。
|
179
|
+
|
180
|
+
继承 IConfig 类型让应用自动管理该类型,唯一需要的是,构造函数中,仅存在一个必须指定的参数 Session。
|
181
|
+
|
182
|
+
在应用自动创建 IConfig 实例时,除 session 参数外,还会传递一个 reload 参数 (bool类型),表示是首次加载还是重新加载特性。
|
183
|
+
可以从kwargs 中获取该参数,并针对性的设计相应代码。例如,重新加载相关联的其他模块等。
|
184
|
+
"""
|
185
|
+
|
186
|
+
class Plugin:
|
187
|
+
"""
|
188
|
+
插件管理类。对加载的插件文件进行管理。该类型由PyMudApp进行管理,无需人工创建。
|
189
|
+
|
190
|
+
有关插件的详细信息,请参见 `插件 <plugins.html>`_
|
191
|
+
|
192
|
+
:param name: 插件的文件名, 如'myplugin.py'
|
193
|
+
:param location: 插件所在的目录。自动加载的插件包括PyMUD包目录下的plugins目录以及当前目录下的plugins目录
|
194
|
+
|
195
|
+
"""
|
196
|
+
def __init__(self, name, location):
|
197
|
+
self._plugin_file = name
|
198
|
+
self._plugin_loc = location
|
199
|
+
|
200
|
+
self.reload()
|
201
|
+
|
202
|
+
def reload(self):
|
203
|
+
"加载/重新加载插件对象"
|
204
|
+
#del self.modspec, self.mod
|
205
|
+
self.modspec = importlib.util.spec_from_file_location(self._plugin_file[:-3], self._plugin_loc)
|
206
|
+
if self.modspec and self.modspec.loader:
|
207
|
+
self.mod = importlib.util.module_from_spec(self.modspec)
|
208
|
+
self.modspec.loader.exec_module(self.mod)
|
209
|
+
|
210
|
+
self._app_init = self._load_mod_function("PLUGIN_PYMUD_START")
|
211
|
+
self._session_create = self._load_mod_function("PLUGIN_SESSION_CREATE")
|
212
|
+
self._session_destroy = self._load_mod_function("PLUGIN_SESSION_DESTROY")
|
213
|
+
self._app_destroy = self._load_mod_function("PLUGIN_PYMUD_DESTROY")
|
214
|
+
|
215
|
+
else:
|
216
|
+
raise FileNotFoundError(Settings.gettext("exception_plugin_file_not_found", self._plugin_file))
|
217
|
+
|
218
|
+
def _load_mod_function(self, func_name):
|
219
|
+
# 定义一个默认函数,当插件文件中未定义指定名称的函数时,返回该函数
|
220
|
+
# 该函数接受任意数量的位置参数和关键字参数,但不执行任何操作
|
221
|
+
def default_func(*args, **kwargs):
|
222
|
+
pass
|
223
|
+
|
224
|
+
result = default_func
|
225
|
+
if func_name in self.mod.__dict__:
|
226
|
+
func = self.mod.__dict__[func_name]
|
227
|
+
if callable(func):
|
228
|
+
result = func
|
229
|
+
return result
|
230
|
+
|
231
|
+
@property
|
232
|
+
def name(self):
|
233
|
+
"插件名称,由插件文件中的 PLUGIN_NAME 常量定义"
|
234
|
+
return self.mod.__dict__["PLUGIN_NAME"]
|
235
|
+
|
236
|
+
@property
|
237
|
+
def desc(self):
|
238
|
+
"插件描述,由插件文件中的 PLUGIN_DESC 常量定义"
|
239
|
+
return self.mod.__dict__["PLUGIN_DESC"]
|
240
|
+
|
241
|
+
@property
|
242
|
+
def help(self):
|
243
|
+
"插件帮助,由插件文件中的文档字符串定义"
|
244
|
+
return self.mod.__doc__
|
245
|
+
|
246
|
+
def onAppInit(self, app):
|
247
|
+
"""
|
248
|
+
PyMUD应用启动时对插件执行的操作,由插件文件中的 PLUGIN_PYMUD_START 函数定义
|
249
|
+
|
250
|
+
:param app: 启动的 PyMudApp 对象实例
|
251
|
+
"""
|
252
|
+
self._app_init(app)
|
253
|
+
|
254
|
+
def onSessionCreate(self, session):
|
255
|
+
"""
|
256
|
+
新会话创建时对插件执行的操作,由插件文件中的 PLUGIN_SESSION_CREATE 函数定义
|
257
|
+
|
258
|
+
:param session: 新创建的会话对象实例
|
259
|
+
"""
|
260
|
+
try:
|
261
|
+
self._session_create(session)
|
262
|
+
except Exception as e:
|
263
|
+
print_exception(session, e)
|
264
|
+
|
265
|
+
|
266
|
+
def onSessionDestroy(self, session):
|
267
|
+
"""
|
268
|
+
会话关闭时(注意不是断开)对插件执行的操作,由插件文件中的 PLUGIN_SESSION_DESTROY 函数定义
|
269
|
+
|
270
|
+
:param session: 所关闭的会话对象实例
|
271
|
+
"""
|
272
|
+
try:
|
273
|
+
self._session_destroy(session)
|
274
|
+
except Exception as e:
|
275
|
+
print_exception(session, e)
|
276
|
+
|
277
|
+
def onAppDestroy(self, app):
|
278
|
+
"""
|
279
|
+
PyMUD应用关闭时对插件执行的操作,由插件文件中的 PLUGIN_PYMUD_DESTROY 函数定义
|
280
|
+
:param app: 关闭的 PyMudApp 对象实例
|
281
|
+
"""
|
282
|
+
self._app_destroy(app)
|
283
|
+
|
284
|
+
def __getattr__(self, __name: str) -> Any:
|
285
|
+
if hasattr(self.mod, __name):
|
286
286
|
return self.mod.__getattribute__(__name)
|