From d07157eadfc0ee8af592140adb5a8643076fc984 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9C=9E=E9=A3=9B?= Date: Wed, 14 May 2025 02:53:55 +0800 Subject: [PATCH 1/5] fix: handle error when can not parse counter --- module/os_shop/item.py | 27 +++++++++++++++++++++++++-- module/os_shop/selector.py | 7 +++++-- module/os_shop/shop.py | 3 +++ 3 files changed, 33 insertions(+), 4 deletions(-) diff --git a/module/os_shop/item.py b/module/os_shop/item.py index 468deebfb..5001d4ad4 100644 --- a/module/os_shop/item.py +++ b/module/os_shop/item.py @@ -43,9 +43,32 @@ class CounterOcr(Ocr): """ result_list = super().ocr(image, direct_ocr=direct_ocr) if isinstance(result_list, list): - return [[int(j)for j in i.split('/')]for i in result_list] + parsed = [] + for i in result_list: + if not i or '/' not in i: + logger.warning(f'Invalid OCR result format: {i}') + parsed.append([0, 0]) + continue + + parts = i.split('/') + if len(parts) != 2: + logger.warning(f'Invalid counter format: {i}') + parsed.append([0, 0]) + continue + parsed.append([int(j) for j in parts]) + + return parsed else: - return [int(i) for i in result_list.split('/')] + if not result_list or '/' not in result_list: + logger.warning(f'Invalid OCR result: {result_list}') + return [0, 0] + + parts = result_list.split('/') + if len(parts) != 2: + logger.warning(f'Invalid counter format: {result_list}') + return [0, 0] + + return [int(i) for i in parts] COUNTER_OCR = CounterOcr([], threshold=96, name='Counter_ocr') diff --git a/module/os_shop/selector.py b/module/os_shop/selector.py index 524673777..6f4a56a3c 100644 --- a/module/os_shop/selector.py +++ b/module/os_shop/selector.py @@ -74,6 +74,9 @@ class Selector(): """ return not (self.is_cl1_enabled and item.name == 'PurpleCoins') + def check_item_count(self, item) -> bool: + return item.count >= 1 and item.totoal_count >= 1 and item.count <= item.totoal_count + def items_filter_in_akashi_shop(self, items) -> List[Item]: """ Returns items that can be bought. @@ -89,7 +92,7 @@ class Selector(): if not parser.strip(): parser = GeneratedConfig.OpsiGeneral_AkashiShopFilter FILTER.load(parser) - return FILTER.applys(items, funcs=[self.check_cl1_purple_coins, self.enough_coins_in_akashi]) + return FILTER.applys(items, funcs=[self.check_cl1_purple_coins, self.enough_coins_in_akashi, self.check_item_count]) def items_filter_in_os_shop(self, items) -> List[Item]: """ @@ -111,4 +114,4 @@ class Selector(): else: parser = OS_SHOP[preset] FILTER.load(parser) - return FILTER.apply(items, func=self.check_cl1_purple_coins) + return FILTER.applys(items, func=[self.check_cl1_purple_coins, self.check_item_count]) diff --git a/module/os_shop/shop.py b/module/os_shop/shop.py index 1fe48b9c5..99b4d8e6e 100644 --- a/module/os_shop/shop.py +++ b/module/os_shop/shop.py @@ -198,6 +198,9 @@ class OSShop(PortShop, AkashiShop): if _item is None: logger.warning(f'Item {item.name} not found in shop {item.shop_index + 1} at pos {item.scroll_pos:.2f}, skip.') continue + if not self.check_item_count(_item): + logger.warning(f'Get {_item.name} count error, skip.') + continue if self.os_shop_buy_execute(_item): logger.info(f'Bought item: {_item.name}.') skip_get_coins = False From 7ee0460e68962c44d933dc78d810bc96faca2586 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9C=9E=E9=A3=9B?= Date: Wed, 14 May 2025 02:54:59 +0800 Subject: [PATCH 2/5] fix: handle when shop amount is 0 --- module/os_shop/item.py | 4 +-- module/os_shop/shop.py | 58 +++++++++++++++++++++++++----------------- 2 files changed, 36 insertions(+), 26 deletions(-) diff --git a/module/os_shop/item.py b/module/os_shop/item.py index 5001d4ad4..771f1b2e2 100644 --- a/module/os_shop/item.py +++ b/module/os_shop/item.py @@ -83,8 +83,8 @@ class OSShopItem(Item): super().__init__(*args, **kwargs) self._shop_index = None self._scroll_pos = None - self.total_count = 1 - self.count = 1 + self.total_count = -1 + self.count = -1 @property def shop_index(self): diff --git a/module/os_shop/shop.py b/module/os_shop/shop.py index 99b4d8e6e..c2eb14d50 100644 --- a/module/os_shop/shop.py +++ b/module/os_shop/shop.py @@ -8,7 +8,7 @@ from module.os_shop.akashi_shop import AkashiShop from module.os_shop.assets import PORT_SUPPLY_CHECK, SHOP_BUY_CONFIRM from module.os_shop.port_shop import PortShop from module.os_shop.ui import OS_SHOP_SCROLL -from module.shop.assets import AMOUNT_MAX, AMOUNT_MINUS, AMOUNT_PLUS, SHOP_BUY_CONFIRM_AMOUNT, SHOP_BUY_CONFIRM as OS_SHOP_BUY_CONFIRM +from module.shop.assets import AMOUNT_MAX, AMOUNT_MINUS, AMOUNT_PLUS, SHOP_BUY_CONFIRM_AMOUNT, SHOP_BUY_CONFIRM as OS_SHOP_BUY_CONFIRM, SHOP_CLICK_SAFE_AREA from module.shop.clerk import OCR_SHOP_AMOUNT @@ -26,7 +26,8 @@ class OSShop(PortShop, AkashiShop): amount_finish = False self.interval_clear([ PORT_SUPPLY_CHECK, SHOP_BUY_CONFIRM_AMOUNT, - SHOP_BUY_CONFIRM, OS_SHOP_BUY_CONFIRM, GET_ITEMS_1 + SHOP_BUY_CONFIRM, OS_SHOP_BUY_CONFIRM, GET_ITEMS_1, + SHOP_CLICK_SAFE_AREA ]) while True: @@ -41,16 +42,16 @@ class OSShop(PortShop, AkashiShop): continue if self.appear_then_click(SHOP_BUY_CONFIRM, offset=(20, 20), interval=3): - self.interval_reset(SHOP_BUY_CONFIRM) continue if self.appear_then_click(OS_SHOP_BUY_CONFIRM, offset=(20, 20), interval=3): - self.interval_reset(OS_SHOP_BUY_CONFIRM) continue if not amount_finish and self.appear(SHOP_BUY_CONFIRM_AMOUNT, offset=(20, 20)): - self.shop_buy_amount_handler(button) - amount_finish = True + amount_finish = self.shop_buy_amount_handler(button) + if amount_finish: + self.interval_reset(SHOP_BUY_CONFIRM) + self.interval_reset(OS_SHOP_BUY_CONFIRM) continue if amount_finish and self.appear_then_click(SHOP_BUY_CONFIRM_AMOUNT, offset=(20, 20), interval=3): @@ -102,32 +103,40 @@ class OSShop(PortShop, AkashiShop): Raises: ScriptError: OCR_SHOP_AMOUNT """ + limit = -1 + retry = Timer(0, count=3) + retry.start() + while True: + if skip_first_screenshot: + skip_first_screenshot = False + else: + self.device.screenshot() + limit = OCR_SHOP_AMOUNT.ocr(self.device.image) + + if limit == 0: + logger.warning('OCR_SHOP_AMOUNT resulted 0, retrying') + self.device.click(SHOP_CLICK_SAFE_AREA) + return False + + if limit > 0: + break + + if retry.reached(): + logger.critical('OCR_SHOP_AMOUNT resulted error; ' + 'asset may be compromised') + raise ScriptError + retry.reset() + + currency = self.get_currency_coins(item) count = min(int(currency // item.price), item.count) if count == 1: - return + return True coins = self.get_coins_no_limit(item) total_count = min(int(coins // item.price), item.count) - limit = 0 - retry = Timer(0, count=3) - retry.start() - while True: - limit = OCR_SHOP_AMOUNT.ocr(self.device.image) - if limit: - break - - if retry.reached(): - logger.critical('OCR_SHOP_AMOUNT resulted in zero (0); ' - 'asset may be compromised') - raise ScriptError - - self.device.sleep((0.3, 0.5)) - self.device.screenshot() - - retry.reset() set_to_max = False # Avg count of all items(no PurpleCoins) is 8.9, so use 10. if count <= 10: @@ -158,6 +167,7 @@ class OSShop(PortShop, AkashiShop): self.ui_ensure_index(limit, letter=OCR_SHOP_AMOUNT, prev_button=AMOUNT_MINUS, next_button=AMOUNT_PLUS, skip_first_screenshot=True) + return True def handle_port_supply_buy(self) -> bool: """ From 95d732ab857598a9f6a5d8d06e84b4646b531095 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9C=9E=E9=A3=9B?= Date: Thu, 15 May 2025 13:13:06 +0800 Subject: [PATCH 3/5] fix: argument typo --- module/os_shop/selector.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/os_shop/selector.py b/module/os_shop/selector.py index 6f4a56a3c..ade628a16 100644 --- a/module/os_shop/selector.py +++ b/module/os_shop/selector.py @@ -114,4 +114,4 @@ class Selector(): else: parser = OS_SHOP[preset] FILTER.load(parser) - return FILTER.applys(items, func=[self.check_cl1_purple_coins, self.check_item_count]) + return FILTER.applys(items, funcs=[self.check_cl1_purple_coins, self.check_item_count]) From 99a577dfcb524d1a3c661268c2721dbd7f57a40d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9C=9E=E9=A3=9B?= Date: Thu, 15 May 2025 14:05:33 +0800 Subject: [PATCH 4/5] fix: item fields typo --- module/os_shop/selector.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/os_shop/selector.py b/module/os_shop/selector.py index ade628a16..1b1cb8581 100644 --- a/module/os_shop/selector.py +++ b/module/os_shop/selector.py @@ -75,7 +75,7 @@ class Selector(): return not (self.is_cl1_enabled and item.name == 'PurpleCoins') def check_item_count(self, item) -> bool: - return item.count >= 1 and item.totoal_count >= 1 and item.count <= item.totoal_count + return item.count >= 1 and item.total_count >= 1 and item.count <= item.total_count def items_filter_in_akashi_shop(self, items) -> List[Item]: """ From 12342c8a3d9d63f937cc47db6a35c01b1ad9fb09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9C=9E=E9=A3=9B?= Date: Thu, 15 May 2025 14:06:20 +0800 Subject: [PATCH 5/5] doc: add function doc --- module/os_shop/selector.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/module/os_shop/selector.py b/module/os_shop/selector.py index 1b1cb8581..3da497b6a 100644 --- a/module/os_shop/selector.py +++ b/module/os_shop/selector.py @@ -75,6 +75,16 @@ class Selector(): return not (self.is_cl1_enabled and item.name == 'PurpleCoins') def check_item_count(self, item) -> bool: + """ + Check if the item has a valid count. + + Args: + item: Irem. + + Returns: + bool: True if the item has at least one count, the total count is at least one, + and the current count does not exceed the total count. False otherwise. + """ return item.count >= 1 and item.total_count >= 1 and item.count <= item.total_count def items_filter_in_akashi_shop(self, items) -> List[Item]: