Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 31 additions & 31 deletions auto_fetch.py
Original file line number Diff line number Diff line change
Expand Up @@ -405,7 +405,7 @@ def save_statistics_to_log(self):
stats_text = (
f"总共填写次数: {self.total_fill_count}\n"
f"填写×次数: {self.incorrect_fill_count}\n"
f"当次运行时长: {int(hours)}小时{int(minutes)}分钟\n"
f"运行: {int(hours)}小时{int(minutes)}分钟\n"
)
with open("log.txt", "a", encoding="utf-8") as log_file:
log_file.write(stats_text)
Expand Down Expand Up @@ -454,7 +454,7 @@ def recognize_and_predict(self, screenshot = None):
else:
logger.error("识别结果有错误,本轮跳过")
# 选择预测方法
if self.cannot_model.is_model_loaded:
if self.cannot_model and self.cannot_model.is_model_loaded:
if self.field_recognizer is not None:
# 构建包含地形的完整特征向量
full_features = self.build_terrain_features(left_counts, right_counts)
Expand Down Expand Up @@ -580,18 +580,17 @@ def auto_fetch_data(self):

self.state_start_time = time.time() # 重置状态开始时间

# UNKNOWN 状态超时检测
# 非战斗状态:超过 36 秒触发重启(登录过程、主菜单、模式选择等)
# 战斗流程状态:超过 200 秒触发重启(防止战斗卡死)
# 全局超时检测:无论什么状态,只要超过时间都可能触发重启
# 非战斗状态:超过 50 秒触发重启
# 战斗流程状态:超过 120 秒触发重启(防止战斗卡死)
elapsed_time = time.time() - self.state_start_time
is_battle_state = self.last_state in [GameState.PRE_BATTLE, GameState.IN_BATTLE, GameState.SETTLEMENT, GameState.FINISHED]
timeout_threshold = 200.0 if is_battle_state else 36.0
timeout_threshold = 120.0 if is_battle_state else 50.0

if current_state == GameState.UNKNOWN and elapsed_time > timeout_threshold:
if is_battle_state:
self._log(logging.WARNING, f"战斗流程中连续 {elapsed_time:.2f} 秒处于未知状态,超过200秒阈值,触发重启")
else:
self._log(logging.WARNING, f"连续 {elapsed_time:.2f} 秒处于未知状态,超过36秒阈值,触发重启")
# 检查是否超时
if elapsed_time > timeout_threshold:
state_name = self.last_state.name if self.last_state else "NONE"
self._log(logging.WARNING, f"在状态 '{state_name}' 停留超过 {elapsed_time:.2f} 秒(阈值: {timeout_threshold:.0f} 秒),触发重启")

# 使用 LoginManager 的重启登录方法
if not self.login_manager.can_restart():
Expand Down Expand Up @@ -691,9 +690,10 @@ def auto_fetch_loop(self):
# 每次循环开始时检查状态
if not self.auto_fetch_running:
break


self.updater() # 多开器如果不更新会强制停止
self.auto_fetch_data()

# 每次循环结束时检查状态
if not self.auto_fetch_running:
break
Expand All @@ -703,8 +703,9 @@ def auto_fetch_loop(self):
self._log(logging.INFO, "已达到设定时长,结束自动获取")
break
# 检测一次间隔时间——————————————————————————————————
time.sleep(0.1)
time.sleep(0.2)
except Exception as e:
logger.exception(f"自动获取数据出错:\n{e}")
self._log(logging.ERROR, f"自动获取数据出错:\n{e}")
break

Expand All @@ -726,28 +727,27 @@ def start_auto_fetch(self):
self._log(logging.INFO, f"创建文件夹: {self.data_folder}")
self.data_folder.mkdir(parents=True, exist_ok=True) # 创建文件夹
(self.data_folder / "images").mkdir(parents=True, exist_ok=True)
with open(self.data_folder / "arknights.csv", "w", newline="") as file:
# 创建CSV表头
if self.field_recognizer is not None:
# 获取场地特征列数
num_field_features = len(self.field_recognizer.get_feature_columns())

# 按照data_cleaning_with_field_recognize_gpu.py的格式创建表头
header = [f"{i+1}L" for i in range(MONSTER_COUNT)] # 1L-77L
header += [f"{i+1}LF" for i in range(MONSTER_COUNT, MONSTER_COUNT + num_field_features)] # 78LF-83LF (场地特征)
header += [f"{i+1}R" for i in range(MONSTER_COUNT)] # 1R-77R
header += [f"{i+1}RF" for i in range(MONSTER_COUNT, MONSTER_COUNT + num_field_features)] # 78RF-83RF (场地特征)

