pymud 0.21.2a1__tar.gz → 0.21.2.post1__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 (28) hide show
  1. {pymud-0.21.2a1 → pymud-0.21.2.post1}/PKG-INFO +8 -6
  2. {pymud-0.21.2a1 → pymud-0.21.2.post1}/README.md +7 -5
  3. {pymud-0.21.2a1 → pymud-0.21.2.post1}/pyproject.toml +1 -1
  4. {pymud-0.21.2a1 → pymud-0.21.2.post1}/src/pymud/extras.py +132 -88
  5. {pymud-0.21.2a1 → pymud-0.21.2.post1}/src/pymud/pymud.py +25 -10
  6. {pymud-0.21.2a1 → pymud-0.21.2.post1}/src/pymud/session.py +0 -11
  7. {pymud-0.21.2a1 → pymud-0.21.2.post1}/src/pymud.egg-info/PKG-INFO +8 -6
  8. {pymud-0.21.2a1 → pymud-0.21.2.post1}/LICENSE.txt +0 -0
  9. {pymud-0.21.2a1 → pymud-0.21.2.post1}/setup.cfg +0 -0
  10. {pymud-0.21.2a1 → pymud-0.21.2.post1}/src/pymud/__init__.py +0 -0
  11. {pymud-0.21.2a1 → pymud-0.21.2.post1}/src/pymud/__main__.py +0 -0
  12. {pymud-0.21.2a1 → pymud-0.21.2.post1}/src/pymud/decorators.py +0 -0
  13. {pymud-0.21.2a1 → pymud-0.21.2.post1}/src/pymud/dialogs.py +0 -0
  14. {pymud-0.21.2a1 → pymud-0.21.2.post1}/src/pymud/i18n.py +0 -0
  15. {pymud-0.21.2a1 → pymud-0.21.2.post1}/src/pymud/lang/i18n_chs.py +0 -0
  16. {pymud-0.21.2a1 → pymud-0.21.2.post1}/src/pymud/lang/i18n_eng.py +0 -0
  17. {pymud-0.21.2a1 → pymud-0.21.2.post1}/src/pymud/logger.py +0 -0
  18. {pymud-0.21.2a1 → pymud-0.21.2.post1}/src/pymud/main.py +0 -0
  19. {pymud-0.21.2a1 → pymud-0.21.2.post1}/src/pymud/modules.py +0 -0
  20. {pymud-0.21.2a1 → pymud-0.21.2.post1}/src/pymud/objects.py +0 -0
  21. {pymud-0.21.2a1 → pymud-0.21.2.post1}/src/pymud/pkuxkx.py +0 -0
  22. {pymud-0.21.2a1 → pymud-0.21.2.post1}/src/pymud/protocol.py +0 -0
  23. {pymud-0.21.2a1 → pymud-0.21.2.post1}/src/pymud/settings.py +0 -0
  24. {pymud-0.21.2a1 → pymud-0.21.2.post1}/src/pymud.egg-info/SOURCES.txt +0 -0
  25. {pymud-0.21.2a1 → pymud-0.21.2.post1}/src/pymud.egg-info/dependency_links.txt +0 -0
  26. {pymud-0.21.2a1 → pymud-0.21.2.post1}/src/pymud.egg-info/entry_points.txt +0 -0
  27. {pymud-0.21.2a1 → pymud-0.21.2.post1}/src/pymud.egg-info/requires.txt +0 -0
  28. {pymud-0.21.2a1 → pymud-0.21.2.post1}/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.21.2a1
3
+ Version: 0.21.2.post1
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>
@@ -44,11 +44,11 @@ Dynamic: license-file
44
44
 
45
45
  ### 北大侠客行Mud (www.pkuxkx.net),最好的中文Mud游戏!
46
46
  ### PyMUD是我为了更好的玩北大侠客行,特意自行开发的MUD客户端。PyMUD具有以下特点:
