pyscreeps-arena 0.3.6__py3-none-any.whl → 0.5.7.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. pyscreeps_arena/__init__.py +59 -2
  2. pyscreeps_arena/compiler.py +568 -60
  3. pyscreeps_arena/core/config.py +1 -1
  4. pyscreeps_arena/core/const.py +6 -5
  5. pyscreeps_arena/localization.py +10 -0
  6. pyscreeps_arena/project.7z +0 -0
  7. pyscreeps_arena/ui/P2PY.py +108 -0
  8. pyscreeps_arena/ui/__init__.py +12 -0
  9. pyscreeps_arena/ui/creeplogic_edit.py +14 -0
  10. pyscreeps_arena/ui/map_render.py +705 -0
  11. pyscreeps_arena/ui/mapviewer.py +14 -0
  12. pyscreeps_arena/ui/project_ui.py +215 -0
  13. pyscreeps_arena/ui/qcreeplogic/__init__.py +3 -0
  14. pyscreeps_arena/ui/qcreeplogic/model.py +72 -0
  15. pyscreeps_arena/ui/qcreeplogic/qcreeplogic.py +770 -0
  16. pyscreeps_arena/ui/qmapv/__init__.py +3 -0
  17. pyscreeps_arena/ui/qmapv/qcinfo.py +567 -0
  18. pyscreeps_arena/ui/qmapv/qco.py +441 -0
  19. pyscreeps_arena/ui/qmapv/qmapv.py +728 -0
  20. pyscreeps_arena/ui/qmapv/test_array_drag.py +191 -0
  21. pyscreeps_arena/ui/qmapv/test_drag.py +107 -0
  22. pyscreeps_arena/ui/qmapv/test_qcinfo.py +169 -0
  23. pyscreeps_arena/ui/qmapv/test_qco_drag.py +7 -0
  24. pyscreeps_arena/ui/qmapv/test_qmapv.py +224 -0
  25. pyscreeps_arena/ui/qmapv/test_simple_array.py +303 -0
  26. pyscreeps_arena/ui/qrecipe/__init__.py +1 -0
  27. pyscreeps_arena/ui/qrecipe/model.py +434 -0
  28. pyscreeps_arena/ui/qrecipe/qrecipe.py +914 -0
  29. pyscreeps_arena/ui/rs_icon.py +43 -0
  30. {pyscreeps_arena-0.3.6.dist-info → pyscreeps_arena-0.5.7.1.dist-info}/METADATA +15 -3
  31. pyscreeps_arena-0.5.7.1.dist-info/RECORD +40 -0
  32. {pyscreeps_arena-0.3.6.dist-info → pyscreeps_arena-0.5.7.1.dist-info}/WHEEL +1 -1
  33. pyscreeps_arena-0.5.7.1.dist-info/entry_points.txt +4 -0
  34. pyscreeps_arena-0.3.6.dist-info/RECORD +0 -17
  35. pyscreeps_arena-0.3.6.dist-info/entry_points.txt +0 -2
  36. {pyscreeps_arena-0.3.6.dist-info → pyscreeps_arena-0.5.7.1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,770 @@
1
+ from PyQt6.QtWidgets import (
2
+ QWidget, QHBoxLayout, QVBoxLayout, QGridLayout, QLabel, QLineEdit,
3
+ QCheckBox, QSpinBox, QPushButton, QFrame, QGroupBox,
4
+ QComboBox, QApplication
5
+ )
6
+ from PyQt6.QtCore import (
7
+ pyqtProperty, pyqtSignal, Qt
8
+ )
9
+ from pyscreeps_arena.ui.qrecipe.qrecipe import QPSARecipe
10
+ from pyscreeps_arena.ui.qcreeplogic.model import CreepLogicSettings
11
+ from typing import List, Optional, Union
12
+
13
+ # Import configuration from build.py
14
+ import sys
15
+ import os
16
+ # Add the project root directory to Python path
17
+ sys.path.append(os.path.dirname(os.path.abspath(__file__)))
18
+ from pyscreeps_arena import config
19
+
20
+ # Language mapping
21
+ LANG = {
22
+ 'cn': {
23
+ 'class_name': '类名',
24
+ 'inherit_name': '继承类名',
25
+ 'properties': '属性设置',
26
+ 'functions': '函数控制',
27
+ 'creep_recipe': '爬虫配方',
28
+ 'reset': '重置',
29
+ 'copy': '复制',
30
+ 'name': 'NAME',
31
+ 'draw': 'DRAW',
32
+ 'layer': 'LAYER',
33
+ 'once': 'ONCE',
34
+ 'spawnable': 'SPAWNABLE',
35
+ 'optimise': 'OPTIMISE',
36
+ 'extension': 'EXTENSION',
37
+ 'direction': 'DIRECTION',
38
+ 'on_loading': 'onLoading',
39
+ 'on_start': 'onStart',
40
+ 'on_stop': 'onStop',
41
+ 'on_changed': 'onChanged',
42
+ 'on_killed': 'onKilled',
43
+ 'on_draw': 'onDraw',
44
+ },
45
+ 'en': {
46
+ 'class_name': 'Class Name',
47
+ 'inherit_name': 'Inherit Class',
48
+ 'properties': 'Properties',
49
+ 'functions': 'Functions',
50
+ 'creep_recipe': 'Creep Recipe',
51
+ 'reset': 'Reset',
52
+ 'copy': 'Copy',
53
+ 'name': 'NAME',
54
+ 'draw': 'DRAW',
55
+ 'layer': 'LAYER',
56
+ 'once': 'ONCE',
57
+ 'spawnable': 'SPAWNABLE',
58
+ 'optimise': 'OPTIMISE',
59
+ 'extension': 'EXTENSION',
60
+ 'direction': 'DIRECTION',
61
+ 'on_loading': 'onLoading',
62
+ 'on_start': 'onStart',
63
+ 'on_stop': 'onStop',
64
+ 'on_changed': 'onChanged',
65
+ 'on_killed': 'onKilled',
66
+ 'on_draw': 'onDraw',
67
+ }
68
+ }
69
+
70
+ def lang(key: str) -> str:
71
+ """Helper function to get translated text"""
72
+ return LANG[config.language if hasattr(config, 'language') and config.language in LANG else 'cn'][key]
73
+
74
+ # 全局样式常量
75
+ CHECKBOX_STYLE = "QCheckBox::indicator { width: 16px; height: 16px; border: 3px solid #555; border-radius: 5px; background-color: white; } QCheckBox::indicator:checked { background-color: #4CAF50; image: url('data:image/svg+xml;utf8,<svg xmlns=\'http://www.w3.org/2000/svg\' width=\'18\' height=\'18\' viewBox=\'0 0 24 24\'><path fill=\'white\' d=\'M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z\'/></svg>'); }"
76
+
77
+ class QPSACreepLogic(QWidget):
78
+ """
79
+ 爬虫逻辑设置组件,用于配置爬虫的基本属性和行为。
80
+ """
81
+
82
+ # 定义信号
83
+ onChanged = pyqtSignal()
84
+ onReset = pyqtSignal()
85
+ onCopy = pyqtSignal()
86
+
87
+ def __init__(self, parent: Optional[QWidget] = None):
88
+ super().__init__(parent)
89
+
90
+ # 模型
91
+ self._settings = CreepLogicSettings()
92
+
93
+ # QPSARecipe组件
94
+ self._qrecipe = QPSARecipe()
95
+ self._qrecipe.onChanged.connect(self._on_recipe_changed)
96
+
97
+ # 初始化UI
98
+ self.init_ui()
99
+
100
+ def init_ui(self):
101
+ main_layout = QVBoxLayout(self)
102
+ main_layout.setSpacing(15)
103
+ main_layout.setContentsMargins(10, 10, 10, 10)
104
+
105
+ # 1. 类名和继承类名行
106
+ class_row = QHBoxLayout()
107
+ class_row.setSpacing(10)
108
+
109
+ # 左边:类名
110
+ class_name_group = QWidget()
111
+ class_name_layout = QVBoxLayout(class_name_group)
112
+ class_name_layout.setContentsMargins(0, 0, 0, 0)
113
+ class_name_label = QLabel(lang('class_name'))
114
+ self._class_name_edit = QLineEdit()
115
+ self._class_name_edit.setPlaceholderText("MyCreep") # 类名默认为MyCreep的placeholder
116
+ class_name_layout.addWidget(class_name_label)
117
+ class_name_layout.addWidget(self._class_name_edit)
118
+ class_name_group.setFixedWidth(240) # 3:2比例,总宽度600的话
119
+
120
+ # 右边:继承类名
121
+ inherit_name_group = QWidget()
122
+ inherit_name_layout = QVBoxLayout(inherit_name_group)
123
+ inherit_name_layout.setContentsMargins(0, 0, 0, 0)
124
+ inherit_name_label = QLabel(lang('inherit_name'))
125
+ self._inherit_name_edit = QLineEdit("CreepLogic")
126
+ inherit_name_layout.addWidget(inherit_name_label)
127
+ inherit_name_layout.addWidget(self._inherit_name_edit)
128
+ inherit_name_group.setFixedWidth(160) # 3:2比例
129
+
130
+ class_row.addWidget(class_name_group)
131
+ class_row.addWidget(inherit_name_group)
132
+ class_row.addStretch()
133
+ main_layout.addLayout(class_row)
134
+
135
+ # 2. 属性字段行(参考engine.py设计,除了RECIPE)
136
+ properties_group = QGroupBox(lang('properties'))
137
+ properties_layout = QGridLayout(properties_group)
138
+ properties_layout.setSpacing(15)
139
+
140
+ # 设置列宽比例为1:1
141
+ properties_layout.setColumnStretch(0, 1) # 标签列
142
+ properties_layout.setColumnStretch(1, 1) # 控件列
143
+ properties_layout.setColumnStretch(2, 1) # 标签列
144
+ properties_layout.setColumnStretch(3, 1) # 控件列
145
+
146
+ # 设置固定宽度
147
+ label_width = 80
148
+
149
+ # 第一列
150
+ # NAME属性
151
+ name_label = QLabel(lang('name'))
152
+ name_label.setFixedWidth(label_width)
153
+ self._name_edit = QLineEdit()
154
+ # 设置初始PlaceHolder与默认类名一致
155
+ default_class_name = self._class_name_edit.text().strip() or "MyCreep"
156
+ self._name_edit.setPlaceholderText(default_class_name)
157
+ properties_layout.addWidget(name_label, 0, 0)
158
+ properties_layout.addWidget(self._name_edit, 0, 1)
159
+
160
+ # Draw属性
161
+ draw_label = QLabel(lang('draw'))
162
+ draw_label.setFixedWidth(label_width)
163
+ self._draw_checkbox = QCheckBox()
164
+ # 增加复选框大小
165
+ self._draw_checkbox.setStyleSheet(CHECKBOX_STYLE)
166
+ properties_layout.addWidget(draw_label, 1, 0)
167
+ properties_layout.addWidget(self._draw_checkbox, 1, 1)
168
+
169
+ # Layer属性
170
+ layer_label = QLabel(lang('layer'))
171
+ layer_label.setFixedWidth(label_width)
172
+ self._layer_spinbox = QSpinBox()
173
+ self._layer_spinbox.setRange(0, 100)
174
+ self._layer_spinbox.setValue(10)
175
+ properties_layout.addWidget(layer_label, 2, 0)
176
+ properties_layout.addWidget(self._layer_spinbox, 2, 1)
177
+
178
+ # Once属性
179
+ once_label = QLabel(lang('once'))
180
+ once_label.setFixedWidth(label_width)
181
+ self._once_checkbox = QCheckBox()
182
+ self._once_checkbox.setChecked(True)
183
+ # 增加复选框大小
184
+ self._once_checkbox.setStyleSheet(CHECKBOX_STYLE)
185
+ properties_layout.addWidget(once_label, 3, 0)
186
+ properties_layout.addWidget(self._once_checkbox, 3, 1)
187
+
188
+ # 第二列
189
+ # Spawnable属性
190
+ spawnable_label = QLabel(lang('spawnable'))
191
+ spawnable_label.setFixedWidth(label_width)
192
+ self._spawnable_checkbox = QCheckBox()
193
+ self._spawnable_checkbox.setChecked(True)
194
+ # 增加复选框大小
195
+ self._spawnable_checkbox.setStyleSheet(CHECKBOX_STYLE)
196
+ properties_layout.addWidget(spawnable_label, 0, 2)
197
+ properties_layout.addWidget(self._spawnable_checkbox, 0, 3)
198
+
199
+ # Optimise属性
200
+ optimise_label = QLabel(lang('optimise'))
201
+ optimise_label.setFixedWidth(label_width)
202
+ self._optimise_checkbox = QCheckBox()
203
+ self._optimise_checkbox.setChecked(True)
204
+ # 增加复选框大小
205
+ self._optimise_checkbox.setStyleSheet(CHECKBOX_STYLE)
206
+ # 连接信号,实现与QPSARecipe的'自动优化'同步
207
+ self._optimise_checkbox.stateChanged.connect(self._on_optimise_changed)
208
+ properties_layout.addWidget(optimise_label, 1, 2)
209
+ properties_layout.addWidget(self._optimise_checkbox, 1, 3)
210
+
211
+ # Extension属性
212
+ extension_label = QLabel(lang('extension'))
213
+ extension_label.setFixedWidth(label_width)
214
+ self._extension_checkbox = QCheckBox()
215
+ self._extension_checkbox.setChecked(True)
216
+ # 增加复选框大小
217
+ self._extension_checkbox.setStyleSheet(CHECKBOX_STYLE)
218
+ properties_layout.addWidget(extension_label, 2, 2)
219
+ properties_layout.addWidget(self._extension_checkbox, 2, 3)
220
+
221
+ # Direction属性
222
+ direction_label = QLabel(lang('direction'))
223
+ direction_label.setFixedWidth(label_width)
224
+ # 使用QComboBox显示方向符号
225
+ self._direction_combo = QComboBox()
226
+ self._direction_combo.addItem("None", None)
227
+ self._direction_combo.addItem("IN", 9) # IN_DIRECT
228
+ self._direction_combo.addItem("OUT", 10) # OUT_DIRECT
229
+ self._direction_combo.addItem("↑", 1) # TOP
230
+ self._direction_combo.addItem("↗", 2) # TOP_RIGHT
231
+ self._direction_combo.addItem("→", 3) # RIGHT
232
+ self._direction_combo.addItem("↘", 4) # BOTTOM_RIGHT
233
+ self._direction_combo.addItem("↓", 5) # BOTTOM
234
+ self._direction_combo.addItem("↙", 6) # BOTTOM_LEFT
235
+ self._direction_combo.addItem("←", 7) # LEFT
236
+ self._direction_combo.addItem("↖", 8) # TOP_LEFT
237
+ self._direction_combo.currentIndexChanged.connect(self._on_settings_changed)
238
+ properties_layout.addWidget(direction_label, 3, 2)
239
+ properties_layout.addWidget(self._direction_combo, 3, 3)
240
+
241
+ main_layout.addWidget(properties_group)
242
+
243
+ # 3.5 函数控制行
244
+ functions_group = QGroupBox(lang('functions'))
245
+ functions_layout = QGridLayout(functions_group)
246
+ functions_layout.setHorizontalSpacing(20) # 水平间距20px
247
+ functions_layout.setVerticalSpacing(10) # 垂直间距10px
248
+
249
+ # onLoading复选框
250
+ self._on_loading_checkbox = QCheckBox(lang('on_loading'))
251
+ self._on_loading_checkbox.setChecked(True) # 默认开启
252
+ self._on_loading_checkbox.setStyleSheet(CHECKBOX_STYLE)
253
+ functions_layout.addWidget(self._on_loading_checkbox, 0, 0)
254
+
255
+ # onStart复选框
256
+ self._on_start_checkbox = QCheckBox(lang('on_start'))
257
+ self._on_start_checkbox.setChecked(False) # 默认关闭
258
+ self._on_start_checkbox.setStyleSheet(CHECKBOX_STYLE)
259
+ functions_layout.addWidget(self._on_start_checkbox, 0, 1)
260
+
261
+ # onStop复选框
262
+ self._on_stop_checkbox = QCheckBox(lang('on_stop'))
263
+ self._on_stop_checkbox.setChecked(False) # 默认关闭
264
+ self._on_stop_checkbox.setStyleSheet(CHECKBOX_STYLE)
265
+ functions_layout.addWidget(self._on_stop_checkbox, 0, 2)
266
+
267
+ # onChanged复选框
268
+ self._on_changed_checkbox = QCheckBox(lang('on_changed'))
269
+ self._on_changed_checkbox.setChecked(False) # 默认关闭
270
+ self._on_changed_checkbox.setStyleSheet(CHECKBOX_STYLE)
271
+ functions_layout.addWidget(self._on_changed_checkbox, 1, 0)
272
+
273
+ # onKilled复选框
274
+ self._on_killed_checkbox = QCheckBox(lang('on_killed'))
275
+ self._on_killed_checkbox.setChecked(False) # 默认关闭
276
+ self._on_killed_checkbox.setStyleSheet(CHECKBOX_STYLE)
277
+ functions_layout.addWidget(self._on_killed_checkbox, 1, 1)
278
+
279
+ # onDraw复选框
280
+ self._on_draw_checkbox = QCheckBox(lang('on_draw'))
281
+ self._on_draw_checkbox.setChecked(False) # 默认关闭
282
+ self._on_draw_checkbox.setStyleSheet(CHECKBOX_STYLE)
283
+ functions_layout.addWidget(self._on_draw_checkbox, 1, 2)
284
+ main_layout.addWidget(functions_group)
285
+
286
+ # 4. QPSARecipe组件
287
+ recipe_group = QGroupBox(lang('creep_recipe'))
288
+ recipe_layout = QVBoxLayout(recipe_group)
289
+ recipe_layout.addWidget(self._qrecipe)
290
+ main_layout.addWidget(recipe_group)
291
+
292
+ # 5. 按钮行
293
+ buttons_row = QHBoxLayout()
294
+ buttons_row.setSpacing(10)
295
+
296
+ # Reset按钮
297
+ self._reset_button = QPushButton(lang('reset'))
298
+ self._reset_button.clicked.connect(self._on_reset_clicked)
299
+
300
+ # Copy按钮
301
+ self._copy_button = QPushButton(lang('copy'))
302
+ self._copy_button.clicked.connect(self._on_copy_clicked)
303
+
304
+ buttons_row.addWidget(self._reset_button)
305
+ buttons_row.addWidget(self._copy_button)
306
+ buttons_row.addStretch()
307
+ main_layout.addLayout(buttons_row)
308
+
309
+ # 连接信号
310
+ self._connect_signals()
311
+
312
+ def _connect_signals(self):
313
+ """
314
+ 连接所有信号
315
+ """
316
+ # 类名和继承类名信号
317
+ self._class_name_edit.textChanged.connect(self._on_settings_changed)
318
+ self._class_name_edit.textChanged.connect(self._on_class_name_changed)
319
+ self._inherit_name_edit.textChanged.connect(self._on_settings_changed)
320
+
321
+ # NAME字段信号
322
+ self._name_edit.textChanged.connect(self._on_settings_changed)
323
+
324
+ # 属性字段信号
325
+ self._draw_checkbox.stateChanged.connect(self._on_settings_changed)
326
+ self._layer_spinbox.valueChanged.connect(self._on_settings_changed)
327
+ self._once_checkbox.stateChanged.connect(self._on_settings_changed)
328
+ self._spawnable_checkbox.stateChanged.connect(self._on_settings_changed)
329
+ self._extension_checkbox.stateChanged.connect(self._on_settings_changed)
330
+
331
+ # 连接QPSARecipe的onChanged信号,用于同步optimise设置
332
+ self._qrecipe.onChanged.connect(self._on_qrecipe_changed)
333
+
334
+ def _on_settings_changed(self):
335
+ """
336
+ 设置改变时更新模型并发出信号
337
+ """
338
+ self._update_settings()
339
+ self.onChanged.emit()
340
+
341
+ def _on_class_name_changed(self):
342
+ """
343
+ 类名改变时更新NAME的PlaceHolder
344
+ """
345
+ # 获取当前类名或默认值
346
+ class_name = self._class_name_edit.text().strip() or "MyCreep"
347
+ # 更新NAME的PlaceHolder与类名一致
348
+ self._name_edit.setPlaceholderText(class_name)
349
+
350
+ def _on_recipe_changed(self):
351
+ """
352
+ 配方改变时更新模型并发出信号
353
+ """
354
+ self._settings.recipe = self._qrecipe.recipe
355
+ self.onChanged.emit()
356
+
357
+ def _on_optimise_changed(self, state):
358
+ """
359
+ OPTIMISE复选框改变时同步QPSARecipe的'自动优化'设置
360
+ """
361
+ optimise = state == Qt.CheckState.Checked.value
362
+ self._settings.optimise = optimise
363
+ # 同步QPSARecipe的optimise设置
364
+ self._qrecipe.optimise = optimise
365
+ self.onChanged.emit()
366
+
367
+ def _on_qrecipe_changed(self):
368
+ """
369
+ QPSARecipe改变时同步optimise设置
370
+ """
371
+ # 只有当QPSARecipe的optimise设置与当前不同时才更新
372
+ if self._qrecipe.optimise != self._settings.optimise:
373
+ self._settings.optimise = self._qrecipe.optimise
374
+ self._optimise_checkbox.setChecked(self._qrecipe.optimise)
375
+ self.onChanged.emit()
376
+
377
+ def _on_reset_clicked(self):
378
+ """
379
+ Reset按钮点击事件
380
+ """
381
+ self.reset()
382
+ self.onReset.emit()
383
+
384
+ def _on_copy_clicked(self):
385
+ """
386
+ Copy按钮点击事件
387
+ """
388
+ # 生成Python代码
389
+ python_code = self.generate_python_code()
390
+ # 将代码复制到剪贴板
391
+ clipboard = QApplication.clipboard()
392
+ clipboard.setText(python_code)
393
+ self.onCopy.emit()
394
+
395
+ def generate_python_code(self) -> str:
396
+ """
397
+ 生成Python代码,以class <classname>(inherit)开始
398
+ """
399
+ self._update_settings()
400
+
401
+ # 获取类名和继承类名
402
+ class_name = self._class_name_edit.text().strip() or "MyCreep"
403
+ inherit_name = self._inherit_name_edit.text().strip() or "CreepLogic"
404
+
405
+ # 构建类定义
406
+ code_lines = []
407
+ code_lines.append(f"class {class_name}({inherit_name}):")
408
+ name_value = self._settings.name if self._settings.name else class_name
409
+ code_lines.append(f" NAME = \"{name_value}\"")
410
+
411
+ # 添加属性
412
+ if self._settings.draw:
413
+ code_lines.append(f" DRAW = {self._settings.draw}")
414
+ if self._settings.layer != 10:
415
+ code_lines.append(f" LAYER = {self._settings.layer}")
416
+ if self._settings.link is not None:
417
+ if isinstance(self._settings.link, list):
418
+ code_lines.append(f" LINK = {self._settings.link}")
419
+ else:
420
+ code_lines.append(f" LINK = \"{self._settings.link}\"")
421
+ if not self._settings.once:
422
+ code_lines.append(f" ONCE = {self._settings.once}")
423
+ if not self._settings.spawnable:
424
+ code_lines.append(f" SPAWNABLE = {self._settings.spawnable}")
425
+
426
+ # 添加配方,使用qrecipe的.string属性
427
+ recipe_string = self._qrecipe.string
428
+ if recipe_string:
429
+ code_lines.append(f" RECIPE = \"{recipe_string}\"")
430
+
431
+ if not self._settings.optimise:
432
+ code_lines.append(f" OPTIMISE = {self._settings.optimise}")
433
+ if not self._settings.extension:
434
+ code_lines.append(f" EXTENSION = {self._settings.extension}")
435
+ if self._settings.direction is not None:
436
+ # 方向映射:数字 -> 常量名称
437
+ direction_map = {
438
+ 1: "TOP",
439
+ 2: "TOP_RIGHT",
440
+ 3: "RIGHT",
441
+ 4: "BOTTOM_RIGHT",
442
+ 5: "BOTTOM",
443
+ 6: "BOTTOM_LEFT",
444
+ 7: "LEFT",
445
+ 8: "TOP_LEFT",
446
+ 9: "IN_DIRECT",
447
+ 10: "OUT_DIRECT"
448
+ }
449
+ direction_name = direction_map.get(self._settings.direction, self._settings.direction)
450
+ code_lines.append(f" DIRECTION = {direction_name}")
451
+
452
+ # 添加空行和基本方法框架
453
+ # 根据复选框状态决定是否生成onLoading方法
454
+ if self._on_loading_checkbox.isChecked():
455
+ code_lines.append("")
456
+ code_lines.append(" def onLoading(self, c: Creep | None, k: GlobalKnowledge, *refs: \"CreepLogic\") -> None:")
457
+ code_lines.append(" # 初始化逻辑")
458
+ code_lines.append(" pass")
459
+
460
+ # 根据复选框状态决定是否生成onStart方法
461
+ if self._on_start_checkbox.isChecked():
462
+ code_lines.append("")
463
+ code_lines.append(" def onStart(self, c: Creep, k: GlobalKnowledge, *refs: \"CreepLogic\") -> None:")
464
+ code_lines.append(" # 启动逻辑")
465
+ code_lines.append(" pass")
466
+
467
+ # 必生成onStep方法
468
+ code_lines.append("")
469
+ code_lines.append(" def onStep(self, c: Creep, k: GlobalKnowledge, *refs):")
470
+ code_lines.append(" # 主逻辑")
471
+ code_lines.append(" pass")
472
+
473
+ # 根据复选框状态决定是否生成onStop方法
474
+ if self._on_stop_checkbox.isChecked():
475
+ code_lines.append("")
476
+ code_lines.append(" def onStop(self, c: Creep | None, k: GlobalKnowledge, *refs: \"CreepLogic\") -> None:")
477
+ code_lines.append(" # 停止逻辑")
478
+ code_lines.append(" pass")
479
+
480
+ # 根据复选框状态决定是否生成onChanged方法
481
+ if self._on_changed_checkbox.isChecked():
482
+ code_lines.append("")
483
+ code_lines.append(" def onChanged(self, src: str, dst: str, inst: any, k: GlobalKnowledge):")
484
+ code_lines.append(" # 状态变化逻辑")
485
+ code_lines.append(" pass")
486
+
487
+ # 根据复选框状态决定是否生成onKilled方法
488
+ if self._on_killed_checkbox.isChecked():
489
+ code_lines.append("")
490
+ code_lines.append(" def onKilled(self, c: Creep | None, k: GlobalKnowledge, *refs: \"CreepLogic\") -> None:")
491
+ code_lines.append(" # 被杀死逻辑")
492
+ code_lines.append(" pass")
493
+
494
+ # 根据复选框状态决定是否生成onDraw方法
495
+ if self._on_draw_checkbox.isChecked():
496
+ code_lines.append("")
497
+ code_lines.append(" def onDraw(self, c: Creep, v: View, k: GlobalKnowledge, *refs: \"CreepLogic\") -> None:")
498
+ code_lines.append(" # 绘制逻辑")
499
+ code_lines.append(" pass")
500
+
501
+ # 合并所有行
502
+ return "\n".join(code_lines)
503
+
504
+ def _update_settings(self):
505
+ """
506
+ 从UI更新模型
507
+ """
508
+ # 更新NAME
509
+ self._settings.name = self._name_edit.text()
510
+
511
+ # 更新属性
512
+ self._settings.draw = self._draw_checkbox.isChecked()
513
+ self._settings.layer = self._layer_spinbox.value()
514
+
515
+ # 移除LINK的设定
516
+ self._settings.link = None
517
+
518
+ self._settings.once = self._once_checkbox.isChecked()
519
+ self._settings.spawnable = self._spawnable_checkbox.isChecked()
520
+ self._settings.optimise = self._optimise_checkbox.isChecked()
521
+ self._settings.extension = self._extension_checkbox.isChecked()
522
+
523
+ # 处理DIRECTION
524
+ direction_val = self._direction_combo.currentData()
525
+ self._settings.direction = direction_val
526
+
527
+ def reset(self):
528
+ """
529
+ 重置所有设置为默认值
530
+ """
531
+ # 重置模型
532
+ self._settings = CreepLogicSettings()
533
+
534
+ # 重置UI
535
+ self._class_name_edit.clear()
536
+ self._inherit_name_edit.setText("CreepLogic")
537
+ self._name_edit.clear()
538
+
539
+ # 重置属性
540
+ self._draw_checkbox.setChecked(False)
541
+ self._layer_spinbox.setValue(10)
542
+ # 移除LINK的设定,无需重置
543
+ self._once_checkbox.setChecked(True)
544
+ self._spawnable_checkbox.setChecked(True)
545
+ self._qrecipe.recipe = ["MOVE"]
546
+ self._optimise_checkbox.setChecked(True)
547
+ # 同步QPSARecipe的optimise设置
548
+ self._qrecipe.optimise = True
549
+ self._extension_checkbox.setChecked(True)
550
+ self._direction_combo.setCurrentIndex(0)
551
+
552
+ # 重置函数控制复选框
553
+ self._on_loading_checkbox.setChecked(True)
554
+ self._on_start_checkbox.setChecked(False)
555
+ self._on_stop_checkbox.setChecked(False)
556
+ self._on_changed_checkbox.setChecked(False)
557
+ self._on_killed_checkbox.setChecked(False)
558
+ self._on_draw_checkbox.setChecked(False)
559
+
560
+ self.onChanged.emit()
561
+
562
+ def get_settings(self) -> CreepLogicSettings:
563
+ """
564
+ 获取当前设置
565
+ """
566
+ self._update_settings()
567
+ return self._settings
568
+
569
+ def set_settings(self, settings: CreepLogicSettings):
570
+ """
571
+ 设置当前配置
572
+ """
573
+ self._settings = settings
574
+
575
+ # 更新UI
576
+ self._name_edit.setText(settings.name)
577
+
578
+ # 更新属性
579
+ self._draw_checkbox.setChecked(settings.draw)
580
+ self._layer_spinbox.setValue(settings.layer)
581
+
582
+ # 移除LINK的设定,无需更新
583
+
584
+ self._once_checkbox.setChecked(settings.once)
585
+ self._spawnable_checkbox.setChecked(settings.spawnable)
586
+ self._qrecipe.recipe = settings.recipe if isinstance(settings.recipe, list) else ["MOVE"]
587
+ self._optimise_checkbox.setChecked(settings.optimise)
588
+ # 同步QPSARecipe的optimise设置
589
+ self._qrecipe.optimise = settings.optimise
590
+ self._extension_checkbox.setChecked(settings.extension)
591
+
592
+ # 更新DIRECTION
593
+ for i in range(self._direction_combo.count()):
594
+ if self._direction_combo.itemData(i) == settings.direction:
595
+ self._direction_combo.setCurrentIndex(i)
596
+ break
597
+
598
+ self.onChanged.emit()
599
+
600
+ # Properties
601
+ @pyqtProperty(str)
602
+ def name(self) -> str:
603
+ return self._settings.name
604
+
605
+ @name.setter
606
+ def name(self, value: str):
607
+ self._settings.name = value
608
+ self._name_edit.setText(value)
609
+ self.onChanged.emit()
610
+
611
+ @pyqtProperty(bool)
612
+ def draw(self) -> bool:
613
+ return self._settings.draw
614
+
615
+ @draw.setter
616
+ def draw(self, value: bool):
617
+ self._settings.draw = value
618
+ self._draw_checkbox.setChecked(value)
619
+ self.onChanged.emit()
620
+
621
+ @pyqtProperty(int)
622
+ def layer(self) -> int:
623
+ return self._settings.layer
624
+
625
+ @layer.setter
626
+ def layer(self, value: int):
627
+ self._settings.layer = value
628
+ self._layer_spinbox.setValue(value)
629
+ self.onChanged.emit()
630
+
631
+ @pyqtProperty(object)
632
+ def link(self) -> Union[List[str], str, None]:
633
+ return self._settings.link
634
+
635
+ @link.setter
636
+ def link(self, value: Union[List[str], str, None]):
637
+ self._settings.link = value
638
+ if value is None:
639
+ self._link_edit.clear()
640
+ elif isinstance(value, list):
641
+ self._link_edit.setText(", ".join(value))
642
+ else:
643
+ self._link_edit.setText(value)
644
+ self.onChanged.emit()
645
+
646
+ @pyqtProperty(bool)
647
+ def once(self) -> bool:
648
+ return self._settings.once
649
+
650
+ @once.setter
651
+ def once(self, value: bool):
652
+ self._settings.once = value
653
+ self._once_checkbox.setChecked(value)
654
+ self.onChanged.emit()
655
+
656
+ @pyqtProperty(bool)
657
+ def spawnable(self) -> bool:
658
+ return self._settings.spawnable
659
+
660
+ @spawnable.setter
661
+ def spawnable(self, value: bool):
662
+ self._settings.spawnable = value
663
+ self._spawnable_checkbox.setChecked(value)
664
+ self.onChanged.emit()
665
+
666
+ @pyqtProperty(list)
667
+ def recipe(self) -> List[str]:
668
+ return self._settings.recipe if isinstance(self._settings.recipe, list) else ["MOVE"]
669
+
670
+ @recipe.setter
671
+ def recipe(self, value: List[str]):
672
+ self._settings.recipe = value
673
+ self._qrecipe.recipe = value
674
+ self.onChanged.emit()
675
+
676
+ @pyqtProperty(bool)
677
+ def optimise(self) -> bool:
678
+ return self._settings.optimise
679
+
680
+ @optimise.setter
681
+ def optimise(self, value: bool):
682
+ self._settings.optimise = value
683
+ self._optimise_checkbox.setChecked(value)
684
+ self.onChanged.emit()
685
+
686
+ @pyqtProperty(bool)
687
+ def extension(self) -> bool:
688
+ return self._settings.extension
689
+
690
+ @extension.setter
691
+ def extension(self, value: bool):
692
+ self._settings.extension = value
693
+ self._extension_checkbox.setChecked(value)
694
+ self.onChanged.emit()
695
+
696
+ @pyqtProperty(object)
697
+ def direction(self) -> Optional[int]:
698
+ return self._settings.direction
699
+
700
+ @direction.setter
701
+ def direction(self, value: Optional[int]):
702
+ self._settings.direction = value
703
+ for i in range(self._direction_combo.count()):
704
+ if self._direction_combo.itemData(i) == value:
705
+ self._direction_combo.setCurrentIndex(i)
706
+ break
707
+ self.onChanged.emit()
708
+
709
+ @pyqtProperty(object)
710
+ def qrecipe(self) -> QPSARecipe:
711
+ return self._qrecipe
712
+
713
+ def to_dict(self) -> dict:
714
+ """
715
+ 将设置转换为字典格式
716
+ """
717
+ self._update_settings()
718
+ return {
719
+ "class_name": self._class_name_edit.text(),
720
+ "inherit_name": self._inherit_name_edit.text(),
721
+ **self._settings.to_dict()
722
+ }
723
+
724
+ def from_dict(self, data: dict):
725
+ """
726
+ 从字典格式加载设置
727
+ """
728
+ # 加载类名和继承类名
729
+ self._class_name_edit.setText(data.get("class_name", ""))
730
+ self._inherit_name_edit.setText(data.get("inherit_name", "CreepLogic"))
731
+
732
+ # 加载设置
733
+ self._settings = CreepLogicSettings.from_dict(data)
734
+ self.set_settings(self._settings)
735
+
736
+
737
+ if __name__ == "__main__":
738
+ """
739
+ 直接运行组件的主程序入口点
740
+ """
741
+ import sys
742
+ from PyQt6.QtWidgets import QApplication, QMainWindow, QVBoxLayout, QWidget
743
+
744
+ class MainWindow(QMainWindow):
745
+ def __init__(self):
746
+ super().__init__()
747
+ self.setWindowTitle("QPSACreepLogic Demo")
748
+ # 使用resize方法替换setWidth和setHeight
749
+ self.resize(380, 700)
750
+
751
+ # 中央部件
752
+ central_widget = QWidget()
753
+ main_layout = QVBoxLayout(central_widget)
754
+
755
+ # 添加QPSACreepLogic组件
756
+ self.creep_logic_widget = QPSACreepLogic()
757
+ main_layout.addWidget(self.creep_logic_widget)
758
+
759
+ self.setCentralWidget(central_widget)
760
+
761
+ # 创建应用程序和窗口
762
+ app = QApplication(sys.argv)
763
+ window = MainWindow()
764
+ window.show()
765
+
766
+ # 运行应用程序
767
+ sys.exit(app.exec())
768
+
769
+
770
+