def get_expected_header():
"""根据配置生成预期表头"""
if FIELD_FEATURE_COUNT > 0:
header = [f"{i + 1}L" for i in range(MONSTER_COUNT)]
header += [f"{i + 1}LF" for i in range(MONSTER_COUNT, MONSTER_COUNT + FIELD_FEATURE_COUNT)]
header += [f"{i + 1}R" for i in range(MONSTER_COUNT)]
header += [f"{i + 1}RF" for i in range(MONSTER_COUNT, MONSTER_COUNT + FIELD_FEATURE_COUNT)]
header += ["Result", "ImgPath"]
logger.info(f"创建包含场地特征的CSV表头,场地特征数: {num_field_features}")
else:
# 仅怪物数据的格式
header = [f"{i+1}L" for i in range(MONSTER_COUNT)] # 左侧怪物数据
header += [f"{i+1}R" for i in range(MONSTER_COUNT)] # 右侧怪物数据
header = [f"{i + 1}L" for i in range(MONSTER_COUNT)]
header += [f"{i + 1}R" for i in range(MONSTER_COUNT)]
header += ["Result", "ImgPath"]
logger.info("创建仅包含怪物数据的CSV表头")

return header

# 创建CSV表头
with open(self.data_folder / "arknights.csv", "w", newline="") as file:
header = get_expected_header()
writer = csv.writer(file)
writer.writerow(header)

self.log_file_handler = logging.FileHandler(
self.data_folder / f"AutoFetch_{start_time}.log", "a", "utf-8"
)
Expand Down
2 changes: 1 addition & 1 deletion data_package.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ def create_zip_package(output_zip_path):

def package_data():
# 使用当前时间生成输出文件名
current_time = datetime.now().strftime("%Y_%m_%d__%H_%M_%S")
current_time = datetime.now().strftime("%Y%m%d_%H%M%S")
output_zip = f"arknights_package_{current_time}.zip"

# 调用函数创建压缩包
Expand Down
Binary file added images/“交通亭”量产型.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/“果腹”.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/凯尔希.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/圣徒卡门.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/富营养的穿刺者.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/弧光镜卫.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/扎罗,“狼之主”.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified images/拳手囚犯.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed images/暴走食虫花.png
Binary file not shown.
Binary file added images/染污躯壳.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/烈酒级醒酒助手.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/田鼷力士.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/神射手囚犯.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/逐腐兽.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 6 additions & 6 deletions input_panel_ui.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ def init_ui(self):
self.scroll_grid.setContentsMargins(5, 5, 5, 5)

# 设置5列布局
self.COLUMNS = 7
self.COLUMNS = 10
self.ROW_HEIGHT = 120 # 每个单元的高度

scroll.setWidget(scroll_content)
Expand Down Expand Up @@ -342,15 +342,15 @@ def load_images(self):

# 人物图片
img_label = QLabel()
img_label.setFixedSize(60, 60)
img_label.setFixedSize(50, 50)
img_label.setAlignment(Qt.AlignmentFlag.AlignCenter)

try:
pixmap = QPixmap(f"images/{MONSTER_DATA['原始名称'][i]}.png")
if not pixmap.isNull():
pixmap = pixmap.scaled(
60,
60,
50,
50,
Qt.AspectRatioMode.KeepAspectRatio,
Qt.TransformationMode.SmoothTransformation,
)
Expand All @@ -368,15 +368,15 @@ def load_images(self):

# 左输入框
left_entry = QLineEdit()
left_entry.setFixedWidth(60)
left_entry.setFixedWidth(50)
left_entry.setPlaceholderText("左")
left_entry.setAlignment(Qt.AlignmentFlag.AlignCenter)
left_entry.textChanged.connect(self.input_changed.emit) # Connect to signal
self.left_monsters[str(i)] = left_entry

# 右输入框 (放在左输入框下方)
right_entry = QLineEdit()
right_entry.setFixedWidth(60)
right_entry.setFixedWidth(50)
right_entry.setPlaceholderText("右")
right_entry.setAlignment(Qt.AlignmentFlag.AlignCenter)
right_entry.textChanged.connect(self.input_changed.emit) # Connect to signal
Expand Down
9 changes: 2 additions & 7 deletions loadData.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,13 +133,8 @@ def update_device_serial(self, serial):
self.device_serial = serial
return dev

# 自动选择第一个可用设备
if devices:
self.device_serial = devices[0]
logger.info(f"自动选择第一个可用设备: {self.device_serial}")
return self.device_serial

logger.error("未找到可连接的Android设备")
# 只使用指定的设备,不要自动选择其他设备
logger.error(f"未找到指定的设备: {serial},当前在线设备: {devices}")
self.device_serial = ""
return ""