47
- + 原生Python开发,除prompt-toolkit及其依赖库(wcwidth, pygment, pyperclip)外,不需要其他第三方库支持
47
+ + 原生Python开发,除prompt-toolkit及其依赖库 wcwidth, pygment, pyperclip 外,不需要其他第三方库支持
48
48
  + 原生Python的asyncio实现的通信协议处理,支持async/await语法在脚本中直接应用,脚本实现的同步异步两种模式由你自己选择
49
- + 基于控制台的全屏UI界面设计,支持鼠标操作(Android上支持触摸屏操作)
49
+ + 基于控制台的全屏UI界面设计,支持鼠标操作(Android上支持触摸屏操作),极低资源需求,在单核1GB内存的Linux VPS上也可流畅运行
50
50
  + 支持分屏显示,在数据快速滚动的时候,上半屏保持不动,以确保不错过信息
51
- + 解决了99%情况下,北大侠客行中文对不齐,也就是看不清字符画的问题(因为我没有走遍所有地方,不敢保证100%)
51
+ + 解决了99%情况下,北大侠客行中文对不齐,也就是看不清字符画的问题
52
52
  + 真正的支持多session会话,支持命令或鼠标切换会话
53
53
  + 原生支持多种服务器端编码方式,不论是GBK、BIG5、还是UTF-8
54
54
  + 支持NWAS、MTTS协商,支持GMCP、MSDP、MSSP协议
@@ -66,10 +66,12 @@ Dynamic: license-file
66
66
 
67
67
  ## 版本更新信息
68
68
 
69
- ### 0.22.0 (2025-05-27) 本版传错了,已无法使用。
69
+ ### 0.21.2 (2025-06-01)
70
70
 
71
71
  + 问题修复: 修复了当自动重连启动时,即使会话关闭了,也会自动重连的问题。
72
- + 实现调整: 重写了专用的SessionBuffer与SessionBufferControl,降低内存使用。
72
+ + 实现调整: 重写了专用的会话缓冲、记录缓冲与PyMud缓冲显示控制器,在prompt_toolkit的原Buffer和BufferControl的基础仅提供了PYMUD所需的基础功能,以降低内存占用。
73
+ 经测试,当前内存基本稳定,视会话数量和脚本情况差异,维持在几百兆左右(500M以下),且不会有大幅波动。重写后,低配置的VPS也可以稳定运行PyMUD。
74
+ + post1: 问题修复: 修复了当缓存行数超过规定值时,由于代码错误导致清屏的问题。
73
75
 
74
76
  ### 0.21.0 (2025-05-20)
75
77
 
@@ -12,11 +12,11 @@
12
12
 
13
13
  ### 北大侠客行Mud (www.pkuxkx.net),最好的中文Mud游戏!
14
14
  ### PyMUD是我为了更好的玩北大侠客行,特意自行开发的MUD客户端。PyMUD具有以下特点:
15
- + 原生Python开发,除prompt-toolkit及其依赖库(wcwidth, pygment, pyperclip)外,不需要其他第三方库支持
15
+ + 原生Python开发,除prompt-toolkit及其依赖库 wcwidth, pygment, pyperclip 外,不需要其他第三方库支持
16
16
  + 原生Python的asyncio实现的通信协议处理,支持async/await语法在脚本中直接应用,脚本实现的同步异步两种模式由你自己选择
17
- + 基于控制台的全屏UI界面设计,支持鼠标操作(Android上支持触摸屏操作)
17
+ + 基于控制台的全屏UI界面设计,支持鼠标操作(Android上支持触摸屏操作),极低资源需求,在单核1GB内存的Linux VPS上也可流畅运行
18
18
  + 支持分屏显示,在数据快速滚动的时候,上半屏保持不动,以确保不错过信息
19
- + 解决了99%情况下,北大侠客行中文对不齐,也就是看不清字符画的问题(因为我没有走遍所有地方,不敢保证100%)
19
+ + 解决了99%情况下,北大侠客行中文对不齐,也就是看不清字符画的问题
20
20
  + 真正的支持多session会话,支持命令或鼠标切换会话
21
21
  + 原生支持多种服务器端编码方式,不论是GBK、BIG5、还是UTF-8
