From eddc6171a560ae8d527bd5e714d985571a0dc51c Mon Sep 17 00:00:00 2001 From: leovefy Date: Thu, 29 Oct 2026 08:03:25 +0800 Subject: [PATCH] =?UTF-8?q?fix(GameUi):=20=E5=85=BC=E5=AE=B9=E5=95=86?= =?UTF-8?q?=E5=BA=97=E4=B8=A4=E7=A7=8D=E6=8B=9B=E7=89=8C=E5=9B=BE=E7=89=87?= =?UTF-8?q?=EF=BC=8C=E4=BF=AE=E5=A4=8D=E5=8F=8D=E5=A4=8D=E8=BF=9B=E5=87=BA?= =?UTF-8?q?=E5=95=86=E5=BA=97=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tasks/DailyTrifles/script_task.py | 2 +- tasks/GameUi/assets.py | 2 + tasks/GameUi/default_pages.py | 2 +- tasks/GameUi/page/image_main.json | 9 ++ tasks/GameUi/page/page_check_mall_purple.png | Bin 0 -> 13693 bytes tasks/RichMan/mall/navbar.py | 4 +- tests/test_mall_appearance.py | 150 +++++++++++++++++++ 7 files changed, 165 insertions(+), 4 deletions(-) create mode 100644 tasks/GameUi/page/page_check_mall_purple.png create mode 100644 tests/test_mall_appearance.py diff --git a/tasks/DailyTrifles/script_task.py b/tasks/DailyTrifles/script_task.py index e2994c027f..bdea4e2fb9 100644 --- a/tasks/DailyTrifles/script_task.py +++ b/tasks/DailyTrifles/script_task.py @@ -216,7 +216,7 @@ def run_store(self): if self.config.daily_trifles.trifles_config.buy_sushi_count > 0: self.run_buy_sushi() - self.ui_click(self.I_UI_BACK_YELLOW, self.I_CHECK_MALL, interval=2.4, timeout=8) + self.goto_page(page_mall, skip_first_screenshot=False, timeout=8) self.goto_page(page_main) def run_store_sign(self): diff --git a/tasks/GameUi/assets.py b/tasks/GameUi/assets.py index c5211c12f3..44138964ae 100644 --- a/tasks/GameUi/assets.py +++ b/tasks/GameUi/assets.py @@ -145,6 +145,8 @@ class GameUiAssets: I_CHECK_DAILY = RuleImage(roi_front=(28,515,58,62), roi_back=(1,487,154,145), threshold=0.8, method="Template matching", file="./tasks/GameUi/page/page_check_daily.png") # 商店页面标志 I_CHECK_MALL = RuleImage(roi_front=(231,455,131,78), roi_back=(201,432,185,121), threshold=0.8, method="Template matching", file="./tasks/GameUi/page/page_check_mall.png") + # 商店页面标志(紫色招牌) + I_CHECK_MALL_PURPLE = RuleImage(roi_front=(231,455,131,78), roi_back=(201,432,185,121), threshold=0.8, method="Template matching", file="./tasks/GameUi/page/page_check_mall_purple.png") # 商店推荐页面标志 I_CHECK_MALL_RECOMMEND = RuleImage(roi_front=(930,12,42,37), roi_back=(905,0,100,100), threshold=0.8, method="Template matching", file="./tasks/GameUi/page/page_check_mall_recommend.png") # 阴阳寮页面标志 diff --git a/tasks/GameUi/default_pages.py b/tasks/GameUi/default_pages.py index 2860d86581..b812840cec 100644 --- a/tasks/GameUi/default_pages.py +++ b/tasks/GameUi/default_pages.py @@ -95,7 +95,7 @@ def handle_login_page(task) -> bool: page_daily.connect(page_main, GlobalGameAssets.I_UI_BACK_YELLOW, key="page_daily->page_main") page_main.connect(page_daily, GameUiAssets.I_MAIN_GOTO_DAILY, key="page_main->page_daily") -page_mall = Page(GameUiAssets.I_CHECK_MALL, category="global") +page_mall = Page(any_of(GameUiAssets.I_CHECK_MALL, GameUiAssets.I_CHECK_MALL_PURPLE), category="global") page_mall.add_enter_failure_hooks(conditional_action(condition=GameUiAssets.I_CHECK_MAIN, action=RestartAssets.C_LOGIN_SCROLL_CLOSE_AREA)) page_mall.add_enter_success_hooks(GameUiAssets.I_AD_CLOSE_RED, GlobalGameAssets.I_UI_BACK_RED, GlobalGameAssets.I_UI_CANCEL_SAMLL) diff --git a/tasks/GameUi/page/image_main.json b/tasks/GameUi/page/image_main.json index ece4396bb8..935d51f9fa 100644 --- a/tasks/GameUi/page/image_main.json +++ b/tasks/GameUi/page/image_main.json @@ -170,6 +170,15 @@ "threshold": 0.8, "description": "商店页面标志" }, + { + "itemName": "check_mall_purple", + "imageName": "page_check_mall_purple.png", + "roiFront": "231,455,131,78", + "roiBack": "201,432,185,121", + "method": "Template matching", + "threshold": 0.8, + "description": "商店页面标志(紫色招牌)" + }, { "itemName": "check_mall_recommend", "imageName": "page_check_mall_recommend.png", diff --git a/tasks/GameUi/page/page_check_mall_purple.png b/tasks/GameUi/page/page_check_mall_purple.png new file mode 100644 index 0000000000000000000000000000000000000000..f6766029c21fb4f0101b29bdace09ce4b3ed6c97 GIT binary patch literal 13693 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 buY~?zkKat6`?Q&I00000NkvXXu0mjf`J!UO literal 0 HcmV?d00001 diff --git a/tasks/RichMan/mall/navbar.py b/tasks/RichMan/mall/navbar.py index 713c9f69e4..aa725e54bc 100644 --- a/tasks/RichMan/mall/navbar.py +++ b/tasks/RichMan/mall/navbar.py @@ -6,7 +6,7 @@ from module.logger import logger -from tasks.GameUi.page import page_main, page_guild +from tasks.GameUi.page import page_main, page_guild, page_mall from tasks.GameUi.game_ui import GameUi from tasks.Component.Buy.buy import Buy from tasks.RichMan.assets import RichManAssets @@ -89,7 +89,7 @@ def back_mall(self): 返回商城 :return: """ - self.ui_click(self.I_UI_BACK_YELLOW, self.I_CHECK_MALL, interval=3, timeout=6) + self.goto_page(page_mall, skip_first_screenshot=False, timeout=6) def mall_resource(self, index: int) -> int: diff --git a/tests/test_mall_appearance.py b/tests/test_mall_appearance.py new file mode 100644 index 0000000000..f91bc90e0a --- /dev/null +++ b/tests/test_mall_appearance.py @@ -0,0 +1,150 @@ +"""Check both mall appearances and return paths without a device or OCR service.""" + +import unittest +from types import SimpleNamespace +from unittest.mock import patch + +import numpy as np + +from module.exception import GamePageUnknownError +from tasks.DailyTrifles.assets import DailyTriflesAssets +from tasks.DailyTrifles.page import page_store_gift_room +from tasks.DailyTrifles.script_task import ScriptTask +from tasks.GameUi.assets import GameUiAssets +from tasks.GameUi.game_ui import GameUi +from tasks.GameUi.page import page_main, page_mall, page_mall_recommend +from tasks.GameUi.session import NavigatorSession +from tasks.GlobalGame.assets import GlobalGameAssets +from tasks.RichMan.mall.navbar import MallNavbar + + +def frame_with(*rules): + """Build a synthetic frame using the unchanged asset positions.""" + frame = np.zeros((720, 1280, 3), dtype=np.uint8) + for rule in rules: + template = rule.image + x, y = rule.roi_front[:2] + height, width = template.shape[:2] + frame[y:y + height, x:x + width] = template + return frame + + +class OfflineMallUi(GameUi): + def __init__(self, mall_rule, state="mall"): + # Skip real Config/Device setup; keep the production matcher and navigator. + back = GlobalGameAssets.I_UI_BACK_YELLOW + self.frames = { + "mall": frame_with(mall_rule, back), + "main": frame_with(GameUiAssets.I_CHECK_MAIN, GameUiAssets.I_MAIN_GOTO_MALL), + "recommend": frame_with(GameUiAssets.I_CHECK_MALL_RECOMMEND, back), + "gift": frame_with(DailyTriflesAssets.I_GIFT_RECOMMEND, back), + "room": frame_with(back), + "blank": frame_with(), + } + self.state = state + self.after_sign = "gift" + self.clicks = [] + self.screenshot_count = 0 + self.interval_timer = {} + self.config = SimpleNamespace( + daily_trifles=SimpleNamespace( + trifles_config=SimpleNamespace(store_sign=True, buy_sushi_count=-1), + ), + script=SimpleNamespace(device=SimpleNamespace(control_method="minitouch")), + ) + self.device = SimpleNamespace( + image=self.frames[state], + app_lost_login=lambda: False, + app_is_running=lambda: True, + get_orientation=lambda: None, + ) + self.navigator = NavigatorSession(task_category="daily_trifles") + self.navigator.bootstrap([page_main, page_mall, page_mall_recommend, page_store_gift_room]) + + def screenshot(self): + self.screenshot_count += 1 + if self.screenshot_count > 100: + raise AssertionError("Mall navigation kept retrying") + self.device.image = self.frames[self.state] + return self.device.image + + def appear_then_click(self, target, **kwargs): + if not self.appear(target): + return False + self.clicks.append(target) + if target is self.I_UI_BACK_YELLOW: + self.state = "main" if self.state == "mall" else "mall" + elif target is self.I_MAIN_GOTO_MALL: + self.state = "recommend" + else: + raise AssertionError(f"Unexpected click: {target}") + return True + + def run_store_sign(self): + # Leave the cached mall screenshot stale to check that return takes a new one. + self.state = self.after_sign + + +class MallAppearanceTests(unittest.TestCase): + variants = (GameUiAssets.I_CHECK_MALL, GameUiAssets.I_CHECK_MALL_PURPLE) + + def setUp(self): + for target in ("tasks.GameUi.navigator.Timer.wait", "tasks.GameUi.navigator.time.sleep"): + patcher = patch(target) + patcher.start() + self.addCleanup(patcher.stop) + + def test_both_appearances_are_recognized_but_non_mall_is_not(self): + for rule in self.variants: + with self.subTest(rule=rule.name): + task = OfflineMallUi(rule) + self.assertTrue(task.confirm_page(page_mall)) + task.state = "main" + self.assertFalse(task.confirm_page(page_mall, skip_first_screenshot=False)) + + def test_entering_from_main_stops_at_either_mall_appearance(self): + for rule in self.variants: + with self.subTest(rule=rule.name): + task = OfflineMallUi(rule, state="main") + self.assertTrue(task.goto_page(page_mall)) + self.assertEqual(task.state, "mall") + self.assertEqual(task.clicks, [task.I_MAIN_GOTO_MALL, task.I_UI_BACK_YELLOW]) + + def test_return_does_not_click_back_when_already_in_mall(self): + for rule in self.variants: + with self.subTest(rule=rule.name): + task = OfflineMallUi(rule) + MallNavbar.back_mall(task) + self.assertEqual(task.state, "mall") + self.assertEqual(task.clicks, []) + + def test_daily_trifles_returns_from_gift_room_then_exits_to_main(self): + for rule in self.variants: + with self.subTest(rule=rule.name): + task = OfflineMallUi(rule) + ScriptTask.run_store(task) + self.assertEqual(task.state, "main") + self.assertEqual(task.clicks, [task.I_UI_BACK_YELLOW] * 2) + + def test_rich_man_returns_from_an_unregistered_shop_room(self): + for rule in self.variants: + with self.subTest(rule=rule.name): + task = OfflineMallUi(rule, state="room") + MallNavbar.back_mall(task) + self.assertEqual(task.state, "mall") + self.assertEqual(task.clicks, [task.I_UI_BACK_YELLOW]) + + def test_unrecognized_return_page_raises_instead_of_finishing(self): + for caller in (ScriptTask.run_store, MallNavbar.back_mall): + with self.subTest(caller=caller.__qualname__): + task = OfflineMallUi(self.variants[1], state="mall" if caller is ScriptTask.run_store else "blank") + task.after_sign = "blank" + with patch("tasks.GameUi.navigator.Timer") as timer: + timer.return_value.start.return_value.reached.return_value = True + with self.assertRaises(GamePageUnknownError): + caller(task) + self.assertEqual(task.clicks, []) + + +if __name__ == "__main__": + unittest.main()