Add Ghostbox hardware and logistics automation
This commit is contained in:
@@ -327,7 +327,9 @@ class GameLoopWorker(QThread):
|
||||
release_spirit_key=None,
|
||||
resurrect_key=None,
|
||||
enable_mouse_loot=True,
|
||||
use_hardware_input=True,
|
||||
use_hardware_input=None,
|
||||
use_tianya_box=None,
|
||||
use_ghost_box=None,
|
||||
turn_error_key=None,
|
||||
turn_error_hold_sec=None,
|
||||
distance_interact_pause_sec=None,
|
||||
@@ -374,7 +376,12 @@ class GameLoopWorker(QThread):
|
||||
self.release_spirit_key = release_spirit_key
|
||||
self.resurrect_key = resurrect_key
|
||||
self.enable_mouse_loot = enable_mouse_loot
|
||||
self.use_hardware_input = bool(use_hardware_input)
|
||||
if use_tianya_box is None and use_ghost_box is None:
|
||||
self.use_tianya_box = True if use_hardware_input is None else bool(use_hardware_input)
|
||||
self.use_ghost_box = False
|
||||
else:
|
||||
self.use_tianya_box = bool(use_tianya_box)
|
||||
self.use_ghost_box = bool(use_ghost_box)
|
||||
self.turn_error_key = (turn_error_key or "s").strip().lower() or "s"
|
||||
try:
|
||||
self.turn_error_hold_sec = float(turn_error_hold_sec)
|
||||
@@ -393,10 +400,14 @@ class GameLoopWorker(QThread):
|
||||
self.log_signal.emit("❌ 无法导入 game_state 模块")
|
||||
return
|
||||
|
||||
hw_ctrl.configure(use_hardware_input=self.use_hardware_input)
|
||||
hw_ctrl.configure(use_tianya_box=self.use_tianya_box, use_ghost_box=self.use_ghost_box)
|
||||
backend_text = {
|
||||
"hardware": "硬件",
|
||||
"hardware_unavailable": "硬件(不可用)",
|
||||
"hardware": "天涯盒子",
|
||||
"hardware_unavailable": "天涯盒子(不可用)",
|
||||
"tianya": "天涯盒子",
|
||||
"tianya_unavailable": "天涯盒子(不可用)",
|
||||
"ghost": "幽灵盒子",
|
||||
"ghost_unavailable": "幽灵盒子(不可用)",
|
||||
"directinput": "pydirectinput",
|
||||
"directinput_unavailable": "pydirectinput(不可用)",
|
||||
}.get(hw_ctrl.backend_label(), "未知")
|
||||
@@ -495,14 +506,19 @@ class GameLoopWorker(QThread):
|
||||
enable_mount=bool(layout.get("enable_mount", True)),
|
||||
)
|
||||
self.logistics_manager = LogisticsManager(route_file=self.vendor_path)
|
||||
self.logistics_manager.hearthstone_key = str(layout.get("hearthstone_key", "b") or "b")
|
||||
self.logistics_manager.hearthstone_cast_sec = float(layout.get("hearthstone_wait_sec", 12.0))
|
||||
self.logistics_manager.repair_target_key = str(layout.get("repair_target_key", "8") or "8")
|
||||
self.logistics_manager.repair_interact_key = str(layout.get("repair_interact_key", "4") or "4")
|
||||
|
||||
self.log_signal.emit(f"⛑️ 回城修理:开始执行路径({os.path.basename(self.vendor_path)})")
|
||||
|
||||
get_state = lambda: parse_game_state() if self.running else None
|
||||
ok = self.logistics_manager.run_route1_round(
|
||||
ok = self.logistics_manager.run_repair_flow(
|
||||
get_state,
|
||||
self.patrol_controller,
|
||||
route_file=self.vendor_path,
|
||||
stop_check=lambda: not self.running,
|
||||
use_hearthstone=True,
|
||||
)
|
||||
if ok:
|
||||
self.log_signal.emit("✅ 回城修理:路径完成")
|
||||
@@ -1069,6 +1085,18 @@ class WoWMultiKeyGUI(QMainWindow):
|
||||
|
||||
params_layout.addWidget(basic_group)
|
||||
|
||||
# 硬件参数
|
||||
hardware_group = QGroupBox("硬件参数")
|
||||
hardware_layout = QHBoxLayout(hardware_group)
|
||||
self.gs_use_tianya_box = QCheckBox("使用天涯盒子")
|
||||
self.gs_use_tianya_box.setChecked(True)
|
||||
self.gs_use_ghost_box = QCheckBox("使用幽灵盒子")
|
||||
self.gs_use_ghost_box.setChecked(False)
|
||||
hardware_layout.addWidget(self.gs_use_tianya_box)
|
||||
hardware_layout.addWidget(self.gs_use_ghost_box)
|
||||
hardware_layout.addStretch()
|
||||
params_layout.addWidget(hardware_group)
|
||||
|
||||
# 游戏参数
|
||||
game_group = QGroupBox("游戏参数")
|
||||
game_grid = QGridLayout(game_group)
|
||||
@@ -1140,6 +1168,29 @@ class WoWMultiKeyGUI(QMainWindow):
|
||||
self.gs_mail_send_wait.setSingleStep(1.0)
|
||||
self.gs_mail_send_wait.setValue(60.0)
|
||||
self.gs_mail_send_wait.setSuffix(" 秒")
|
||||
self.gs_logistics_full_auto = QCheckBox("后勤完成后继续自动巡逻")
|
||||
self.gs_logistics_full_auto.setChecked(False)
|
||||
self.gs_bag_slot_threshold = QSpinBox()
|
||||
self.gs_bag_slot_threshold.setRange(0, 100)
|
||||
self.gs_bag_slot_threshold.setValue(2)
|
||||
self.gs_bag_slot_threshold.setSuffix(" 格")
|
||||
self.gs_durability_threshold = QSpinBox()
|
||||
self.gs_durability_threshold.setRange(1, 100)
|
||||
self.gs_durability_threshold.setValue(20)
|
||||
self.gs_durability_threshold.setSuffix(" %")
|
||||
self.gs_hearthstone_wait = QDoubleSpinBox()
|
||||
self.gs_hearthstone_wait.setRange(1.0, 60.0)
|
||||
self.gs_hearthstone_wait.setSingleStep(0.5)
|
||||
self.gs_hearthstone_wait.setValue(12.0)
|
||||
self.gs_hearthstone_wait.setSuffix(" 秒")
|
||||
self.gs_repair_target_key = QLineEdit()
|
||||
self.gs_repair_target_key.setPlaceholderText("如 8")
|
||||
self.gs_repair_target_key.setMaxLength(16)
|
||||
self.gs_repair_target_key.setText("8")
|
||||
self.gs_repair_interact_key = QLineEdit()
|
||||
self.gs_repair_interact_key.setPlaceholderText("如 4")
|
||||
self.gs_repair_interact_key.setMaxLength(16)
|
||||
self.gs_repair_interact_key.setText("4")
|
||||
self.gs_enable_mount = QCheckBox("启用上马")
|
||||
self.gs_enable_mount.setChecked(True)
|
||||
self.gs_mount_key = QLineEdit()
|
||||
@@ -1166,8 +1217,6 @@ class WoWMultiKeyGUI(QMainWindow):
|
||||
self.gs_resurrect_key.setText("0")
|
||||
self.gs_enable_mouse_loot = QCheckBox("启用扫雷拾取")
|
||||
self.gs_enable_mouse_loot.setChecked(True)
|
||||
self.gs_use_hardware_input = QCheckBox("启用硬件控制(关闭则用 pydirectinput)")
|
||||
self.gs_use_hardware_input.setChecked(True)
|
||||
|
||||
# 网格填充
|
||||
game_grid.addWidget(QLabel("剥皮等待时间:"), 0, 0)
|
||||
@@ -1192,31 +1241,42 @@ class WoWMultiKeyGUI(QMainWindow):
|
||||
|
||||
game_grid.addWidget(QLabel("炉石按键:"), 4, 0)
|
||||
game_grid.addWidget(self.gs_hearthstone_key, 4, 1)
|
||||
game_grid.addWidget(QLabel("释放灵魂按键:"), 4, 2)
|
||||
game_grid.addWidget(self.gs_release_spirit_key, 4, 3)
|
||||
game_grid.addWidget(QLabel("炉石等待:"), 4, 2)
|
||||
game_grid.addWidget(self.gs_hearthstone_wait, 4, 3)
|
||||
|
||||
game_grid.addWidget(QLabel("需转身按键:"), 5, 0)
|
||||
game_grid.addWidget(self.turn_error_key_edit, 5, 1)
|
||||
game_grid.addWidget(QLabel("需转身按住时长:"), 6, 0)
|
||||
game_grid.addWidget(self.turn_error_hold_spin, 6, 1)
|
||||
game_grid.addWidget(QLabel("释放灵魂按键:"), 5, 0)
|
||||
game_grid.addWidget(self.gs_release_spirit_key, 5, 1)
|
||||
game_grid.addWidget(QLabel("复活按键:"), 5, 2)
|
||||
game_grid.addWidget(self.gs_resurrect_key, 5, 3)
|
||||
|
||||
game_grid.addWidget(QLabel("需转身按键:"), 6, 0)
|
||||
game_grid.addWidget(self.turn_error_key_edit, 6, 1)
|
||||
game_grid.addWidget(QLabel("需转身按住时长:"), 6, 2)
|
||||
game_grid.addWidget(self.turn_error_hold_spin, 6, 3)
|
||||
game_grid.addWidget(QLabel("距离远暂停技能时长:"), 7, 0)
|
||||
game_grid.addWidget(self.distance_interact_pause_spin, 7, 1)
|
||||
|
||||
game_grid.addWidget(self.gs_use_hardware_input, 8, 0, 1, 2)
|
||||
game_grid.addWidget(QLabel("复活按键:"), 6, 2)
|
||||
game_grid.addWidget(self.gs_resurrect_key, 6, 3)
|
||||
game_grid.addWidget(self.gs_bag_full_hearthstone, 9, 0, 1, 2)
|
||||
game_grid.addWidget(self.gs_enable_bag_full_mail, 9, 2, 1, 2)
|
||||
game_grid.addWidget(QLabel("邮箱交互键:"), 10, 0)
|
||||
game_grid.addWidget(self.gs_mailbox_interact_key, 10, 1)
|
||||
game_grid.addWidget(QLabel("收信人按键:"), 10, 2)
|
||||
game_grid.addWidget(self.gs_mail_recipient_key, 10, 3)
|
||||
game_grid.addWidget(QLabel("邮寄宏按键:"), 11, 0)
|
||||
game_grid.addWidget(self.gs_mail_send_key, 11, 1)
|
||||
game_grid.addWidget(QLabel("邮箱打开等待:"), 11, 2)
|
||||
game_grid.addWidget(self.gs_mailbox_open_wait, 11, 3)
|
||||
game_grid.addWidget(QLabel("邮寄后等待:"), 12, 0)
|
||||
game_grid.addWidget(self.gs_mail_send_wait, 12, 1)
|
||||
game_grid.addWidget(self.gs_bag_full_hearthstone, 8, 0, 1, 2)
|
||||
game_grid.addWidget(self.gs_enable_bag_full_mail, 8, 2, 1, 2)
|
||||
game_grid.addWidget(QLabel("邮箱交互键:"), 9, 0)
|
||||
game_grid.addWidget(self.gs_mailbox_interact_key, 9, 1)
|
||||
game_grid.addWidget(QLabel("收信人按键:"), 9, 2)
|
||||
game_grid.addWidget(self.gs_mail_recipient_key, 9, 3)
|
||||
game_grid.addWidget(QLabel("邮寄宏按键:"), 10, 0)
|
||||
game_grid.addWidget(self.gs_mail_send_key, 10, 1)
|
||||
game_grid.addWidget(QLabel("邮箱打开等待:"), 10, 2)
|
||||
game_grid.addWidget(self.gs_mailbox_open_wait, 10, 3)
|
||||
game_grid.addWidget(QLabel("邮寄后等待:"), 11, 0)
|
||||
game_grid.addWidget(self.gs_mail_send_wait, 11, 1)
|
||||
game_grid.addWidget(self.gs_logistics_full_auto, 11, 2, 1, 2)
|
||||
game_grid.addWidget(QLabel("包格触发阈值:"), 12, 0)
|
||||
game_grid.addWidget(self.gs_bag_slot_threshold, 12, 1)
|
||||
game_grid.addWidget(QLabel("耐久触发阈值:"), 12, 2)
|
||||
game_grid.addWidget(self.gs_durability_threshold, 12, 3)
|
||||
game_grid.addWidget(QLabel("修理目标键:"), 13, 0)
|
||||
game_grid.addWidget(self.gs_repair_target_key, 13, 1)
|
||||
game_grid.addWidget(QLabel("修理交互键:"), 13, 2)
|
||||
game_grid.addWidget(self.gs_repair_interact_key, 13, 3)
|
||||
|
||||
params_layout.addWidget(game_group)
|
||||
|
||||
@@ -1263,6 +1323,15 @@ class WoWMultiKeyGUI(QMainWindow):
|
||||
self.gs_mail_send_key.setText(str(cfg.get('mail_send_key', 'f8') or 'f8'))
|
||||
self.gs_mailbox_open_wait.setValue(float(cfg.get('mailbox_open_wait_sec', 2.0)))
|
||||
self.gs_mail_send_wait.setValue(float(cfg.get('mail_send_wait_sec', 60.0)))
|
||||
self.gs_logistics_full_auto.setChecked(bool(cfg.get('logistics_full_auto', False)))
|
||||
self.gs_bag_slot_threshold.setValue(int(cfg.get('bag_slot_threshold', 2)))
|
||||
durability_threshold = float(cfg.get('durability_threshold', 0.2))
|
||||
if durability_threshold <= 1.0:
|
||||
durability_threshold *= 100.0
|
||||
self.gs_durability_threshold.setValue(int(round(durability_threshold)))
|
||||
self.gs_hearthstone_wait.setValue(float(cfg.get('hearthstone_wait_sec', 12.0)))
|
||||
self.gs_repair_target_key.setText(str(cfg.get('repair_target_key', '8') or '8'))
|
||||
self.gs_repair_interact_key.setText(str(cfg.get('repair_interact_key', '4') or '4'))
|
||||
self.gs_mount_retry.setValue(float(cfg.get('mount_retry_after_sec', 2.0)))
|
||||
self.gs_release_spirit_key.setText(str(cfg.get('release_spirit_key', '9') or '9'))
|
||||
self.gs_resurrect_key.setText(str(cfg.get('resurrect_key', '0') or '0'))
|
||||
@@ -1279,7 +1348,15 @@ class WoWMultiKeyGUI(QMainWindow):
|
||||
self.turn_error_hold_spin.setValue(float(bot_cfg.get('turn_error_hold_sec', 0.8)))
|
||||
self.distance_interact_pause_spin.setValue(float(bot_cfg.get('distance_interact_pause_sec', 1.0)))
|
||||
self.gs_enable_mouse_loot.setChecked(bool(bot_cfg.get('enable_mouse_loot', True)))
|
||||
self.gs_use_hardware_input.setChecked(bool(bot_cfg.get('use_hardware_input', True)))
|
||||
has_box_flags = ('use_tianya_box' in bot_cfg) or ('use_ghost_box' in bot_cfg)
|
||||
if has_box_flags:
|
||||
use_tianya_box = bool(bot_cfg.get('use_tianya_box', False))
|
||||
use_ghost_box = bool(bot_cfg.get('use_ghost_box', False))
|
||||
else:
|
||||
use_tianya_box = bool(bot_cfg.get('use_hardware_input', True))
|
||||
use_ghost_box = False
|
||||
self.gs_use_tianya_box.setChecked(use_tianya_box)
|
||||
self.gs_use_ghost_box.setChecked(use_ghost_box)
|
||||
except Exception:
|
||||
self.skinning_wait_spin.setValue(1.5)
|
||||
self.food_key_edit.setText('f1')
|
||||
@@ -1289,7 +1366,8 @@ class WoWMultiKeyGUI(QMainWindow):
|
||||
self.turn_error_hold_spin.setValue(0.8)
|
||||
self.distance_interact_pause_spin.setValue(1.0)
|
||||
self.gs_enable_mouse_loot.setChecked(True)
|
||||
self.gs_use_hardware_input.setChecked(True)
|
||||
self.gs_use_tianya_box.setChecked(True)
|
||||
self.gs_use_ghost_box.setChecked(False)
|
||||
|
||||
def _save_params_config(self):
|
||||
"""保存「参数配置」界面到 game_state_config.json(多分辨率)并写入 wow_multikey_qt.json(bot 参数)"""
|
||||
@@ -1314,6 +1392,12 @@ class WoWMultiKeyGUI(QMainWindow):
|
||||
cfg['mail_send_key'] = self.gs_mail_send_key.text().strip() or 'f8'
|
||||
cfg['mailbox_open_wait_sec'] = float(self.gs_mailbox_open_wait.value())
|
||||
cfg['mail_send_wait_sec'] = float(self.gs_mail_send_wait.value())
|
||||
cfg['logistics_full_auto'] = self.gs_logistics_full_auto.isChecked()
|
||||
cfg['bag_slot_threshold'] = int(self.gs_bag_slot_threshold.value())
|
||||
cfg['durability_threshold'] = float(self.gs_durability_threshold.value()) / 100.0
|
||||
cfg['hearthstone_wait_sec'] = float(self.gs_hearthstone_wait.value())
|
||||
cfg['repair_target_key'] = self.gs_repair_target_key.text().strip() or '8'
|
||||
cfg['repair_interact_key'] = self.gs_repair_interact_key.text().strip() or '4'
|
||||
cfg['release_spirit_key'] = (self.gs_release_spirit_key.text().strip() or '9')
|
||||
cfg['resurrect_key'] = (self.gs_resurrect_key.text().strip() or '0')
|
||||
path = save_layout_config(cfg)
|
||||
@@ -1328,10 +1412,14 @@ class WoWMultiKeyGUI(QMainWindow):
|
||||
self.config['bot']['turn_error_hold_sec'] = float(self.turn_error_hold_spin.value())
|
||||
self.config['bot']['distance_interact_pause_sec'] = float(self.distance_interact_pause_spin.value())
|
||||
self.config['bot']['enable_mouse_loot'] = self.gs_enable_mouse_loot.isChecked()
|
||||
self.config['bot']['use_hardware_input'] = self.gs_use_hardware_input.isChecked()
|
||||
use_tianya_box = self.gs_use_tianya_box.isChecked()
|
||||
use_ghost_box = self.gs_use_ghost_box.isChecked()
|
||||
self.config['bot']['use_tianya_box'] = use_tianya_box
|
||||
self.config['bot']['use_ghost_box'] = use_ghost_box
|
||||
self.config['bot']['use_hardware_input'] = use_tianya_box or use_ghost_box
|
||||
self._save_main_config()
|
||||
from hardware_control import hw_ctrl
|
||||
hw_ctrl.configure(use_hardware_input=self.gs_use_hardware_input.isChecked())
|
||||
hw_ctrl.configure(use_tianya_box=use_tianya_box, use_ghost_box=use_ghost_box)
|
||||
|
||||
self.log(f"✅ 参数配置已保存至 {path},并更新 bot 参数")
|
||||
QMessageBox.information(self, "保存成功", f"参数配置已保存至:\n{path}\n\nBot 参数已写入:\n{self.config_path}")
|
||||
@@ -1824,7 +1912,8 @@ class WoWMultiKeyGUI(QMainWindow):
|
||||
resurrect_key = '0'
|
||||
|
||||
enable_mouse_loot = self.gs_enable_mouse_loot.isChecked()
|
||||
use_hardware_input = self.gs_use_hardware_input.isChecked()
|
||||
use_tianya_box = self.gs_use_tianya_box.isChecked()
|
||||
use_ghost_box = self.gs_use_ghost_box.isChecked()
|
||||
|
||||
self.game_worker = GameLoopWorker(
|
||||
mode, waypoints_path=waypoints_path, prepare_route_path=prepare_route_path, vendor_path=vendor_path,
|
||||
@@ -1847,7 +1936,8 @@ class WoWMultiKeyGUI(QMainWindow):
|
||||
release_spirit_key=release_spirit_key,
|
||||
resurrect_key=resurrect_key,
|
||||
enable_mouse_loot=enable_mouse_loot,
|
||||
use_hardware_input=use_hardware_input,
|
||||
use_tianya_box=use_tianya_box,
|
||||
use_ghost_box=use_ghost_box,
|
||||
turn_error_key=turn_error_key,
|
||||
turn_error_hold_sec=turn_error_hold_sec,
|
||||
distance_interact_pause_sec=distance_interact_pause_sec,
|
||||
@@ -1880,7 +1970,13 @@ class WoWMultiKeyGUI(QMainWindow):
|
||||
min_dist = float(self.record_min_distance_spin.value())
|
||||
except Exception:
|
||||
min_dist = 0.5
|
||||
self.game_worker = GameLoopWorker(mode='record', record_filename=name, record_min_distance=min_dist)
|
||||
self.game_worker = GameLoopWorker(
|
||||
mode='record',
|
||||
record_filename=name,
|
||||
record_min_distance=min_dist,
|
||||
use_tianya_box=self.gs_use_tianya_box.isChecked(),
|
||||
use_ghost_box=self.gs_use_ghost_box.isChecked(),
|
||||
)
|
||||
self.game_worker.state_signal.connect(self.record_state_label.setText)
|
||||
self.game_worker.log_signal.connect(self.log)
|
||||
self.game_worker.finished.connect(self._on_record_finished)
|
||||
|
||||
Reference in New Issue
Block a user