22
22
  + 支持NWAS、MTTS协商,支持GMCP、MSDP、MSSP协议
@@ -34,10 +34,12 @@
34
34
 
35
35
  ## 版本更新信息
36
36
 
37
- ### 0.22.0 (2025-05-27) 本版传错了,已无法使用。
37
+ ### 0.21.2 (2025-06-01)
38
38
 
39
39
  + 问题修复: 修复了当自动重连启动时,即使会话关闭了,也会自动重连的问题。
40
- + 实现调整: 重写了专用的SessionBuffer与SessionBufferControl,降低内存使用。
40
+ + 实现调整: 重写了专用的会话缓冲、记录缓冲与PyMud缓冲显示控制器,在prompt_toolkit的原Buffer和BufferControl的基础仅提供了PYMUD所需的基础功能,以降低内存占用。
41
+ 经测试,当前内存基本稳定,视会话数量和脚本情况差异,维持在几百兆左右(500M以下),且不会有大幅波动。重写后,低配置的VPS也可以稳定运行PyMUD。
42
+ + post1: 问题修复: 修复了当缓存行数超过规定值时,由于代码错误导致清屏的问题。
41
43
 
42
44
  ### 0.21.0 (2025-05-20)
43
45
 
@@ -1,7 +1,7 @@
1
1
  [project]
2
2
 
3
3
  name = "pymud" # Required
4
- version = "0.21.2a1" # Required
4
+ version = "0.21.2post1" # Required
5
5
  description = "a MUD Client written in Python" # Optional
6
6
  readme = "README.md" # Optional
7
7
  requires-python = ">=3.8"
@@ -1,9 +1,10 @@
1
1
  # External Libraries
2
+ from functools import lru_cache
2
3
  from unicodedata import east_asian_width
3
4
  from wcwidth import wcwidth
4
5
  from dataclasses import dataclass
5
- import time, re, logging
6
-
6
+ import time, re, logging, linecache, os
7
+ from typing import Optional, List, Dict
7
8
  from typing import Iterable, NamedTuple, Optional, Union, Tuple
8
9
  from prompt_toolkit import ANSI
9
10
  from prompt_toolkit.application import get_app
@@ -236,7 +237,7 @@ class VSplitWindow(Window):
236
237
  below = total - upper - 1
237
238
 
238
239
  #if isNotMargin:
239
- if isinstance(self.content, SessionBufferControl):
240
+ if isinstance(self.content, PyMudBufferControl):
240
241
  b = self.content.buffer
241
242
  if not b:
242
243
  return y
@@ -276,33 +277,35 @@ class VSplitWindow(Window):
276
277
 
277
278
  else:
278
279
  # 有split window
279
- # 复制上半部分,正序复制,确保即使有自动折行时,第一行也保持在屏幕最顶部
280
- lineno = start_lineno
281
- while y < upper and lineno < line_count:
282
- line = ui_content.get_line(lineno)
283
- visible_line_to_row_col[y] = (lineno, horizontal_scroll)
284
- x = 0
285
- x, y = copy_line(line, lineno, x, y, is_input=True)
286
- lineno += 1
287
- y += 1
280
+
288
281
 
289
- # x = 0
290
- # x, y = copy_line([("","-"*width)], lineno, x, y, is_input=False)
291
- # y += 1
292
282
 
293
- # 复制下半部分,倒序复制,确保即使有自动折行时,最后一行也保持在屏幕最底部
283
+ # 先复制下半部分,倒序复制,确保即使有自动折行时,最后一行也保持在屏幕最底部
294
284
  y = total
295
285
  lineno = line_count
296
286
 
297
- while y >= below and lineno >= 0:
287
+ while y > below and lineno >= 0:
298
288
  lineno -= 1
299
289
  # Take the next line and copy it in the real screen.
300
290
  display_lines = ui_content.get_height_for_line(lineno, width, None)
301
291
  y -= display_lines
292
+ if y <= below:
293
+ break
302
294
  line = ui_content.get_line(lineno)
