pymud 0.19.3__py3-none-any.whl → 0.19.3.post2__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 +0 -1
- pymud/extras.py +59 -51
- pymud/objects.py +231 -44
- pymud/protocol.py +4 -4
- pymud/pymud.py +101 -28
- pymud/session.py +662 -92
- pymud/settings.py +1 -1
- {pymud-0.19.3.dist-info → pymud-0.19.3.post2.dist-info}/LICENSE.txt +674 -674
- {pymud-0.19.3.dist-info → pymud-0.19.3.post2.dist-info}/METADATA +10 -2
- pymud-0.19.3.post2.dist-info/RECORD +16 -0
- pymud-0.19.3.dist-info/RECORD +0 -16
- {pymud-0.19.3.dist-info → pymud-0.19.3.post2.dist-info}/WHEEL +0 -0
- {pymud-0.19.3.dist-info → pymud-0.19.3.post2.dist-info}/entry_points.txt +0 -0
- {pymud-0.19.3.dist-info → pymud-0.19.3.post2.dist-info}/top_level.txt +0 -0
pymud/session.py
CHANGED
@@ -11,6 +11,18 @@ from .settings import Settings
|
|
11
11
|
class Session:
|
12
12
|
"""
|
13
13
|
会话管理主对象,每一个角色的所有处理实现均在该类中实现。
|
14
|
+
|
15
|
+
**Session对象由PyMudApp对象进行创建和管理,不需要手动创建。**
|
16
|
+
|
17
|
+
:param app: 对应的PyMudApp对象
|
18
|
+
:param name: 本会话的名称
|
19
|
+
:param host: 本会话连接的远程服务器地址
|
20
|
+
:param port: 本会话连接的远程服务器端口
|
21
|
+
:param encoding: 远程服务器的编码
|
22
|
+
:param after_connect: 当连接到远程服务器后执行的操作
|
23
|
+
:param loop: asyncio的消息循环队列
|
24
|
+
:param kwargs: 关键字参数清单,当前支持的关键字 **scripts** : 需加载的脚本清单
|
25
|
+
|
14
26
|
"""
|
15
27
|
#_esc_regx = re.compile("\x1b\\[[^mz]+[mz]")
|
16
28
|
_esc_regx = re.compile("\x1b\\[[\d;]+[abcdmz]", flags = re.IGNORECASE)
|
@@ -156,6 +168,7 @@ class Session:
|
|
156
168
|
self.open()
|
157
169
|
|
158
170
|
def initialize(self):
|
171
|
+
"初始化Session有关对象。 **无需脚本调用。**"
|
159
172
|
self._line_buffer = bytearray()
|
160
173
|
|
161
174
|
self._triggers = DotDict()
|
@@ -172,10 +185,11 @@ class Session:
|
|
172
185
|
self._command_history = []
|
173
186
|
|
174
187
|
def open(self):
|
188
|
+
"创建到远程服务器的连接,同步方式。通过调用异步connect方法实现。"
|
175
189
|
asyncio.ensure_future(self.connect(), loop = self.loop)
|
176
190
|
|
177
191
|
async def connect(self):
|
178
|
-
"
|
192
|
+
"创建到远程服务器的连接,异步非阻塞方式。"
|
179
193
|
def _protocol_factory():
|
180
194
|
return MudClientProtocol(self, onDisconnected = self.onDisconnected)
|
181
195
|
|
@@ -200,11 +214,17 @@ class Session:
|
|
200
214
|
asyncio.ensure_future(self.reconnect(wait), loop = self.loop)
|
201
215
|
|
202
216
|
async def reconnect(self, timeout = 15):
|
217
|
+
"""
|
218
|
+
重新连接到远程服务器,异步非阻塞方式。该方法在 `Settings.client['auto_reconnect']` 设置为真时,断开后自动调用
|
219
|
+
|
220
|
+
:param timeout: 重连之前的等待时间,默认15s,可由 `Settings.client['reconnect_wait']` 设置所覆盖
|
221
|
+
"""
|
203
222
|
self.info(f"{timeout}秒之后将自动重新连接...")
|
204
223
|
await asyncio.sleep(timeout)
|
205
224
|
await self.create_task(self.connect())
|
206
225
|
|
207
226
|
def onConnected(self):
|
227
|
+
"当连接到服务器之后执行的操作。包括打印连接时间,执行自定义事件(若设置)等。"
|
208
228
|
now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
209
229
|
self.info(f"{now}: 已成功连接到服务器")
|
210
230
|
if isinstance(self.after_connect, str):
|
@@ -215,6 +235,7 @@ class Session:
|
|
215
235
|
event_connected(self)
|
216
236
|
|
217
237
|
def disconnect(self):
|
238
|
+
"断开到服务器的连接。"
|
218
239
|
if self.connected:
|
219
240
|
self.write_eof()
|
220
241
|
|
@@ -224,6 +245,7 @@ class Session:
|
|
224
245
|
# self.handle_save()
|
225
246
|
|
226
247
|
def onDisconnected(self, protocol):
|
248
|
+
"当从服务器连接断开时执行的操作。包括保存变量(若设置)、打印断开时间、执行自定义事件(若设置)等。"
|
227
249
|
# 断开时自动保存变量数据
|
228
250
|
if Settings.client["var_autosave"]:
|
229
251
|
self.handle_save()
|
@@ -241,8 +263,8 @@ class Session:
|
|
241
263
|
asyncio.ensure_future(self.reconnect(wait), loop = self.loop)
|
242
264
|
|
243
265
|
@property
|
244
|
-
def connected(self):
|
245
|
-
"
|
266
|
+
def connected(self) -> bool:
|
267
|
+
"只读属性,返回服务器端的连接状态"
|
246
268
|
if self._protocol:
|
247
269
|
con = self._protocol.connected
|
248
270
|
else:
|
@@ -251,8 +273,8 @@ class Session:
|
|
251
273
|
return con
|
252
274
|
|
253
275
|
@property
|
254
|
-
def duration(self):
|
255
|
-
"
|
276
|
+
def duration(self) -> float:
|
277
|
+
"只读属性,返回服务器端连接的时间,以秒为单位"
|
256
278
|
dura = 0
|
257
279
|
if self._protocol and self._protocol.connected:
|
258
280
|
dura = self._protocol.duration
|
@@ -261,6 +283,21 @@ class Session:
|
|
261
283
|
|
262
284
|
@property
|
263
285
|
def status_maker(self):
|
286
|
+
"""
|
287
|
+
可读写属性,会话状态窗口的内容生成器,应为一个可返回 `AnyFormattedText` 对象的不带额外参数的方法
|
288
|
+
|
289
|
+
示例:
|
290
|
+
.. code:: python
|
291
|
+
|
292
|
+
class Configuration:
|
293
|
+
def __init__(self, session):
|
294
|
+
self.session = session
|
295
|
+
self.session.status_maker = self.mystatus
|
296
|
+
|
297
|
+
def mystatus(self):
|
298
|
+
'可返回AnyFormattedText类型的对象。具体参见 prompt_toolkit 。'
|
299
|
+
return "this is a test status"
|
300
|
+
"""
|
264
301
|
return self._status_maker
|
265
302
|
|
266
303
|
@status_maker.setter
|
@@ -270,6 +307,20 @@ class Session:
|
|
270
307
|
|
271
308
|
@property
|
272
309
|
def event_connected(self):
|
310
|
+
"""
|
311
|
+
可读写属性,自定义的会话连接事件,应为一个带一个额外参数 Session 的方法
|
312
|
+
|
313
|
+
示例:
|
314
|
+
.. code:: Python
|
315
|
+
|
316
|
+
class Configuration:
|
317
|
+
def __init__(self, session):
|
318
|
+
self.session = session
|
319
|
+
self.session.event_connected = self.onSessionConnected
|
320
|
+
|
321
|
+
def onSessionConnected(self, session):
|
322
|
+
session.info("Connected!")
|
323
|
+
"""
|
273
324
|
return self._events["connected"]
|
274
325
|
|
275
326
|
@event_connected.setter
|
@@ -278,6 +329,11 @@ class Session:
|
|
278
329
|
|
279
330
|
@property
|
280
331
|
def event_disconnected(self):
|
332
|
+
"""
|
333
|
+
可读写属性,自定义的会话断开事件,应为一个带一个参数 Session 的方法
|
334
|
+
|
335
|
+
使用方法同 event_connected
|
336
|
+
"""
|
281
337
|
return self._events["disconnected"]
|
282
338
|
|
283
339
|
@event_disconnected.setter
|
@@ -285,51 +341,119 @@ class Session:
|
|
285
341
|
self._events["disconnected"] = event
|
286
342
|
|
287
343
|
@property
|
288
|
-
def modules(self):
|
289
|
-
"
|
344
|
+
def modules(self) -> OrderedDict:
|
345
|
+
"""
|
346
|
+
只读属性,返回本会话加载的所有模块,类型为顺序字典 OrderedDict
|
347
|
+
|
348
|
+
在字典中,关键字为模块名,值为模块本身与配置对象的二级字典,包含两个关键字, module 与 config
|
349
|
+
|
350
|
+
如,存在一个名为 my.py的模块文件,则加载后,session.modules['my'] 可以访问该模块有关信息。其中:
|
351
|
+
|
352
|
+
- `session.modules['my']['module']` 访问模块对象
|
353
|
+
- `session.modules['my']['config']` 访问该该模块文件中的Configuration类的实例(若有定义)
|
354
|
+
"""
|
290
355
|
return self._modules
|
291
356
|
|
292
357
|
@property
|
293
|
-
def plugins(self):
|
294
|
-
"
|
358
|
+
def plugins(self) -> DotDict:
|
359
|
+
"""
|
360
|
+
只读属性,为PYMUD插件的辅助点访问器
|
361
|
+
|
362
|
+
如,存在一个名为myplugin.py的插件文件并已正常加载,该文件中定义了 PLUGIN_NAME 为 "myplugin",则可以通过本属性及插件名访问该插件
|
363
|
+
|
364
|
+
.. code:: Python
|
365
|
+
|
366
|
+
plugin = session.plugins.myplugin # plugin为 Plugin类型的对象实例
|
367
|
+
"""
|
295
368
|
return self.application.plugins
|
296
369
|
|
297
370
|
@property
|
298
371
|
def vars(self):
|
299
|
-
"
|
372
|
+
"""
|
373
|
+
本会话内变量的辅助点访问器,可以通过vars+变量名快速访问该变量值
|
374
|
+
|
375
|
+
.. code:: Python
|
376
|
+
|
377
|
+
# 以下两个获取变量值的方法等价
|
378
|
+
exp = session.vars.exp
|
379
|
+
exp = session.getVariable('exp')
|
380
|
+
|
381
|
+
# 以下两个为变量赋值的方法等价
|
382
|
+
session.vars.exp = 10000
|
383
|
+
session.setVariable('exp', 10000)
|
384
|
+
"""
|
300
385
|
return self._variables
|
301
386
|
|
302
387
|
@property
|
303
388
|
def globals(self):
|
304
|
-
"
|
389
|
+
"""
|
390
|
+
全局变量的辅助点访问器,可以通过globals+变量名快速访问该变量值
|
391
|
+
|
392
|
+
全局变量与会话变量的区别在于,全局变量在所有会话之间是共享和统一的
|
393
|
+
|
394
|
+
.. code:: Python
|
395
|
+
|
396
|
+
# 以下两个获取全局变量值的方法等价
|
397
|
+
hooked = session.globals.hooked
|
398
|
+
hooked = session.getGlobal('hooked')
|
399
|
+
|
400
|
+
# 以下两个为全局变量赋值的方法等价
|
401
|
+
session.globals.hooked = True
|
402
|
+
session.setGlobal('hooked', True)
|
403
|
+
"""
|
305
404
|
return self.application.globals
|
306
405
|
|
307
406
|
@property
|
308
407
|
def tris(self):
|
309
|
-
"
|
408
|
+
"""
|
409
|
+
本会话的触发器的辅助点访问器,可以通过tris+触发器id快速访问触发器
|
410
|
+
|
411
|
+
.. code:: Python
|
412
|
+
|
413
|
+
session.tris.mytri.enabled = False
|
414
|
+
"""
|
310
415
|
return self._triggers
|
311
416
|
|
312
417
|
@property
|
313
418
|
def alis(self):
|
314
|
-
"
|
419
|
+
"""
|
420
|
+
本会话的别名辅助点访问器,可以通过alis+别名id快速访问别名
|
421
|
+
|
422
|
+
.. code:: Python
|
423
|
+
|
424
|
+
session.alis.myali.enabled = False
|
425
|
+
"""
|
315
426
|
return self._aliases
|
316
427
|
|
317
428
|
@property
|
318
429
|
def cmds(self):
|
319
|
-
"
|
430
|
+
"""
|
431
|
+
本会话的命令辅助点访问器,可以通过cmds+命令id快速访问命令
|
432
|
+
|
433
|
+
.. code:: Python
|
434
|
+
|
435
|
+
session.cmds.mycmd.enabled = False
|
436
|
+
"""
|
320
437
|
return self._commands
|
321
438
|
|
322
439
|
@property
|
323
440
|
def timers(self):
|
324
|
-
"
|
441
|
+
"""
|
442
|
+
本会话的定时器辅助点访问器,可以通过timers+定时器id快速访问定时器
|
443
|
+
|
444
|
+
.. code:: Python
|
445
|
+
|
446
|
+
session.timers.mytimer.enabled = False
|
447
|
+
"""
|
325
448
|
return self._timers
|
326
449
|
|
327
450
|
@property
|
328
451
|
def gmcp(self):
|
329
|
-
"
|
452
|
+
"本会话的GMCP辅助访问器"
|
330
453
|
return self._gmcp
|
331
454
|
|
332
455
|
def get_status(self):
|
456
|
+
"返回状态窗口内容的真实函数。 **脚本中无需调用。**"
|
333
457
|
text = f"这是一个默认的状态窗口信息\n会话: {self.name} 连接状态: {self.connected}"
|
334
458
|
if callable(self._status_maker):
|
335
459
|
text = self._status_maker()
|
@@ -337,7 +461,15 @@ class Session:
|
|
337
461
|
return text
|
338
462
|
|
339
463
|
def getPlainText(self, rawText: str, trim_newline = False) -> str:
|
340
|
-
"
|
464
|
+
"""
|
465
|
+
将带有VT100或者MXP转义字符的字符串转换为正常字符串(删除所有转义)。 **脚本中无需调用。**
|
466
|
+
|
467
|
+
:param rawText: 原始文本对象
|
468
|
+
:param trim_newline: 返回值是否删除末尾的回车符和换行符
|
469
|
+
|
470
|
+
:return: 经处理后的纯文本字符串
|
471
|
+
|
472
|
+
"""
|
341
473
|
plainText = self._esc_regx.sub("", rawText)
|
342
474
|
if trim_newline:
|
343
475
|
plainText = plainText.rstrip("\n").rstrip("\r")
|
@@ -345,7 +477,12 @@ class Session:
|
|
345
477
|
return plainText
|
346
478
|
|
347
479
|
def writetobuffer(self, data, newline = False):
|
348
|
-
"
|
480
|
+
"""
|
481
|
+
将数据写入到用于本地显示的缓冲中。 **脚本中无需调用。**
|
482
|
+
|
483
|
+
:param data: 写入的数据, 应为 str 类型
|
484
|
+
:param newline: 是否额外增加换行符
|
485
|
+
"""
|
349
486
|
self.buffer.insert_text(data)
|
350
487
|
|
351
488
|
if len(data) > 0 and (data[-1] == "\n"):
|
@@ -356,18 +493,29 @@ class Session:
|
|
356
493
|
self._line_count += 1
|
357
494
|
|
358
495
|
def clear_half(self):
|
359
|
-
"
|
496
|
+
"""
|
497
|
+
清除半数缓冲。 **脚本中无需调用。**
|
498
|
+
|
499
|
+
半数的数量由 Settings.client['buffer_lines'] 确定,默认为5000行。
|
500
|
+
"""
|
360
501
|
if (self._line_count >= 2 * Settings.client["buffer_lines"]) and self.buffer.document.is_cursor_at_the_end:
|
361
502
|
self._line_count = self.buffer.clear_half()
|
362
503
|
|
363
504
|
def feed_data(self, data) -> None:
|
364
|
-
"
|
505
|
+
"""
|
506
|
+
由协议对象调用,将收到的远程数据加入会话缓冲。永远只会传递1个字节的数据,以bytes形式。 **脚本中无需调用。**
|
507
|
+
|
508
|
+
:param data: 传入的数据, bytes 格式
|
509
|
+
"""
|
365
510
|
self._line_buffer.extend(data)
|
366
511
|
|
367
512
|
if (len(data) == 1) and (data[0] == ord("\n")):
|
368
513
|
self.go_ahead()
|
369
514
|
|
370
515
|
def feed_eof(self) -> None:
|
516
|
+
"""
|
517
|
+
由协议对象调用,处理收到远程 eof 数据,即远程断开连接。 **脚本中无需调用。**
|
518
|
+
"""
|
371
519
|
self._eof = True
|
372
520
|
if self.connected:
|
373
521
|
self._transport.write_eof()
|
@@ -375,6 +523,16 @@ class Session:
|
|
375
523
|
self.log.info(f"服务器断开连接! {self._protocol.__repr__}")
|
376
524
|
|
377
525
|
def feed_gmcp(self, name, value) -> None:
|
526
|
+
"""
|
527
|
+
由协议对象调用,处理收到远程 GMCP 数据。 **脚本中无需调用。**
|
528
|
+
|
529
|
+
:param name: 收到的GMCP数据的 name
|
530
|
+
:param value: 收到的GMCP数据的 value。 该数据值类型为 字符串形式执行过eval后的结果
|
531
|
+
|
532
|
+
**注** 当未通过GMCPTrigger对某个name的GMCP数据进行处理时,会通过session.info将该GMCP数据打印出来以供调试。
|
533
|
+
当已有GMCPTrigger处理该name的GMCP数据时,则不会再打印此信息。
|
534
|
+
"""
|
535
|
+
|
378
536
|
nothandle = True
|
379
537
|
if name in self._gmcp.keys():
|
380
538
|
gmcp = self._gmcp[name]
|
@@ -386,13 +544,32 @@ class Session:
|
|
386
544
|
self.info(f"{name}: {value}", "GMCP")
|
387
545
|
|
388
546
|
def feed_msdp(self, name, value) -> None:
|
547
|
+
"""
|
548
|
+
由协议对象调用,处理收到远程 MSDP 数据。 **脚本中无需调用。**
|
549
|
+
|
550
|
+
:param name: 收到的MSDP数据的 name
|
551
|
+
:param value: 收到的MSDP数据的 value
|
552
|
+
|
553
|
+
**注** 由于北大侠客行不支持MSDP,因此该函数体并未实现
|
554
|
+
"""
|
389
555
|
pass
|
390
556
|
|
391
557
|
def feed_mssp(self, name, value) -> None:
|
392
|
-
|
558
|
+
"""
|
559
|
+
由协议对象调用,处理收到远程 MSSP 数据。 **脚本中无需调用。**
|
560
|
+
|
561
|
+
:param name: 收到的MSSP数据的 name
|
562
|
+
:param value: 收到的MSSP数据的 value
|
563
|
+
|
564
|
+
**注** 由于北大侠客行不支持MSSP,因此该函数体并未实现
|
565
|
+
"""
|
393
566
|
|
394
567
|
def go_ahead(self) -> None:
|
395
|
-
"
|
568
|
+
"""
|
569
|
+
对当前接收缓冲内容进行处理并放到显示缓冲中。 **脚本中无需调用。**
|
570
|
+
|
571
|
+
触发器的响应在该函数中进行处理。
|
572
|
+
"""
|
396
573
|
raw_line = self._line_buffer.decode(self.encoding, Settings.server["encoding_errors"])
|
397
574
|
tri_line = self.getPlainText(raw_line, trim_newline = True)
|
398
575
|
self._line_buffer.clear()
|
@@ -441,43 +618,88 @@ class Session:
|
|
441
618
|
self.writetobuffer(self.display_line)
|
442
619
|
|
443
620
|
def set_exception(self, exc: Exception):
|
621
|
+
"""
|
622
|
+
由协议对象调用,处理异常。 **脚本中无需调用。**
|
623
|
+
|
624
|
+
:param exc: 异常对象
|
625
|
+
"""
|
444
626
|
self.error(f"连接过程中发生异常,异常信息为: {exc}")
|
445
|
-
|
627
|
+
|
446
628
|
|
447
629
|
def create_task(self, coro, *args, name: str = None) -> asyncio.Task:
|
630
|
+
"""
|
631
|
+
创建一个任务,并将其加入到会话的任务管理队列中。
|
632
|
+
|
633
|
+
加入会话管理的任务,在任务完成(结束或中止)后,会自动从管理队列中移除。
|
634
|
+
|
635
|
+
:param coro: 一个async定义的协程对象或者其他可等待对象
|
636
|
+
:param name: 任务的名称定义,可选项。该属性仅在3.10及以后的Python版本中支持
|
637
|
+
|
638
|
+
示例:
|
639
|
+
.. code:: Python
|
640
|
+
|
641
|
+
class Configuration:
|
642
|
+
def __init__(self, session):
|
643
|
+
self.session = session
|
644
|
+
self.session.create_task(self.async_example())
|
645
|
+
|
646
|
+
async def async_example(self):
|
647
|
+
await asyncio.sleep(1)
|
648
|
+
self.session.info("show a message after 1 second")
|
649
|
+
"""
|
448
650
|
if self.pyversion in ["3.7", "3.8", "3.9"]:
|
449
651
|
task = self.loop.create_task(coro)
|
450
|
-
#task = asyncio.create_task(coro)
|
451
652
|
else:
|
452
653
|
task = self.loop.create_task(coro, name = name)
|
453
|
-
|
654
|
+
|
454
655
|
task.add_done_callback(self._tasks.discard)
|
455
656
|
self._tasks.add(task)
|
456
|
-
|
657
|
+
|
457
658
|
return task
|
458
659
|
|
459
660
|
def remove_task(self, task: asyncio.Task, msg = None):
|
661
|
+
"""
|
662
|
+
清除一个受本会话管理的任务。若任务未完成,则取消该任务。
|
663
|
+
|
664
|
+
由于加入会话管理的任务,在任务完成后会自动从管理队列中移除,因此该方法主要用来取消未完成的任务。
|
665
|
+
|
666
|
+
:param task: 由本会话管理的一个 asyncio.Task 对象
|
667
|
+
:param msg: 本意是用来反馈 task.cancel() 时的消息,但为了保持兼容低版本Python环境,该参数并未使用。
|
668
|
+
"""
|
460
669
|
result = task.cancel()
|
461
670
|
self._tasks.discard(task)
|
462
|
-
|
463
|
-
# self._tasks.remove(task)
|
671
|
+
|
464
672
|
return result
|
465
673
|
|
466
674
|
def clean_finished_tasks(self):
|
467
|
-
|
468
|
-
|
675
|
+
# 清理已经完成的任务。
|
676
|
+
# 自PyMUD 0.19.2post2版之后,清理完成任务在该任务完成时刻自动调用,因此本函数不再使用,保留的目的是为了向前兼容。
|
469
677
|
|
470
|
-
|
471
|
-
# if isinstance(task, asyncio.Task) and task.done():
|
472
|
-
# self._tasks.remove(task)
|
678
|
+
self._tasks = set([t for t in self._tasks if not t.done()])
|
473
679
|
|
474
680
|
def write(self, data) -> None:
|
475
|
-
"
|
681
|
+
"""
|
682
|
+
向服务器写入数据(RAW格式字节数组/字节串)。 **一般不应在脚本中直接调用。**
|
683
|
+
|
684
|
+
:param data: 向传输中写入的数据, 应为 bytes, bytearray, memoryview 类型
|
685
|
+
"""
|
476
686
|
if self._transport and not self._transport.is_closing():
|
477
687
|
self._transport.write(data)
|
478
688
|
|
479
689
|
def writeline(self, line: str) -> None:
|
480
|
-
"
|
690
|
+
"""
|
691
|
+
向服务器中写入一行,用于向服务器写入不经别名或命令解析时的数据。将自动在行尾添加换行符。
|
692
|
+
|
693
|
+
- 如果line中包含分隔符(由Settings.client.seperator指定,默认为半角分号;)的多个命令,将逐行依次写入。
|
694
|
+
- 当 Settings.cleint["echo_input"] 为真时,向服务器写入的内容同时在本地缓冲中回显。
|
695
|
+
|
696
|
+
:param line: 字符串行内容
|
697
|
+
|
698
|
+
示例:
|
699
|
+
.. code:: Python
|
700
|
+
|
701
|
+
session.writeline("open door")
|
702
|
+
"""
|
481
703
|
if self.seperator in line:
|
482
704
|
lines = line.split(self.seperator)
|
483
705
|
for ln in lines:
|
@@ -497,8 +719,22 @@ class Session:
|
|
497
719
|
|
498
720
|
def exec(self, cmd: str, name = None, *args, **kwargs):
|
499
721
|
"""
|
500
|
-
在名称为name的会话中使用exec_command执行MUD
|
501
|
-
|
722
|
+
在名称为name的会话中使用exec_command执行MUD命令。当不指定name时,在当前会话中执行。
|
723
|
+
|
724
|
+
- exec 与 writeline 都会向服务器写入数据。其差异在于,exec执行的内容,会先经过Alias处理和Command处理,实际向远程发送内容与cmd可以不一致。
|
725
|
+
- exec 在内部通过调用 exec_command 实现, exec 可以实现与 exec_command 完全相同的功能
|
726
|
+
- exec 是后来增加的函数,因此保留 exec_command 的目的是为了脚本的向前兼容
|
727
|
+
|
728
|
+
:param cmd: 要执行的命令
|
729
|
+
:param name: 要执行命令的会话的名称,当不指定时,在当前会话执行。
|
730
|
+
:param args: 保留兼容与扩展性所需,脚本中调用时无需指定
|
731
|
+
:param kwargs: 保留兼容与扩展性所需,脚本中调用时无需指定
|
732
|
+
|
733
|
+
示例:
|
734
|
+
.. code:: Python
|
735
|
+
|
736
|
+
session.addAlias(SimpleAlias(self.session, "^cb\s(\S+)\s(\S+)", "#3 get %1 from jinnang;#wa 250;combine gem;#wa 250;pack gem", id = "ali_combine"))
|
737
|
+
session.exec("cb j1a")
|
502
738
|
"""
|
503
739
|
name = name or self.name
|
504
740
|
if name in self.application.sessions.keys():
|
@@ -507,10 +743,32 @@ class Session:
|
|
507
743
|
else:
|
508
744
|
self.error(f"不存在名称为{name}的会话")
|
509
745
|
|
746
|
+
async def exec_async(self, cmd: str, name = None, *args, **kwargs):
|
747
|
+
"""
|
748
|
+
exec的异步形式。在名称为name的会话中使用exec_command_async执行MUD命令。当不指定name时,在当前会话中执行。
|
749
|
+
|
750
|
+
- exec_async 在内部通过调用 exec_command_async 实现, exec_async 可以实现与 exec_command_async 完全相同的功能
|
751
|
+
- exec_async 是后来增加的函数,因此保留 exec_command_async 的目的是为了脚本的向前兼容
|
752
|
+
- 异步调用时,该函数要等待对应的代码执行完毕后才会返回。可以用于确保命令执行完毕。
|
753
|
+
"""
|
754
|
+
name = name or self.name
|
755
|
+
if name in self.application.sessions.keys():
|
756
|
+
session = self.application.sessions[name]
|
757
|
+
await session.exec_command_async(cmd, *args, **kwargs)
|
758
|
+
else:
|
759
|
+
self.error(f"不存在名称为{name}的会话")
|
760
|
+
|
761
|
+
|
762
|
+
|
510
763
|
def exec_code(self, cl: CodeLine, *args, **kwargs):
|
511
764
|
"""
|
512
|
-
执行解析为CodeLine形式的MUD
|
513
|
-
|
765
|
+
执行解析为CodeLine形式的MUD命令(必定为单个命令)。一般情况下,脚本中不应调用该方法,而应使用exec/exec_command。
|
766
|
+
|
767
|
+
这是命令执行的最核心执行函数,所有真实调用的起源(同步调用情况下)
|
768
|
+
|
769
|
+
:param cl: CodeLine形式的执行代码
|
770
|
+
:param args: 保留兼容与扩展性所需
|
771
|
+
:param kwargs: 保留兼容与扩展性所需
|
514
772
|
"""
|
515
773
|
if cl.length == 0:
|
516
774
|
self.writeline("")
|
@@ -565,8 +823,15 @@ class Session:
|
|
565
823
|
|
566
824
|
async def exec_code_async(self, cl: CodeLine, *args, **kwargs):
|
567
825
|
"""
|
568
|
-
|
569
|
-
|
826
|
+
该方法为exec_code的异步形式实现。一般情况下,脚本中不应调用该方法,而应使用 exec_command_async。
|
827
|
+
|
828
|
+
这是命令执行的最核心执行函数,所有真实调用的起源(异步调用情况下)。
|
829
|
+
|
830
|
+
异步调用时,该函数要等待对应的代码执行完毕后才会返回。可以用于确保命令执行完毕。
|
831
|
+
|
832
|
+
:param cl: CodeLine形式的执行代码
|
833
|
+
:param args: 保留兼容与扩展性所需
|
834
|
+
:param kwargs: 保留兼容与扩展性所需
|
570
835
|
"""
|
571
836
|
if cl.length == 0:
|
572
837
|
self.writeline("")
|
@@ -606,7 +871,7 @@ class Session:
|
|
606
871
|
handler = self._cmds_handler.get(cmd, None)
|
607
872
|
if handler and callable(handler):
|
608
873
|
if asyncio.iscoroutinefunction(handler):
|
609
|
-
await handler(code = cl, *args, **kwargs)
|
874
|
+
await self.create_task(handler(code = cl, *args, **kwargs))
|
610
875
|
else:
|
611
876
|
handler(code = cl, *args, **kwargs)
|
612
877
|
else:
|
@@ -618,7 +883,11 @@ class Session:
|
|
618
883
|
|
619
884
|
def exec_text(self, cmdtext: str):
|
620
885
|
"""
|
621
|
-
执行文本形式的MUD
|
886
|
+
执行文本形式的MUD命令。必定为单个命令,且确定不是#开头的,同时不进行参数替代
|
887
|
+
|
888
|
+
一般情况下,脚本中不应调用该方法,而应使用 exec/exec_command。
|
889
|
+
|
890
|
+
:param cmdtext: 纯文本命令
|
622
891
|
"""
|
623
892
|
isNotCmd = True
|
624
893
|
for command in self._commands.values():
|
@@ -644,9 +913,13 @@ class Session:
|
|
644
913
|
if notAlias:
|
645
914
|
self.writeline(cmdtext)
|
646
915
|
|
647
|
-
# self.clean_finished_tasks()
|
648
|
-
|
649
916
|
async def exec_text_async(self, cmdtext: str):
|
917
|
+
"""
|
918
|
+
该方法为 exec_text 的异步形式实现。一般情况下,脚本中不应调用该方法,而应使用 exec_async/exec_command_async。
|
919
|
+
|
920
|
+
异步调用时,该函数要等待对应的代码执行完毕后才会返回。可以用于确保命令执行完毕。
|
921
|
+
"""
|
922
|
+
|
650
923
|
isNotCmd = True
|
651
924
|
for command in self._commands.values():
|
652
925
|
if isinstance(command, Command) and command.enabled:
|
@@ -673,10 +946,18 @@ class Session:
|
|
673
946
|
|
674
947
|
def exec_command(self, line: str, *args, **kwargs) -> None:
|
675
948
|
"""
|
676
|
-
|
677
|
-
|
678
|
-
|
679
|
-
|
949
|
+
在当前会话中执行MUD命令。多个命令可以用分隔符隔开。
|
950
|
+
|
951
|
+
- 此函数中,多个命令是一次性发送到服务器的,并未进行等待确认上一条命令执行完毕。
|
952
|
+
- 若要等待每一个命令执行完毕后再进行下一个命令,则应使用本函数的异步形式 exec_command_async
|
953
|
+
- 本函数和writeline的区别在于,本函数会先进行Command和Alias解析,若不是再使用writeline发送
|
954
|
+
- 当line不包含Command和Alias时,等同于writeline
|
955
|
+
- 本函数使用方法与 exec 相同,差异在于不能指定会话名
|
956
|
+
- exec 是后来增加的函数,因此保留 exec_command 的目的是为了脚本的向前兼容
|
957
|
+
|
958
|
+
:param line: 需指定的内容
|
959
|
+
:param args: 保留兼容性与扩展性需要
|
960
|
+
:param kwargs: 保留兼容性与扩展性需要
|
680
961
|
"""
|
681
962
|
|
682
963
|
## 以下为函数执行本体
|
@@ -690,7 +971,12 @@ class Session:
|
|
690
971
|
cb.execute(self)
|
691
972
|
|
692
973
|
def exec_command_after(self, wait: float, line: str):
|
693
|
-
"
|
974
|
+
"""
|
975
|
+
延时一段时间之后,执行命令exec_command
|
976
|
+
|
977
|
+
:param wait: float, 延时等待时间,单位为秒。
|
978
|
+
:param line: str, 延时等待结束后执行的内容
|
979
|
+
"""
|
694
980
|
async def delay_task():
|
695
981
|
await asyncio.sleep(wait)
|
696
982
|
self.exec_command(line)
|
@@ -699,8 +985,12 @@ class Session:
|
|
699
985
|
|
700
986
|
async def exec_command_async(self, line: str, *args, **kwargs):
|
701
987
|
"""
|
702
|
-
|
703
|
-
|
988
|
+
exec_command 的异步形式。在当前会话中执行MUD命令。多个命令可以用分隔符隔开。
|
989
|
+
|
990
|
+
- 异步时,多个命令是逐个发送到服务器的,每一命令都等待确认上一条命令执行完毕,且多命令之间会插入一定时间等待
|
991
|
+
- 多个命令之间的间隔等待时间由 Settings.client["interval"] 指定,单位为 ms
|
992
|
+
- 本函数使用方法与 exec_async 相同,差异在于不能指定会话名
|
993
|
+
- exec_async 是后来增加的函数,因此保留 exec_command_async 的目的是为了脚本的向前兼容
|
704
994
|
"""
|
705
995
|
|
706
996
|
## 以下为函数执行本体
|
@@ -715,19 +1005,39 @@ class Session:
|
|
715
1005
|
await cb.async_execute(self)
|
716
1006
|
|
717
1007
|
def write_eof(self) -> None:
|
1008
|
+
"""
|
1009
|
+
向服务器发送 eof 信息,即与服务器断开连接。 **脚本中无需调用。**
|
1010
|
+
|
1011
|
+
若要在脚本中控制断开与服务器的连接,请使用 session.disconnect()
|
1012
|
+
"""
|
718
1013
|
self._transport.write_eof()
|
719
1014
|
|
720
1015
|
def getUniqueNumber(self):
|
721
|
-
"
|
1016
|
+
"""
|
1017
|
+
获取本session中的唯一数值。该方法用来为各类对象生成随机不重复ID
|
1018
|
+
|
1019
|
+
:return: 返回为整数,返回结果在本会话中唯一。
|
1020
|
+
"""
|
722
1021
|
self._uid += 1
|
723
1022
|
return self._uid
|
724
1023
|
|
725
1024
|
def getUniqueID(self, prefix):
|
726
|
-
"
|
1025
|
+
"""
|
1026
|
+
根据唯一编号获取本session中的唯一名称, 格式为: prefix_uid
|
1027
|
+
|
1028
|
+
:param prefix: 为唯一数值增加的前缀
|
1029
|
+
:return: 形式为 prefix_uid 的唯一标识
|
1030
|
+
"""
|
727
1031
|
return "{0}_{1}".format(prefix, self.getUniqueNumber())
|
728
1032
|
|
729
1033
|
def enableGroup(self, group: str, enabled = True):
|
730
|
-
"
|
1034
|
+
"""
|
1035
|
+
使能或禁用Group中所有对象, 返回组内各对象个数。
|
1036
|
+
|
1037
|
+
:param group: 组名,即各对象的 group 属性的值
|
1038
|
+
:param enabled: 使能/禁用开关。为True时表示使能, False为禁用
|
1039
|
+
:return: 5个整数的列表,依次表示改组内操作的 别名,触发器,命令,定时器,GMCP 的个数
|
1040
|
+
"""
|
731
1041
|
counts = [0, 0, 0, 0, 0]
|
732
1042
|
for ali in self._aliases.values():
|
733
1043
|
if isinstance(ali, Alias) and (ali.group == group):
|
@@ -800,59 +1110,158 @@ class Session:
|
|
800
1110
|
self._delObject(id, cls)
|
801
1111
|
|
802
1112
|
def addAliases(self, alis: dict):
|
803
|
-
"
|
1113
|
+
"""
|
1114
|
+
向会话中增加多个别名
|
1115
|
+
|
1116
|
+
:param alis: 多个别名的字典。字典 key 应为每个别名的 id。
|
1117
|
+
|
1118
|
+
示例:
|
1119
|
+
.. code:: Python
|
1120
|
+
|
1121
|
+
class Configuration:
|
1122
|
+
def __init__(self, session):
|
1123
|
+
self.session = session
|
1124
|
+
self._aliases = dict()
|
1125
|
+
|
1126
|
+
self._initAliases()
|
1127
|
+
|
1128
|
+
def _initAliases(self):
|
1129
|
+
self._aliases['my_ali1'] = SimpleAlias(self.session, "n", "north", id = "my_ali1")
|
1130
|
+
self._aliases['my_ali2'] = SimpleAlias(self.session, "s", "south", id = "my_ali2")
|
1131
|
+
self.session.addAliases(self._aliases)
|
1132
|
+
"""
|
804
1133
|
self._addObjects(alis, Alias)
|
805
1134
|
|
806
1135
|
def addCommands(self, cmds: dict):
|
807
|
-
"
|
1136
|
+
"""
|
1137
|
+
向会话中增加多个命令。使用方法与 addAliases 类似。
|
1138
|
+
|
1139
|
+
:param cmds: 多个命令的字典。字典 key 应为每个命令的 id。
|
1140
|
+
"""
|
808
1141
|
self._addObjects(cmds, Command)
|
809
1142
|
|
810
1143
|
def addTriggers(self, tris: dict):
|
811
|
-
"
|
1144
|
+
"""
|
1145
|
+
向会话中增加多个触发器。使用方法与 addAliases 类似。
|
1146
|
+
|
1147
|
+
:param tris: 多个触发器的字典。字典 key 应为每个触发器的 id。
|
1148
|
+
"""
|
812
1149
|
self._addObjects(tris, Trigger)
|
813
1150
|
|
814
1151
|
def addGMCPs(self, gmcps: dict):
|
815
|
-
"
|
1152
|
+
"""
|
1153
|
+
向会话中增加多个GMCPTrigger。使用方法与 addAliases 类似。
|
1154
|
+
|
1155
|
+
:param gmcps: 多个GMCPTrigger的字典。字典 key 应为每个GMCPTrigger的 id。
|
1156
|
+
"""
|
816
1157
|
self._addObjects(gmcps, GMCPTrigger)
|
817
1158
|
|
818
1159
|
def addTimers(self, tis: dict):
|
819
|
-
"
|
1160
|
+
"""
|
1161
|
+
向会话中增加多个定时器。使用方法与 addAliases 类似。
|
1162
|
+
|
1163
|
+
:param tis: 多个定时器的字典。字典 key 应为每个定时器的 id。
|
1164
|
+
"""
|
820
1165
|
self._addObjects(tis, Timer)
|
821
1166
|
|
822
1167
|
def addAlias(self, ali: Alias):
|
823
|
-
"
|
1168
|
+
"""
|
1169
|
+
向会话中增加一个别名。
|
1170
|
+
|
1171
|
+
:param ali: 要增加的别名对象,应为 Alias 类型或其子类
|
1172
|
+
"""
|
824
1173
|
self._addObject(ali, Alias)
|
825
1174
|
|
826
1175
|
def addCommand(self, cmd: Command):
|
827
|
-
"
|
1176
|
+
"""
|
1177
|
+
向会话中增加一个命令。
|
1178
|
+
|
1179
|
+
:param cmd: 要增加的命令对象,应为 Command 类型或其子类
|
1180
|
+
"""
|
828
1181
|
self._addObject(cmd, Command)
|
829
1182
|
|
830
1183
|
def addTrigger(self, tri: Trigger):
|
831
|
-
"
|
1184
|
+
"""
|
1185
|
+
向会话中增加一个触发器。
|
1186
|
+
|
1187
|
+
:param tri: 要增加的触发器对象,应为 Trigger 类型或其子类
|
1188
|
+
"""
|
832
1189
|
self._addObject(tri, Trigger)
|
833
1190
|
|
834
1191
|
def addTimer(self, ti: Timer):
|
835
|
-
"
|
1192
|
+
"""
|
1193
|
+
向会话中增加一个定时器。
|
1194
|
+
|
1195
|
+
:param ti: 要增加的定时器对象,应为 Timer 类型或其子类
|
1196
|
+
"""
|
836
1197
|
self._addObject(ti, Timer)
|
837
1198
|
|
838
1199
|
def addGMCP(self, gmcp: GMCPTrigger):
|
839
|
-
"
|
1200
|
+
"""
|
1201
|
+
向会话中增加一个GMCP触发器。
|
1202
|
+
|
1203
|
+
:param gmcp: 要增加的GMCP触发器对象,应为 GMCPTrigger 类型或其子类
|
1204
|
+
"""
|
1205
|
+
|
840
1206
|
self._addObject(gmcp, GMCPTrigger)
|
841
1207
|
|
842
1208
|
def delAlias(self, ali):
|
843
|
-
"
|
1209
|
+
"""
|
1210
|
+
从会话中移除一个别名,可接受 Alias 对象或其 id
|
1211
|
+
|
1212
|
+
:param ali: 要删除的别名指代,可以为别名 id 或者别名自身
|
1213
|
+
|
1214
|
+
示例:
|
1215
|
+
.. code:: Python
|
1216
|
+
|
1217
|
+
class Configuration:
|
1218
|
+
def __init__(self, session):
|
1219
|
+
self.session = session
|
1220
|
+
|
1221
|
+
ali = Alias(session, "s", "south", id = "my_ali1")
|
1222
|
+
session.addAlias(ali)
|
1223
|
+
|
1224
|
+
# 以下两行语句均可以删除该别名
|
1225
|
+
session.delAlias("my_ali1")
|
1226
|
+
session.delAlias(ali)
|
1227
|
+
"""
|
844
1228
|
if isinstance(ali, Alias):
|
845
1229
|
self._delObject(ali.id, Alias)
|
846
1230
|
elif isinstance(ali, str) and (ali in self._aliases.keys()):
|
847
1231
|
self._delObject(ali, Alias)
|
848
1232
|
|
849
1233
|
def delAliases(self, ali_es: Iterable):
|
850
|
-
"
|
1234
|
+
"""
|
1235
|
+
从会话中移除一组别名,可接受 Alias 对象或其 id 的迭代器
|
1236
|
+
|
1237
|
+
:param ali_es: 要删除的一组别名指代,可以为别名 id 或者别名自身的列表
|
1238
|
+
|
1239
|
+
示例:
|
1240
|
+
.. code:: Python
|
1241
|
+
|
1242
|
+
class Configuration:
|
1243
|
+
def __init__(self, session):
|
1244
|
+
self.session = session
|
1245
|
+
self._aliases = dict()
|
1246
|
+
|
1247
|
+
self._aliases["my_ali1"] = Alias(session, "s", "south", id = "my_ali1")
|
1248
|
+
self._aliases["my_ali2"] = Alias(session, "n", "north", id = "my_ali2")
|
1249
|
+
|
1250
|
+
session.addAliases(self._aliase)
|
1251
|
+
|
1252
|
+
# 以下两行语句均可以删除两个别名
|
1253
|
+
session.delAliases(self._aliases)
|
1254
|
+
session.delAliases(self._aliases.keys())
|
1255
|
+
"""
|
851
1256
|
for ali in ali_es:
|
852
1257
|
self.delAlias(ali)
|
853
1258
|
|
854
1259
|
def delCommand(self, cmd):
|
855
|
-
"
|
1260
|
+
"""
|
1261
|
+
从会话中移除一个命令,可接受 Command 对象或其 id。使用方法与 delAlias 类似
|
1262
|
+
|
1263
|
+
:param cmd: 要删除的命令指代,可以为命令id或者命令自身
|
1264
|
+
"""
|
856
1265
|
if isinstance(cmd, Command):
|
857
1266
|
cmd.reset()
|
858
1267
|
self._delObject(cmd.id, Command)
|
@@ -861,24 +1270,42 @@ class Session:
|
|
861
1270
|
self._delObject(cmd, Command)
|
862
1271
|
|
863
1272
|
def delCommands(self, cmd_s: Iterable):
|
864
|
-
"
|
1273
|
+
"""
|
1274
|
+
从会话中移除一组命令,可接受可接受 Command 对象或其 id 的迭代器。使用方法与 delAliases 类似
|
1275
|
+
|
1276
|
+
:param cmd_s: 要删除的命令指代,可以为命令 id 或者命令自身的列表
|
1277
|
+
"""
|
865
1278
|
for cmd in cmd_s:
|
866
1279
|
self.delCommand(cmd)
|
867
1280
|
|
868
1281
|
def delTrigger(self, tri):
|
869
|
-
"
|
1282
|
+
"""
|
1283
|
+
从会话中移除一个触发器,可接受 Trigger 对象或其的id。使用方法与 delAlias 类似
|
1284
|
+
|
1285
|
+
:param tri: 要删除的触发器指代,可以为触发器 id 或者触发器自身
|
1286
|
+
"""
|
1287
|
+
|
870
1288
|
if isinstance(tri, Trigger):
|
871
1289
|
self._delObject(tri.id, Trigger)
|
872
1290
|
elif isinstance(tri, str) and (tri in self._triggers.keys()):
|
873
1291
|
self._delObject(tri, Trigger)
|
874
1292
|
|
875
1293
|
def delTriggers(self, tri_s: Iterable):
|
876
|
-
"
|
1294
|
+
"""
|
1295
|
+
从会话中移除一组触发器,可接受可接受 Trigger 对象或其 id 的迭代器。使用方法与 delAliases 类似
|
1296
|
+
|
1297
|
+
:param tri_s: 要删除的触发器指代,可以为触发器 id 或者触发器自身的列表
|
1298
|
+
"""
|
877
1299
|
for tri in tri_s:
|
878
1300
|
self.delTrigger(tri)
|
879
1301
|
|
880
1302
|
def delTimer(self, ti):
|
881
|
-
"
|
1303
|
+
"""
|
1304
|
+
从会话中移除一个定时器,可接受 Timer 对象或其的id。使用方法与 delAlias 类似
|
1305
|
+
|
1306
|
+
:param ti: 要删除的定时器指代,可以为定时器 id 或者定时器自身
|
1307
|
+
"""
|
1308
|
+
|
882
1309
|
if isinstance(ti, Timer):
|
883
1310
|
ti.enabled = False
|
884
1311
|
self._delObject(ti.id, Timer)
|
@@ -887,24 +1314,40 @@ class Session:
|
|
887
1314
|
self._delObject(ti, Timer)
|
888
1315
|
|
889
1316
|
def delTimers(self, ti_s: Iterable):
|
890
|
-
"
|
1317
|
+
"""
|
1318
|
+
从会话中移除一组定时器,可接受可接受 Timer 对象或其 id 的迭代器。使用方法与 delAliases 类似
|
1319
|
+
|
1320
|
+
:param ti_s: 要删除的定时器指代,可以为定时器 id 或者定时器自身的列表
|
1321
|
+
"""
|
891
1322
|
for ti in ti_s:
|
892
1323
|
self.delTimer(ti)
|
893
1324
|
|
894
1325
|
def delGMCP(self, gmcp: GMCPTrigger):
|
895
|
-
"
|
1326
|
+
"""
|
1327
|
+
从会话中移除一个GMCP触发器,可接受 GMCPTrigger 对象或其的id。使用方法与 delAlias 类似
|
1328
|
+
|
1329
|
+
:param gmcp: 要删除的GMCP触发器指代,可以为GMCP触发器 id 或者GMCP触发器自身
|
1330
|
+
"""
|
896
1331
|
if isinstance(gmcp, GMCPTrigger):
|
897
1332
|
self._delObject(gmcp.id, GMCPTrigger)
|
898
1333
|
elif isinstance(gmcp, str) and (gmcp in self._gmcp.keys()):
|
899
1334
|
self._delObject(gmcp, GMCPTrigger)
|
900
1335
|
|
901
1336
|
def delGMCPs(self, gmcp_s: Iterable):
|
902
|
-
"
|
1337
|
+
"""
|
1338
|
+
从会话中移除一组GMCP触发器,可接受可接受 GMCPTrigger 对象或其 id 的迭代器。使用方法与 delAliases 类似
|
1339
|
+
|
1340
|
+
:param gmcp_s: 要删除的GMCP触发器指代,可以为 id 或者GMCP触发器自身的列表
|
1341
|
+
"""
|
903
1342
|
for gmcp in gmcp_s:
|
904
1343
|
self.delGMCP(gmcp)
|
905
1344
|
|
906
1345
|
def replace(self, newstr):
|
907
|
-
"
|
1346
|
+
"""
|
1347
|
+
将当前行内容显示替换为newstr。该方法仅在用于触发器的同步处置中才能正确相应
|
1348
|
+
|
1349
|
+
:param newstr: 替换后的内容
|
1350
|
+
"""
|
908
1351
|
if len(newstr) > 0:
|
909
1352
|
newstr += Settings.client["newline"]
|
910
1353
|
self.display_line = newstr
|
@@ -914,23 +1357,66 @@ class Session:
|
|
914
1357
|
## 变量 Variables 处理
|
915
1358
|
## ###################
|
916
1359
|
def delVariable(self, name):
|
917
|
-
"""
|
1360
|
+
"""
|
1361
|
+
删除一个变量。删除变量是从session管理的变量列表中移除关键字,而不是设置为 None
|
1362
|
+
|
1363
|
+
:param name: 变量名
|
1364
|
+
"""
|
918
1365
|
assert isinstance(name, str), "name必须是一个字符串"
|
919
1366
|
if name in self._variables.keys():
|
920
1367
|
self._variables.pop(name)
|
921
1368
|
|
922
1369
|
def setVariable(self, name, value):
|
923
|
-
"""
|
1370
|
+
"""
|
1371
|
+
设置一个变量的值。可以使用vars快捷点访问器实现同样效果。
|
1372
|
+
|
1373
|
+
:param name: 变量名。变量名必须为一个字符串
|
1374
|
+
:param value: 变量的值。变量值可以为任意 Python 类型。但为了要保存变量数据到硬盘,建议使用可序列化类型。
|
1375
|
+
|
1376
|
+
示例:
|
1377
|
+
.. code:: Python
|
1378
|
+
|
1379
|
+
# 以下两种方式等价
|
1380
|
+
session.setVariable("myvar1", "the value")
|
1381
|
+
session.vars.myvar1 = "the value"
|
1382
|
+
"""
|
924
1383
|
assert isinstance(name, str), "name必须是一个字符串"
|
925
1384
|
self._variables[name] = value
|
926
1385
|
|
927
1386
|
def getVariable(self, name, default = None):
|
1387
|
+
"""
|
1388
|
+
获取一个变量的值。可以使用vars快捷点访问器实现类似效果,但vars访问时,默认值总为None。
|
1389
|
+
|
1390
|
+
:param name: 变量名。变量名必须为一个字符串
|
1391
|
+
:param default: 当会话中不存在该变量时,返回的值。默认为 None。
|
1392
|
+
:return: 变量的值,或者 default
|
1393
|
+
|
1394
|
+
示例:
|
1395
|
+
.. code:: Python
|
1396
|
+
|
1397
|
+
# 以下两种方式等价
|
1398
|
+
myvar = session.getVariable("myvar1", None)
|
1399
|
+
myvar = session.vars.myvar1
|
1400
|
+
"""
|
928
1401
|
"""获取一个变量的值. 当name指定的变量不存在时,返回default"""
|
929
1402
|
assert isinstance(name, str), "name必须是一个字符串"
|
930
1403
|
return self._variables.get(name, default)
|
931
1404
|
|
932
1405
|
def setVariables(self, names, values):
|
933
|
-
"""
|
1406
|
+
"""
|
1407
|
+
同时设置一组变量的值。要注意,变量名称和值的数量要相同。当不相同时,抛出异常。
|
1408
|
+
|
1409
|
+
:param names: 所有变量名的元组或列表
|
1410
|
+
:param values: 所有变量对应值的元祖或列表
|
1411
|
+
|
1412
|
+
示例:
|
1413
|
+
.. code:: Python
|
1414
|
+
|
1415
|
+
hp_key = ("qi", "jing", "neili", "jingli")
|
1416
|
+
hp_value = [1000, 800, 1100, 1050]
|
1417
|
+
|
1418
|
+
session.setVariables(hp_key, hp_value)
|
1419
|
+
"""
|
934
1420
|
assert isinstance(names, tuple) or isinstance(names, list), "names命名应为元组或列表,不接受其他类型"
|
935
1421
|
assert isinstance(values, tuple) or isinstance(values, list), "values值应为元组或列表,不接受其他类型"
|
936
1422
|
assert (len(names) > 0) and (len(values) > 0) and (len(names) == len(values)), "names与values应不为空,且长度相等"
|
@@ -940,7 +1426,17 @@ class Session:
|
|
940
1426
|
self.setVariable(name, value)
|
941
1427
|
|
942
1428
|
def getVariables(self, names):
|
943
|
-
"""
|
1429
|
+
"""
|
1430
|
+
同时获取一组变量的值。
|
1431
|
+
|
1432
|
+
:param names: 所有变量名的元组或列表
|
1433
|
+
:return: 返回所有变量值的元组。可在获取值时直接解包。
|
1434
|
+
|
1435
|
+
示例:
|
1436
|
+
.. code:: Python
|
1437
|
+
|
1438
|
+
qi, jing, neili, jingli = session.getVariables(["qi", "jing", "neili", "jingli"])
|
1439
|
+
"""
|
944
1440
|
assert isinstance(names, tuple) or isinstance(names, list), "names命名应为元组或列表,不接受其他类型"
|
945
1441
|
assert len(names) > 0, "names应不为空"
|
946
1442
|
values = list()
|
@@ -951,24 +1447,51 @@ class Session:
|
|
951
1447
|
return tuple(values)
|
952
1448
|
|
953
1449
|
def updateVariables(self, kvdict: dict):
|
954
|
-
"""
|
1450
|
+
"""
|
1451
|
+
使用字典更新一组变量的值。若变量不存在将自动添加。
|
1452
|
+
|
1453
|
+
:param kvdict: 变量/值的字典
|
1454
|
+
|
1455
|
+
示例:
|
1456
|
+
.. code:: Python
|
1457
|
+
|
1458
|
+
newvars = {"qi": 1000, "jing": 800, "neili": 1100, "jingli": 1050}
|
1459
|
+
session.updateVariables(newvars)
|
1460
|
+
"""
|
1461
|
+
|
955
1462
|
self._variables.update(kvdict)
|
956
1463
|
|
957
1464
|
## ###################
|
958
1465
|
## 全局变量 Globals 处理
|
959
1466
|
## ###################
|
960
1467
|
def delGlobal(self, name):
|
961
|
-
"
|
1468
|
+
"""
|
1469
|
+
删除一个全局变量,使用方式与会话变量variable相同
|
1470
|
+
|
1471
|
+
:param name: 全局变量的名称
|
1472
|
+
"""
|
962
1473
|
assert isinstance(name, str), "name必须是一个字符串"
|
963
1474
|
self.application.del_globals(name)
|
964
1475
|
|
965
1476
|
def setGlobal(self, name, value):
|
966
|
-
"""
|
1477
|
+
"""
|
1478
|
+
设置一个全局变量的值,使用方式与会话变量variable相同
|
1479
|
+
|
1480
|
+
:param name: 全局变量的名称
|
1481
|
+
:param value: 全局变量的值
|
1482
|
+
"""
|
967
1483
|
assert isinstance(name, str), "name必须是一个字符串"
|
968
1484
|
self.application.set_globals(name, value)
|
969
1485
|
|
970
1486
|
def getGlobal(self, name, default = None):
|
971
|
-
"""
|
1487
|
+
"""
|
1488
|
+
获取一个全局变量的值,使用方式与会话变量variable相同
|
1489
|
+
|
1490
|
+
:param name: 全局变量的名称
|
1491
|
+
:param default: 当全局变量不存在时的返回值
|
1492
|
+
:return: 全局变量的值,或者 default
|
1493
|
+
"""
|
1494
|
+
|
972
1495
|
assert isinstance(name, str), "name必须是一个字符串"
|
973
1496
|
return self.application.get_globals(name, default)
|
974
1497
|
|
@@ -1688,7 +2211,13 @@ class Session:
|
|
1688
2211
|
ss.exec_command(new_cmd)
|
1689
2212
|
|
1690
2213
|
def clean(self):
|
1691
|
-
"
|
2214
|
+
"""
|
2215
|
+
清除会话有关任务项和事件标识,具体包括:
|
2216
|
+
|
2217
|
+
- 复位所有可能包含异步操作的对象,包括定时器、触发器、别名、GMCP触发器、命令
|
2218
|
+
- 取消所有由本会话管理但仍未完成的任务
|
2219
|
+
- 清空会话管理的所有任务
|
2220
|
+
"""
|
1692
2221
|
try:
|
1693
2222
|
# 加载时,取消所有任务,复位所有含async的对象, 保留变量
|
1694
2223
|
for tm in self._timers.values():
|
@@ -1720,7 +2249,9 @@ class Session:
|
|
1720
2249
|
pass
|
1721
2250
|
|
1722
2251
|
def reset(self):
|
1723
|
-
"
|
2252
|
+
"""
|
2253
|
+
复位:清除所有异步项和等待对象,卸载所有模块,清除所有会话有关对象。
|
2254
|
+
"""
|
1724
2255
|
self.clean()
|
1725
2256
|
|
1726
2257
|
modules = self._modules.values()
|
@@ -1735,7 +2266,15 @@ class Session:
|
|
1735
2266
|
self._tasks.clear()
|
1736
2267
|
|
1737
2268
|
def load_module(self, module_names):
|
1738
|
-
"
|
2269
|
+
"""
|
2270
|
+
模块加载函数。
|
2271
|
+
|
2272
|
+
:param module_names: 要加载的模块清单。为元组/列表时,加载指定名称的系列模块,当名称为字符串时,加载单个模块。
|
2273
|
+
|
2274
|
+
示例:
|
2275
|
+
- session.load_module('mymodule'): 加载名为mymodule.py文件对应的模块
|
2276
|
+
- session.load_modules(['mymod1', 'mymod2']): 依次加载mymod1.py与mymod2.py文件对应的模块
|
2277
|
+
"""
|
1739
2278
|
if isinstance(module_names, (list, tuple)):
|
1740
2279
|
for mod in module_names:
|
1741
2280
|
mod = mod.strip()
|
@@ -1777,7 +2316,14 @@ class Session:
|
|
1777
2316
|
self.error(f"异常追踪为: {traceback.format_exc()}")
|
1778
2317
|
|
1779
2318
|
def unload_module(self, module_names):
|
1780
|
-
"
|
2319
|
+
"""
|
2320
|
+
模块卸载函数。卸载模块时,将自动调用模块中名称为Configuration类对象的unload方法。
|
2321
|
+
|
2322
|
+
一般使用 #unload 命令来卸载模块,而不是在脚本中使用 unload_module 函数来卸载模块
|
2323
|
+
|
2324
|
+
:param module_names: 要卸载的模块清单。为元组/列表时,卸载指定名称的系列模块,当名称为字符串时,卸载单个模块。
|
2325
|
+
"""
|
2326
|
+
|
1781
2327
|
if isinstance(module_names, (list, tuple)):
|
1782
2328
|
for mod in module_names:
|
1783
2329
|
mod = mod.strip()
|
@@ -1807,7 +2353,13 @@ class Session:
|
|
1807
2353
|
self.warning(f"指定模块名称 {module_name} 并未加载.")
|
1808
2354
|
|
1809
2355
|
def reload_module(self, module_names = None):
|
1810
|
-
"
|
2356
|
+
"""
|
2357
|
+
模块重新加载函数。
|
2358
|
+
|
2359
|
+
一般使用 #reload 命令来重新加载模块,而不是在脚本中使用 reload_module 函数来重新加载模块
|
2360
|
+
|
2361
|
+
:param module_names: 要重新加载的模块清单。为元组/列表时,卸载指定名称的系列模块,当名称为字符串时,卸载单个模块。当不指定时,重新加载所有已加载模块。
|
2362
|
+
"""
|
1811
2363
|
if module_names is None:
|
1812
2364
|
self.clean()
|
1813
2365
|
mods = list(self._modules.keys())
|
@@ -2234,13 +2786,31 @@ class Session:
|
|
2234
2786
|
self.writetobuffer("{}[{}] {}{}".format(style, title, msg, Settings.CLR_STYLE), newline = True)
|
2235
2787
|
|
2236
2788
|
def info(self, msg, title = "PYMUD INFO", style = Settings.INFO_STYLE):
|
2237
|
-
"
|
2789
|
+
"""
|
2790
|
+
使用默认的INFO_STYLE(绿色)输出信息,并自动换行。信息格式类似 [title] msg
|
2791
|
+
|
2792
|
+
:param msg: 要输出的信息
|
2793
|
+
:param title: 要显示在前面的标题,不指定时默认为 PYMUD INFO
|
2794
|
+
:param style: 要输出信息的格式(ANSI), 默认为 INFO_STYLE, \x1b[32m
|
2795
|
+
"""
|
2238
2796
|
self.info2(msg, title, style)
|
2239
2797
|
|
2240
2798
|
def warning(self, msg, title = "PYMUD WARNING", style = Settings.WARN_STYLE):
|
2241
|
-
"
|
2799
|
+
"""
|
2800
|
+
使用默认的WARN_STYLE(黄色)输出信息,并自动换行。信息格式类似 [title] msg
|
2801
|
+
|
2802
|
+
:param msg: 要输出的信息
|
2803
|
+
:param title: 要显示在前面的标题,不指定时默认为 PYMUD WARNING
|
2804
|
+
:param style: 要输出信息的格式(ANSI), 默认为 WARN_STYLE, \x1b[33m
|
2805
|
+
"""
|
2242
2806
|
self.info2(msg, title, style)
|
2243
2807
|
|
2244
2808
|
def error(self, msg, title = "PYMUD ERROR", style = Settings.ERR_STYLE):
|
2245
|
-
"
|
2809
|
+
"""
|
2810
|
+
使用默认的ERR_STYLE(红色)输出信息,并自动换行。信息格式类似 [title] msg
|
2811
|
+
|
2812
|
+
:param msg: 要输出的信息
|
2813
|
+
:param title: 要显示在前面的标题,不指定时默认为 PYMUD ERROR
|
2814
|
+
:param style: 要输出信息的格式(ANSI), 默认为 ERR_STYLE, \x1b[31m
|
2815
|
+
"""
|
2246
2816
|
self.info2(msg, title, style)
|