Expand Down
83 changes: 52 additions & 31 deletions login.py
Original file line number Diff line number Diff line change
Expand Up @@ -345,16 +345,32 @@ def sleep_with_check(seconds):
return False

# 等待登录完成,最多等待70秒
self._log(logging.INFO, "等待登录完成")
self._log(logging.INFO, "等待登录完成 (最长70秒,动态检测)...")
start_time = time.time()

while time.time() - start_time < 70:
if not check_stop():
return False
# 简单的等待,不进行复杂的页面检测
if not sleep_with_check(1):

# 每隔3秒进行一次检测,避免频繁截图和识别抢占CPU(特别是多开时)
if not sleep_with_check(3):
return False

screenshot = self.connector.capture_screenshot()
if screenshot is not None:
comp_matched, _ = self.match_template(screenshot, "competition_page", threshold=0.7)
ann_matched, _ = self.match_template(screenshot, "announcement_close", threshold=0.9)
event_matched, _ = self.match_template(screenshot, "event_claim_close", threshold=0.9)

if comp_matched or ann_matched or event_matched:
elapsed = int(time.time() - start_time)
self._log(logging.INFO, f"检测到游戏界面已加载 (耗时: {elapsed}秒),提前结束等待")
if not sleep_with_check(3):
return False

break

# 寻找争锋频道页面,最多等待30秒
# 寻找争锋频道入口,最多等待30秒
self._log(logging.INFO, "寻找争锋频道入口")
start_time = time.time()

Expand All @@ -365,50 +381,55 @@ def sleep_with_check(seconds):
return True

# 识别失败时点击右上角两次
click_count = 0
while click_count < 2:
self._log(logging.INFO, "未检测到争锋频道入口,点击屏幕右上角")
self._log(logging.INFO, "未检测到争锋频道入口,点击屏幕右上角")
for _ in range(2):
self.connector.click((0.1, 0.1))
if not sleep_with_check(2):
return False
click_count += 1

# 点击右上角后,立即再次检查争锋频道入口
if not sleep_with_check(1):
return False
screenshot = self.connector.capture_screenshot()
if screenshot is not None:
if self._check_and_click_competition_page(screenshot, sleep_with_check, check_stop):
return True

# 识别失败后识别关闭按钮

# 同时检测两种关闭按钮五次(每次间隔2秒)
self._log(logging.INFO, "尝试检测并关闭公告/活动弹窗")
close_buttons = ["announcement_close", "event_claim_close"]
close_button_found = False
for button in close_buttons:
for i in range(5):
screenshot = self.connector.capture_screenshot()
if screenshot is not None:
matched, pos = self.match_template(screenshot, button, threshold=0.9)
if matched:
h, w = screenshot.shape[:2]
rel_x = pos[0] / w
rel_y = pos[1] / h
self._log(logging.INFO, f"{button}位置: ({pos[0]}, {pos[1]}), 相对坐标: ({rel_x:.2f}, {rel_y:.2f})")
self.connector.click((rel_x, rel_y))
self._log(logging.INFO, f"关闭{button}页面")
close_button_found = True
if not sleep_with_check(1):
return False
break

# 再次识别争锋频道入口
if close_button_found:
if not sleep_with_check(1):
for button in close_buttons:
matched, pos = self.match_template(screenshot, button, threshold=0.9)
if matched:
h, w = screenshot.shape[:2]
rel_x = pos[0] / w
rel_y = pos[1] / h
self._log(logging.INFO, f"{button}位置: ({pos[0]}, {pos[1]}), 相对坐标: ({rel_x:.2f}, {rel_y:.2f})")
self.connector.click((rel_x, rel_y))
self._log(logging.INFO, f"第 {i+1} 次检测,关闭 {button} 页面")
break # 发现并点击了一个按钮后,跳出内层循环,避免同一张截图重复点击

# 每次检测完等待2秒
if not sleep_with_check(2):
return False

# 关闭完之后,20秒内重复检测争锋频道入口
self._log(logging.INFO, "检测争锋频道入口")
check_start_time = time.time()
while time.time() - check_start_time < 20:
if not check_stop():
return False

screenshot = self.connector.capture_screenshot()
if screenshot is not None:
if self._check_and_click_competition_page(screenshot, sleep_with_check, check_stop):
return True


# 每次轮询间隔2秒,避免频繁截图造成性能浪费
if not sleep_with_check(2):
return False

# 还是失败的话就重启
self._log(logging.ERROR, "未找到争锋频道入口,登录流程失败")
return False
Expand Down
Loading
Loading