303
295
  visible_line_to_row_col[y] = (lineno, horizontal_scroll)
304
296
  copy_line(line, lineno, 0, y, is_input=True)
305
297
 
298
+ # 复制上半部分,正序复制,确保即使有自动折行时,第一行也保持在屏幕最顶部
299
+ y = -vertical_scroll_2
300
+ lineno = start_lineno
301
+ while y <= below and lineno < line_count:
302
+ line = ui_content.get_line(lineno)
303
+ visible_line_to_row_col[y] = (lineno, horizontal_scroll)
304
+ x = 0
305
+ x, y = copy_line(line, lineno, x, y, is_input=True)
306
+ lineno += 1
307
+ y += 1
308
+
306
309
  # 最后复制分割线,若上下有由于折行额外占用的内容,都用分割线给覆盖掉
307
310
  copy_line([("","-"*width)], -1, 0, upper + 1, is_input=False)
308
311
 
@@ -377,7 +380,7 @@ class VSplitWindow(Window):
377
380
  if info is None:
378
381
  return
379
382
 
380
- if isinstance(self.content, SessionBufferControl):
383
+ if isinstance(self.content, PyMudBufferControl):
381
384
  b = self.content.buffer
382
385
  if not b:
383
386
  return
@@ -394,7 +397,7 @@ class VSplitWindow(Window):
394
397
  if info is None:
395
398
  return
396
399
 
397
- if isinstance(self.content, SessionBufferControl):
400
+ if isinstance(self.content, PyMudBufferControl):
398
401
  b = self.content.buffer
399
402
  if not b:
400
403
  return
@@ -518,6 +521,7 @@ class EasternMenuContainer(MenuContainer):
518
521
 
519
522
  return Window(FormattedTextControl(get_text_fragments), style="class:menu")
520
523
 
524
+
521
525
  @dataclass
522
526
  class SessionSelectionState:
523
527
  start_row: int = -1
@@ -547,9 +551,53 @@ class SessionSelectionState:
547
551
  return self.end_row - self.start_row + 1
548
552
  else:
549
553
  return 0
550
-
551
554
 
552
- class SessionBuffer:
555
+
556
+ class BufferBase:
557
+ def __init__(self, name, newline = "\n", max_buffered_lines = 10000) -> None:
558
+ self.name = name
559
+ self.newline = newline
560
+ self.max_buffered_lines = max_buffered_lines
561
+ self.start_lineno = -1
562
+ self.selection = SessionSelectionState(-1, -1, -1, -1)
563
+
564
+ def clear(self):
565
+ pass
566
+
567
+ @property
568
+ def lineCount(self) -> int:
569
+ return 0
570
+
571
+ def getLine(self, lineno: int) -> str:
572
+ return ""
573
+
574
+ # 获取指定某行到某行的内容。当start未设置时,从首行开始。当end未设置时,到最后一行结束。
575
+ # 注意判断首位顺序逻辑,以及给定参数是否越界
576
+ def selection_range_at_line(self, lineno: int) -> Optional[Tuple[int, int]]:
577
+ if self.selection.is_valid():
578
+ if self.selection.rows > 1:
579
+ if lineno == self.selection.start_row:
580
+ return (self.selection.start_col, len(self.getLine(lineno)) - 1)
581
+ elif lineno == self.selection.end_row:
582
+ return (0, self.selection.end_col)
583
+ elif lineno > self.selection.start_row and lineno < self.selection.end_row:
584
+ return (0, len(self.getLine(lineno)) - 1)
585
+
586
+ elif self.selection.rows == 1:
587
+ if lineno == self.selection.start_row:
588
+ return (self.selection.start_col, self.selection.end_col)
589
+
590
+ return None
591
+
592
+ def exit_selection(self):
593
+ self.selection = SessionSelectionState(-1, -1, -1, -1)
594
+
595
+ def nosplit(self):
596
+ self.start_lineno = -1
597
+ get_app().invalidate()
598
+
599
+
600
+ class SessionBuffer(BufferBase):
553
601
  def __init__(
554
602
  self,
555
603
  name,
@@ -557,13 +605,10 @@ class SessionBuffer:
557
605
  max_buffered_lines = 10000,
558
606
  ) -> None:
