Skip to content

Commit d22a7e4

Browse files
eee555ljzloser
andauthored
插件 (#75) (#76)
* doc:modify readme and license * feat(plugin): 新增插件系统支持 添加插件管理功能,包括插件进程管理、事件处理、上下文共享和配置管理。主要变更包括: - 新增插件管理器PluginManager - 实现插件进程间通信 - 添加基础插件框架类BasePlugin - 支持事件订阅和分发机制 - 提供插件配置管理功能 --------- Co-authored-by: LjingZhijoin Group <107012527+ljzloser@users.noreply.github.com>
1 parent c761db6 commit d22a7e4

22 files changed

+1158
-62
lines changed

.gitignore

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ __pycache__/
77

88
# C extensions
99
*.so
10-
10+
*.exe
1111
# Distribution / packaging
1212
.Python
1313
build/
@@ -165,4 +165,5 @@ toollib/frame.csv
165165
*.evf
166166
*.mvf
167167
old/
168-
发布流程.txt
168+
发布流程.txt
169+
src/plugins/*/*.json

requirements.txt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
pyQt5==5.15.11
22
ms-toollib==1.5.1
3-
setuptools==78.1.1
3+
setuptools==80.9.0
44
pyinstaller==6.16.0
5-
5+
msgspec>=0.20.0
6+
zmq>=0.0.0
67

78

src/main.py

Lines changed: 83 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,50 @@
1212
import ms_toollib as ms
1313
import ctypes
1414
from ctypes import wintypes
15+
from mp_plugins.context import AppContext
16+
from mp_plugins.events import *
17+
from mp_plugins import PluginManager
18+
from pathlib import Path
19+
import os
20+
1521
os.environ["QT_FONT_DPI"] = "96"
1622

1723

24+
# def patch_env():
25+
# import os
26+
27+
28+
# env = os.environ.copy()
29+
# root = os.path.dirname(os.path.abspath(__file__)) # 你的项目根目录
30+
# env["PYTHONPATH"] = root
31+
# return env
32+
def get_paths():
33+
if getattr(sys, "frozen", False):
34+
# 打包成 exe
35+
dir = os.path.dirname(sys.executable) # exe 所在目录
36+
else:
37+
dir = os.path.dirname(os.path.abspath(__file__))
38+
39+
return dir
40+
41+
42+
def patch_env():
43+
import os
44+
import sys
45+
46+
env = os.environ.copy()
47+
48+
if getattr(sys, "frozen", False):
49+
# 打包成 exe,库解压到 _MEIPASS
50+
root = getattr(sys, "_MEIPASS", None)
51+
else:
52+
# 调试模式,库在项目目录
53+
root = os.path.dirname(os.path.abspath(__file__))
54+
55+
env["PYTHONPATH"] = root
56+
return env
57+
58+
1859
def on_new_connection(localServer: QLocalServer):
1960
"""当新连接进来时,接受连接并将文件路径传递给主窗口"""
2061
socket = localServer.nextPendingConnection()
@@ -53,7 +94,7 @@ def find_window(class_name, window_name):
5394
5495
5596
"""
56-
user32 = ctypes.WinDLL('user32', use_last_error=True)
97+
user32 = ctypes.WinDLL("user32", use_last_error=True)
5798
user32.FindWindowW.argtypes = [wintypes.LPCWSTR, wintypes.LPCWSTR]
5899
user32.FindWindowW.restype = wintypes.HWND
59100

@@ -63,36 +104,39 @@ def find_window(class_name, window_name):
63104
return hwnd
64105

65106

66-
67107
def cli_check_file(file_path: str) -> int:
68108
if not os.path.exists(file_path):
69109
print("ERROR: file not found")
70110
return 2
71-
111+
72112
# 搜集目录或文件下的所有evf和evfs文件
73113
evf_evfs_files = []
74-
if os.path.isfile(file_path) and (file_path.endswith('.evf') or file_path.endswith('.evfs')):
114+
if os.path.isfile(file_path) and (
115+
file_path.endswith(".evf") or file_path.endswith(".evfs")
116+
):
75117
evf_evfs_files = [os.path.abspath(file_path)]
76118
elif os.path.isdir(file_path):
77-
evf_evfs_files = [os.path.abspath(os.path.join(root, file))
78-
for root, dirs, files in os.walk(file_path)
79-
for file in files if file.endswith('.evf') or file.endswith('.evfs')]
119+
evf_evfs_files = [
120+
os.path.abspath(os.path.join(root, file))
121+
for root, dirs, files in os.walk(file_path)
122+
for file in files
123+
if file.endswith(".evf") or file.endswith(".evfs")
124+
]
80125

81126
if not evf_evfs_files:
82127
print("ERROR: must be evf or evfs files or directory")
83128
return 2
84-
85-
129+
86130
# 实例化一个MineSweeperGUI出来
87131
app = QtWidgets.QApplication(sys.argv)
88132
mainWindow = mainWindowGUI.MainWindow()
89133
ui = mineSweeperGUI.MineSweeperGUI(mainWindow, sys.argv)
90-
134+
91135
for ide, e in enumerate(evf_evfs_files):
92136
if not ui.checksum_module_ok():
93137
print("ERROR: ???")
94138
return 2
95-
if e.endswith('.evf'):
139+
if e.endswith(".evf"):
96140
# 检验evf文件是否合法
97141
video = ms.EvfVideo(e)
98142
try:
@@ -101,12 +145,13 @@ def cli_check_file(file_path: str) -> int:
101145
evf_evfs_files[ide] = (e, 2)
102146
else:
103147
checksum = ui.checksum_guard.get_checksum(
104-
video.raw_data[:-(len(video.checksum) + 2)])
148+
video.raw_data[: -(len(video.checksum) + 2)]
149+
)
105150
if video.checksum == checksum:
106151
evf_evfs_files[ide] = (e, 0)
107152
else:
108153
evf_evfs_files[ide] = (e, 1)
109-
elif e.endswith('.evfs'):
154+
elif e.endswith(".evfs"):
110155
# 检验evfs文件是否合法
111156
videos = ms.Evfs(e)
112157
try:
@@ -116,21 +161,22 @@ def cli_check_file(file_path: str) -> int:
116161
else:
117162
if videos.len() <= 0:
118163
evf_evfs_files[ide] = (e, 2)
119-
checksum = ui.checksum_guard.get_checksum(
120-
videos[0].evf_video.raw_data)
164+
checksum = ui.checksum_guard.get_checksum(videos[0].evf_video.raw_data)
121165
if video.checksum != checksum:
122166
evf_evfs_files[ide] = (e, 1)
123167
continue
124168
for idcell, cell in enumerate(videos[1:]):
125169
checksum = ui.checksum_guard.get_checksum(
126-
cell.evf_video.raw_data + videos[idcell - 1].checksum)
170+
cell.evf_video.raw_data + videos[idcell - 1].checksum
171+
)
127172
if cell.evf_file.checksum != checksum:
128173
evf_evfs_files[ide] = (e, 1)
129174
continue
130175
evf_evfs_files[ide] = (e, 0)
131176
print(evf_evfs_files)
132177
return 0
133-
178+
179+
134180
if __name__ == "__main__":
135181
# metaminesweeper.exe -c filename.evf用法,检查文件的合法性
136182
# metaminesweeper.exe -c filename.evfs
@@ -142,7 +188,11 @@ def cli_check_file(file_path: str) -> int:
142188
if args.check:
143189
exit_code = cli_check_file(args.check)
144190
sys.exit(exit_code)
145-
191+
env = patch_env()
192+
context = AppContext("Metasweeper", "1.0.0", "元扫雷")
193+
PluginManager.instance().context = context
194+
195+
PluginManager.instance().start(Path(get_paths()) / "plugins", env)
146196

147197
app = QtWidgets.QApplication(sys.argv)
148198
serverName = "MineSweeperServer"
@@ -159,7 +209,8 @@ def cli_check_file(file_path: str) -> int:
159209
localServer = QLocalServer()
160210
localServer.listen(serverName)
161211
localServer.newConnection.connect(
162-
lambda: on_new_connection(localServer=localServer))
212+
lambda: on_new_connection(localServer=localServer)
213+
)
163214
mainWindow = mainWindowGUI.MainWindow()
164215
ui = mineSweeperGUI.MineSweeperGUI(mainWindow, sys.argv)
165216
ui.mainWindow.show()
@@ -169,16 +220,21 @@ def cli_check_file(file_path: str) -> int:
169220
hwnd = find_window(None, _translate("MainWindow", "元扫雷"))
170221

171222
SetWindowDisplayAffinity = ctypes.windll.user32.SetWindowDisplayAffinity
172-
ui.disable_screenshot = lambda: ... if SetWindowDisplayAffinity(
173-
hwnd, 0x00000011) else 1/0
174-
ui.enable_screenshot = lambda: ... if SetWindowDisplayAffinity(
175-
hwnd, 0x00000000) else 1/0
176-
ui.disable_screenshot = lambda: ... if SetWindowDisplayAffinity(
177-
hwnd, 0x00000011) else 1/0
178-
ui.enable_screenshot = lambda: ... if SetWindowDisplayAffinity(
179-
hwnd, 0x00000000) else 1/0
223+
ui.disable_screenshot = lambda: (
224+
... if SetWindowDisplayAffinity(hwnd, 0x00000011) else 1 / 0
225+
)
226+
ui.enable_screenshot = lambda: (
227+
... if SetWindowDisplayAffinity(hwnd, 0x00000000) else 1 / 0
228+
)
229+
ui.disable_screenshot = lambda: (
230+
... if SetWindowDisplayAffinity(hwnd, 0x00000011) else 1 / 0
231+
)
232+
ui.enable_screenshot = lambda: (
233+
... if SetWindowDisplayAffinity(hwnd, 0x00000000) else 1 / 0
234+
)
180235

181236
sys.exit(app.exec_())
237+
PluginManager.instance().stop()
182238
...
183239
# except:
184240
# pass

0 commit comments

Comments
 (0)