559
607
 
560
- self.name = name
561
- self.lines = []
562
- self.newline = newline
563
- self.isnewline = True
564
- self.max_buffered_lines = max_buffered_lines
565
- self.selection = SessionSelectionState(-1, -1, -1, -1)
566
- self.start_lineno = -1
608
+ super().__init__(name, newline, max_buffered_lines)
609
+
610
+ self._lines : List[str] = []
611
+ self._isnewline = True
567
612
 
568
613
  def append(self, line: str):
569
614
  """
@@ -576,25 +621,25 @@ class SessionBuffer:
576
621
  line = line.rstrip(self.newline)
577
622
  newline_after_append = True
578
623
  if not self.newline in line:
579
- if self.isnewline:
580
- self.lines.append(line)
624
+ if self._isnewline:
625
+ self._lines.append(line)
581
626
  else:
582
- self.lines[-1] += line
627
+ self._lines[-1] += line
583
628
 
584
629
  else:
585
630
  lines = line.split(self.newline)
586
- if self.isnewline:
587
- self.lines.extend(lines)
631
+ if self._isnewline:
632
+ self._lines.extend(lines)
588
633
  else:
589
- self.lines[-1] += lines[0]
590
- self.lines.extend(lines[1:])
634
+ self._lines[-1] += lines[0]
635
+ self._lines.extend(lines[1:])
591
636
 
592
- self.isnewline = newline_after_append
637
+ self._isnewline = newline_after_append
593
638
 
594
639
  ## limit buffered lines
595
- if len(self.lines) > self.max_buffered_lines:
596
- diff = self.max_buffered_lines - len(self.lines)
597
- del self.lines[:diff]
640
+ if len(self._lines) > self.max_buffered_lines:
641
+ diff = len(self._lines) - self.max_buffered_lines
642
+ del self._lines[:diff]
598
643
  ## adjust selection
599
644
  if self.selection.start_row >= 0:
600
645
  self.selection.start_row -= diff
@@ -603,68 +648,60 @@ class SessionBuffer:
603
648
  get_app().invalidate()
604
649
 
605
650
  def clear(self):
606
- self.lines.clear()
651
+ self._lines.clear()
607
652
  self.selection = SessionSelectionState(-1, -1, -1, -1)
608
653
 
609
654
  get_app().invalidate()
610
655
 
611
- def loadfile(self, filename, encoding = 'utf-8', errors = 'ignore'):
612
- with open(filename, 'r', encoding = encoding, errors = errors) as fp:
613
- lines = fp.readlines()
614
- self.clear()
615
- self.lines.extend(lines)
616
-
617
- get_app().invalidate()
618
-
619
656
  @property
620
657
  def lineCount(self):
621
- return len(self.lines)
658
+ return len(self._lines)
622
659
 
623
- def getLine(self, lineno):
624
- if lineno < 0 or lineno >= len(self.lines):
660
+ def getLine(self, lineno: int):
661
+ if lineno < 0 or lineno >= len(self._lines):
625
662
  return ""
626
- return self.lines[lineno]
663
+ return self._lines[lineno]
627
664
 
628
- # 获取指定某行到某行的内容。当start未设置时,从首行开始。当end未设置时,到最后一行结束。
629
- # 注意判断首位顺序逻辑,以及给定参数是否越界
630
- def getLines(self, start = None, end = None):
631
- if start is None:
632
- start = 0
633
- if end is None:
634
- end = len(self.lines) - 1
635
- if start < 0:
636
- start = 0
637
- if end >= len(self.lines):
638
- end = len(self.lines) - 1
639
- if start > end:
640
- return []
641
- return self.lines[start:end+1]
642
-
643
- def selection_range_at_line(self, lineno):
644
- if self.selection.is_valid():
645
- if self.selection.rows > 1:
646
- if lineno == self.selection.start_row:
647
- return (self.selection.start_col, len(self.lines[lineno]) - 1)
648
- elif lineno == self.selection.end_row:
649
- return (0, self.selection.end_col)
650
- elif lineno > self.selection.start_row and lineno < self.selection.end_row:
651
- return (0, len(self.lines[lineno]) - 1)
652
665
 
653
- elif self.selection.rows == 1:
654
- if lineno == self.selection.start_row:
655
- return (self.selection.start_col, self.selection.end_col)
666
+ class LogFileBuffer(BufferBase):
667
+ def __init__(
668
+ self,
669
+ name,
670
+ filepath: Optional[str] = None,
671
+ ) -> None:
656
672
 
657
- return None
673
+ super().__init__(name)
674
+ self._lines : Dict[int, str] = {}
675
+ self.loadfile(filepath)
676
+
677
+ def loadfile(self, filepath: Optional[str] = None):
678
+ if filepath and os.path.exists(filepath):
679
+ self.filepath = filepath
680
+ else:
681
+ self.filepath = None
658
682
 
659
- def exit_selection(self):
660
- self.selection = SessionSelectionState(-1, -1, -1, -1)
683
+ def clear(self):
684
+ self.filepath = None
661
685
 
662
- def nosplit(self):
663
- self.start_lineno = -1
664
- get_app().invalidate()
686
+ @property
687
+ def lineCount(self):
688
+ if not self.filepath or not os.path.exists(self.filepath):
689
+ return 0
690
+
691
+ with open(self.filepath, 'r', encoding = 'utf-8', errors = 'ignore') as fp:
692
+ return sum(1 for _ in fp)
693
+
694
+ def getLine(self, lineno: int):
695
+ if not self.filepath or not os.path.exists(self.filepath):
696
+ return ""
697
+
698
+ return linecache.getline(self.filepath, lineno).rstrip(self.newline)
699
+
700
+ def __del__(self):
701
+ self._lines.clear()
665
702
 
666
- class SessionBufferControl(UIControl):
667
- def __init__(self, buffer: Optional[SessionBuffer]) -> None:
703
+ class PyMudBufferControl(UIControl):
704
+ def __init__(self, buffer: Optional[BufferBase]) -> None:
668
705
  self.buffer = buffer
669
706
 
670
707
  # 为MUD显示进行校正的处理,包括对齐校正,换行颜色校正等
@@ -744,10 +781,14 @@ class SessionBufferControl(UIControl):
744
781
  def get_line(i: int) -> StyleAndTextTuples:
745
782
  line = buffer.getLine(i)
746
783
  # 颜色校正
784
+ SEARCH_LINES = 10
747
785
  thislinecolors = len(self.AVAI_COLOR_REGX.findall(line))
748
786
  if thislinecolors == 0:
749
787
  lineno = i - 1
750
- while lineno >= 0:
788
+ search = 0
789
+ while lineno >= 0 and search < SEARCH_LINES:
790
+ search += 1
791
+
751
792
  lastline = buffer.getLine(lineno)
752
793
  allcolors = self.ALL_COLOR_REGX.findall(lastline)
753
794
 
@@ -883,6 +924,9 @@ class SessionBufferControl(UIControl):
883
924
  else:
884
925
  # Don't handle scroll events here.
885
926
  return NotImplemented
927
+ else:
928
+ # Don't handle scroll events here.
929
+ return NotImplemented
886
930
 
887
931
  # Not focused, but focusing on click events.
888
932
  else:
@@ -9,7 +9,7 @@ from prompt_toolkit.buffer import Buffer
9
9
  from prompt_toolkit.application import Application
10
10
  from prompt_toolkit.filters import Condition
11
11
  from prompt_toolkit.key_binding import KeyBindings
12
- from prompt_toolkit.layout import ConditionalContainer, Float, VSplit, HSplit, Window, WindowAlign, ScrollbarMargin, NumberedMargin
12
+ from prompt_toolkit.layout import ConditionalContainer, Float, VSplit, HSplit, Window, WindowAlign, ScrollbarMargin, NumberedMargin, to_dimension
13
13
  from prompt_toolkit.layout.layout import Layout
14
14
  from prompt_toolkit.layout.controls import FormattedTextControl
15
15
  from prompt_toolkit.layout.dimension import D
@@ -37,7 +37,7 @@ from prompt_toolkit.auto_suggest import AutoSuggestFromHistory
37
37
  from wcwidth import wcwidth, wcswidth
38
38
 
39
39
  from .objects import CodeBlock
40
- from .extras import SessionBuffer, SessionBufferControl, EasternMenuContainer, VSplitWindow, DotDict, MenuItem
40
+ from .extras import BufferBase, LogFileBuffer, SessionBuffer, PyMudBufferControl, EasternMenuContainer, VSplitWindow, DotDict, MenuItem
41
41
  from .modules import Plugin
42
42
  from .session import Session
43
43
  from .settings import Settings
@@ -164,7 +164,7 @@ class PyMudApp:
164
164
  self.logFileShown = '' # 记录页显示的记录文件名
165
165
  #self.logSessionBuffer = SessionBuffer()
166
166
  #self.logSessionBuffer.name = "LOGBUFFER"
167
- self.logSessionBuffer = SessionBuffer("LOGBUFFER", max_buffered_lines = -1)
167
+ self.logSessionBuffer = LogFileBuffer("LOGBUFFER")
168
168
 
169
169
  self.load_plugins()
170
170
 
@@ -218,7 +218,7 @@ class PyMudApp:
218
218
  show_cursor=False
219
219
  )
220
220
 
221
- self.consoleView = SessionBufferControl(
221
+ self.consoleView = PyMudBufferControl(
222
222
  buffer = None,
223
223
  )
224
224
 
@@ -398,11 +398,26 @@ class PyMudApp:
398
398
  else:
399
399
  b = None
400
400
 
401
- if isinstance(b, Buffer):
401
+ if isinstance(b, BufferBase):
402
402
  if lines < 0:
403
- b.cursor_up(-1 * lines)
404
- elif lines > 0:
405
- b.cursor_down(lines)
403
+ if b.start_lineno < 0:
404
+ self.console._scroll_up()
405
+ b.start_lineno = b.lineCount - self.get_height() * 3 // 2
406
+ else:
407
+ b.start_lineno += lines
408
+ if b.start_lineno < 0:
409
+ b.start_lineno = 0
410
+
411
+ else:
412
+ if b.start_lineno < 0:
413
+ return
414
+
415
+ b.start_lineno += lines
416
+
417
+ if b.start_lineno >= b.lineCount - self.get_height():
418
+ b.start_lineno = -1
419
+
420
+
406
421
 
407
422
  def page_up(self, event: KeyPressEvent) -> None:
408
423
  "快捷键PageUp: 用于向上翻页。翻页页数为显示窗口行数的一半减去一行。"
@@ -644,7 +659,7 @@ class PyMudApp:
644
659
  if os.path.exists(filename):
645
660
  lock = threading.RLock()
646
661
  lock.acquire()
647
- self.logSessionBuffer.loadfile(filename, encoding = 'utf-8', errors = 'ignore')
662
+ self.logSessionBuffer.loadfile(filename)
648
663
  lock.release()
649
664
 
650
665
  #self.logSessionBuffer.cursor_position = len(self.logSessionBuffer.text)
@@ -736,7 +751,7 @@ class PyMudApp:
736
751
 
737
752
  elif self.showLog:
738
753
  b = self.logSessionBuffer
739
- b.exit_selection()
754
+ #b.exit_selection()
740
755
  #b.cursor_position = len(b.text)
741
756
  #b.start_lineno = -1
742
757
  b.nosplit()
@@ -571,16 +571,6 @@ class Session:
571
571
  self._line_count += 1
572
572
  self.log.log(self.newline_cli)
573
573
 
574
- def clear_half(self):
575
- """
576
- 清除半数缓冲。 **脚本中无需调用。**
577
-
578
- 半数的数量由 Settings.client['buffer_lines'] 确定,默认为5000行。
579
- """
580
- # if (Settings.client["buffer_lines"] > 0) and (self._line_count >= 2 * Settings.client["buffer_lines"]) and self.buffer.document.is_cursor_at_the_end:
581
- # self._line_count = self.buffer.clear_half()
582
- pass
583
-
584
574
  def feed_data(self, data) -> None:
585
575
  """
586
576
  由协议对象调用,将收到的远程数据加入会话缓冲。永远只会传递1个字节的数据,以bytes形式。 **脚本中无需调用。**
@@ -695,7 +685,6 @@ class Session:
695
685
 
696
686
  # 将数据写入缓存添加到此处
697
687
  if len(self.display_line) > 0:
698
- self.clear_half()
699
688
  self.writetobuffer(self.display_line)
700
689
 
701
690
  def set_exception(self, exc: Exception):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pymud
3
- Version: 0.21.2a1
3
+ Version: 0.21.2.post1
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>
@@ -44,11 +44,11 @@ Dynamic: license-file
44
44
 
45
45
  ### 北大侠客行Mud (www.pkuxkx.net),最好的中文Mud游戏!
46
46
  ### PyMUD是我为了更好的玩北大侠客行,特意自行开发的MUD客户端。PyMUD具有以下特点:
47
- + 原生Python开发,除prompt-toolkit及其依赖库(wcwidth, pygment, pyperclip)外,不需要其他第三方库支持
47
+ + 原生Python开发,除prompt-toolkit及其依赖库 wcwidth, pygment, pyperclip 外,不需要其他第三方库支持
48
48
  + 原生Python的asyncio实现的通信协议处理,支持async/await语法在脚本中直接应用,脚本实现的同步异步两种模式由你自己选择
49
- + 基于控制台的全屏UI界面设计,支持鼠标操作(Android上支持触摸屏操作)
49
+ + 基于控制台的全屏UI界面设计,支持鼠标操作(Android上支持触摸屏操作),极低资源需求,在单核1GB内存的Linux VPS上也可流畅运行
50
50
  + 支持分屏显示,在数据快速滚动的时候,上半屏保持不动,以确保不错过信息
51
- + 解决了99%情况下,北大侠客行中文对不齐,也就是看不清字符画的问题(因为我没有走遍所有地方,不敢保证100%)
51
+ + 解决了99%情况下,北大侠客行中文对不齐,也就是看不清字符画的问题
52
52
  + 真正的支持多session会话,支持命令或鼠标切换会话
53
53
  + 原生支持多种服务器端编码方式,不论是GBK、BIG5、还是UTF-8
54
54
  + 支持NWAS、MTTS协商,支持GMCP、MSDP、MSSP协议
@@ -66,10 +66,12 @@ Dynamic: license-file
66
66
 
67
67
  ## 版本更新信息
68
68
 
69
- ### 0.22.0 (2025-05-27) 本版传错了,已无法使用。
69
+ ### 0.21.2 (2025-06-01)
70
70
 
71
71
  + 问题修复: 修复了当自动重连启动时,即使会话关闭了,也会自动重连的问题。
72
- + 实现调整: 重写了专用的SessionBuffer与SessionBufferControl,降低内存使用。
72
+ + 实现调整: 重写了专用的会话缓冲、记录缓冲与PyMud缓冲显示控制器,在prompt_toolkit的原Buffer和BufferControl的基础仅提供了PYMUD所需的基础功能,以降低内存占用。
73
+ 经测试,当前内存基本稳定,视会话数量和脚本情况差异,维持在几百兆左右(500M以下),且不会有大幅波动。重写后,低配置的VPS也可以稳定运行PyMUD。
74
+ + post1: 问题修复: 修复了当缓存行数超过规定值时,由于代码错误导致清屏的问题。
73
75
 
74
76
  ### 0.21.0 (2025-05-20)
75
77
 
File without changes
File without changes
File without changes
File without changes