1
0
mirror of https://github.com/sui-feng-cb/AzurLaneAutoScript1.git synced 2026-07-31 07:40:52 +08:00

Refractor: island transport preparation

This commit is contained in:
2025-10-15 03:45:59 +08:00
parent 91ed9f7b52
commit a0261d62ac
5 changed files with 442 additions and 693 deletions

View File

@@ -16,6 +16,8 @@ ISLAND_TRANSPORT = Button(area={'cn': (905, 335, 986, 358), 'en': (905, 335, 986
ISLAND_TRANSPORT_CHECK = Button(area={'cn': (264, 154, 317, 180), 'en': (264, 154, 317, 180), 'jp': (264, 154, 317, 180), 'tw': (264, 154, 317, 180)}, color={'cn': (142, 143, 143), 'en': (142, 143, 143), 'jp': (142, 143, 143), 'tw': (142, 143, 143)}, button={'cn': (264, 154, 317, 180), 'en': (264, 154, 317, 180), 'jp': (264, 154, 317, 180), 'tw': (264, 154, 317, 180)}, file={'cn': './assets/cn/island/ISLAND_TRANSPORT_CHECK.png', 'en': './assets/cn/island/ISLAND_TRANSPORT_CHECK.png', 'jp': './assets/cn/island/ISLAND_TRANSPORT_CHECK.png', 'tw': './assets/cn/island/ISLAND_TRANSPORT_CHECK.png'}) ISLAND_TRANSPORT_CHECK = Button(area={'cn': (264, 154, 317, 180), 'en': (264, 154, 317, 180), 'jp': (264, 154, 317, 180), 'tw': (264, 154, 317, 180)}, color={'cn': (142, 143, 143), 'en': (142, 143, 143), 'jp': (142, 143, 143), 'tw': (142, 143, 143)}, button={'cn': (264, 154, 317, 180), 'en': (264, 154, 317, 180), 'jp': (264, 154, 317, 180), 'tw': (264, 154, 317, 180)}, file={'cn': './assets/cn/island/ISLAND_TRANSPORT_CHECK.png', 'en': './assets/cn/island/ISLAND_TRANSPORT_CHECK.png', 'jp': './assets/cn/island/ISLAND_TRANSPORT_CHECK.png', 'tw': './assets/cn/island/ISLAND_TRANSPORT_CHECK.png'})
OCR_PRODUCTION_TIME = Button(area={'cn': (714, 611, 808, 631), 'en': (714, 611, 808, 631), 'jp': (714, 611, 808, 631), 'tw': (714, 611, 808, 631)}, color={'cn': (120, 210, 255), 'en': (120, 210, 255), 'jp': (120, 210, 255), 'tw': (120, 210, 255)}, button={'cn': (714, 611, 808, 631), 'en': (714, 611, 808, 631), 'jp': (714, 611, 808, 631), 'tw': (714, 611, 808, 631)}, file={'cn': './assets/cn/island/OCR_PRODUCTION_TIME.png', 'en': './assets/cn/island/OCR_PRODUCTION_TIME.png', 'jp': './assets/cn/island/OCR_PRODUCTION_TIME.png', 'tw': './assets/cn/island/OCR_PRODUCTION_TIME.png'}) OCR_PRODUCTION_TIME = Button(area={'cn': (714, 611, 808, 631), 'en': (714, 611, 808, 631), 'jp': (714, 611, 808, 631), 'tw': (714, 611, 808, 631)}, color={'cn': (120, 210, 255), 'en': (120, 210, 255), 'jp': (120, 210, 255), 'tw': (120, 210, 255)}, button={'cn': (714, 611, 808, 631), 'en': (714, 611, 808, 631), 'jp': (714, 611, 808, 631), 'tw': (714, 611, 808, 631)}, file={'cn': './assets/cn/island/OCR_PRODUCTION_TIME.png', 'en': './assets/cn/island/OCR_PRODUCTION_TIME.png', 'jp': './assets/cn/island/OCR_PRODUCTION_TIME.png', 'tw': './assets/cn/island/OCR_PRODUCTION_TIME.png'})
OCR_PRODUCTION_TIME_REMAIN = Button(area={'cn': (621, 427, 666, 439), 'en': (621, 427, 666, 439), 'jp': (621, 427, 666, 439), 'tw': (621, 427, 666, 439)}, color={'cn': (196, 203, 205), 'en': (196, 203, 205), 'jp': (196, 203, 205), 'tw': (196, 203, 205)}, button={'cn': (621, 427, 666, 439), 'en': (621, 427, 666, 439), 'jp': (621, 427, 666, 439), 'tw': (621, 427, 666, 439)}, file={'cn': './assets/cn/island/OCR_PRODUCTION_TIME_REMAIN.png', 'en': './assets/cn/island/OCR_PRODUCTION_TIME_REMAIN.png', 'jp': './assets/cn/island/OCR_PRODUCTION_TIME_REMAIN.png', 'tw': './assets/cn/island/OCR_PRODUCTION_TIME_REMAIN.png'}) OCR_PRODUCTION_TIME_REMAIN = Button(area={'cn': (621, 427, 666, 439), 'en': (621, 427, 666, 439), 'jp': (621, 427, 666, 439), 'tw': (621, 427, 666, 439)}, color={'cn': (196, 203, 205), 'en': (196, 203, 205), 'jp': (196, 203, 205), 'tw': (196, 203, 205)}, button={'cn': (621, 427, 666, 439), 'en': (621, 427, 666, 439), 'jp': (621, 427, 666, 439), 'tw': (621, 427, 666, 439)}, file={'cn': './assets/cn/island/OCR_PRODUCTION_TIME_REMAIN.png', 'en': './assets/cn/island/OCR_PRODUCTION_TIME_REMAIN.png', 'jp': './assets/cn/island/OCR_PRODUCTION_TIME_REMAIN.png', 'tw': './assets/cn/island/OCR_PRODUCTION_TIME_REMAIN.png'})
OCR_TRANSPORT_TIME = Button(area={'cn': (611, 139, 687, 154), 'en': (611, 139, 687, 154), 'jp': (611, 139, 687, 154), 'tw': (611, 139, 687, 154)}, color={'cn': (119, 119, 120), 'en': (119, 119, 120), 'jp': (119, 119, 120), 'tw': (119, 119, 120)}, button={'cn': (611, 139, 687, 154), 'en': (611, 139, 687, 154), 'jp': (611, 139, 687, 154), 'tw': (611, 139, 687, 154)}, file={'cn': './assets/cn/island/OCR_TRANSPORT_TIME.png', 'en': './assets/cn/island/OCR_TRANSPORT_TIME.png', 'jp': './assets/cn/island/OCR_TRANSPORT_TIME.png', 'tw': './assets/cn/island/OCR_TRANSPORT_TIME.png'})
OCR_TRANSPORT_TIME_REMAIN = Button(area={'cn': (753, 210, 842, 230), 'en': (753, 210, 842, 230), 'jp': (753, 210, 842, 230), 'tw': (753, 210, 842, 230)}, color={'cn': (252, 203, 127), 'en': (252, 203, 127), 'jp': (252, 203, 127), 'tw': (252, 203, 127)}, button={'cn': (753, 210, 842, 230), 'en': (753, 210, 842, 230), 'jp': (753, 210, 842, 230), 'tw': (753, 210, 842, 230)}, file={'cn': './assets/cn/island/OCR_TRANSPORT_TIME_REMAIN.png', 'en': './assets/cn/island/OCR_TRANSPORT_TIME_REMAIN.png', 'jp': './assets/cn/island/OCR_TRANSPORT_TIME_REMAIN.png', 'tw': './assets/cn/island/OCR_TRANSPORT_TIME_REMAIN.png'})
PROJECT_COMPLETE = Button(area={'cn': (576, 394, 704, 414), 'en': (576, 394, 704, 414), 'jp': (576, 394, 704, 414), 'tw': (576, 394, 704, 414)}, color={'cn': (210, 210, 209), 'en': (210, 210, 209), 'jp': (210, 210, 209), 'tw': (210, 210, 209)}, button={'cn': (580, 533, 762, 584), 'en': (580, 533, 762, 584), 'jp': (580, 533, 762, 584), 'tw': (580, 533, 762, 584)}, file={'cn': './assets/cn/island/PROJECT_COMPLETE.png', 'en': './assets/cn/island/PROJECT_COMPLETE.png', 'jp': './assets/cn/island/PROJECT_COMPLETE.png', 'tw': './assets/cn/island/PROJECT_COMPLETE.png'}) PROJECT_COMPLETE = Button(area={'cn': (576, 394, 704, 414), 'en': (576, 394, 704, 414), 'jp': (576, 394, 704, 414), 'tw': (576, 394, 704, 414)}, color={'cn': (210, 210, 209), 'en': (210, 210, 209), 'jp': (210, 210, 209), 'tw': (210, 210, 209)}, button={'cn': (580, 533, 762, 584), 'en': (580, 533, 762, 584), 'jp': (580, 533, 762, 584), 'tw': (580, 533, 762, 584)}, file={'cn': './assets/cn/island/PROJECT_COMPLETE.png', 'en': './assets/cn/island/PROJECT_COMPLETE.png', 'jp': './assets/cn/island/PROJECT_COMPLETE.png', 'tw': './assets/cn/island/PROJECT_COMPLETE.png'})
PROJECT_START = Button(area={'cn': (686, 610, 706, 630), 'en': (686, 610, 706, 630), 'jp': (686, 610, 706, 630), 'tw': (686, 610, 706, 630)}, color={'cn': (129, 213, 255), 'en': (129, 213, 255), 'jp': (129, 213, 255), 'tw': (129, 213, 255)}, button={'cn': (494, 599, 1087, 642), 'en': (494, 599, 1087, 642), 'jp': (494, 599, 1087, 642), 'tw': (494, 599, 1087, 642)}, file={'cn': './assets/cn/island/PROJECT_START.png', 'en': './assets/cn/island/PROJECT_START.png', 'jp': './assets/cn/island/PROJECT_START.png', 'tw': './assets/cn/island/PROJECT_START.png'}) PROJECT_START = Button(area={'cn': (686, 610, 706, 630), 'en': (686, 610, 706, 630), 'jp': (686, 610, 706, 630), 'tw': (686, 610, 706, 630)}, color={'cn': (129, 213, 255), 'en': (129, 213, 255), 'jp': (129, 213, 255), 'tw': (129, 213, 255)}, button={'cn': (494, 599, 1087, 642), 'en': (494, 599, 1087, 642), 'jp': (494, 599, 1087, 642), 'tw': (494, 599, 1087, 642)}, file={'cn': './assets/cn/island/PROJECT_START.png', 'en': './assets/cn/island/PROJECT_START.png', 'jp': './assets/cn/island/PROJECT_START.png', 'tw': './assets/cn/island/PROJECT_START.png'})
ROLE_SELECT_CHECK = Button(area={'cn': (1162, 182, 1214, 205), 'en': (1162, 182, 1214, 205), 'jp': (1162, 182, 1214, 205), 'tw': (1162, 182, 1214, 205)}, color={'cn': (221, 192, 128), 'en': (221, 192, 128), 'jp': (221, 192, 128), 'tw': (221, 192, 128)}, button={'cn': (1162, 182, 1214, 205), 'en': (1162, 182, 1214, 205), 'jp': (1162, 182, 1214, 205), 'tw': (1162, 182, 1214, 205)}, file={'cn': './assets/cn/island/ROLE_SELECT_CHECK.png', 'en': './assets/cn/island/ROLE_SELECT_CHECK.png', 'jp': './assets/cn/island/ROLE_SELECT_CHECK.png', 'tw': './assets/cn/island/ROLE_SELECT_CHECK.png'}) ROLE_SELECT_CHECK = Button(area={'cn': (1162, 182, 1214, 205), 'en': (1162, 182, 1214, 205), 'jp': (1162, 182, 1214, 205), 'tw': (1162, 182, 1214, 205)}, color={'cn': (221, 192, 128), 'en': (221, 192, 128), 'jp': (221, 192, 128), 'tw': (221, 192, 128)}, button={'cn': (1162, 182, 1214, 205), 'en': (1162, 182, 1214, 205), 'jp': (1162, 182, 1214, 205), 'tw': (1162, 182, 1214, 205)}, file={'cn': './assets/cn/island/ROLE_SELECT_CHECK.png', 'en': './assets/cn/island/ROLE_SELECT_CHECK.png', 'jp': './assets/cn/island/ROLE_SELECT_CHECK.png', 'tw': './assets/cn/island/ROLE_SELECT_CHECK.png'})
@@ -25,3 +27,8 @@ TEMPLATE_ISLAND_MANJUU = Template(file={'cn': './assets/cn/island/TEMPLATE_ISLAN
TEMPLATE_ISLAND_SWITCH = Template(file={'cn': './assets/cn/island/TEMPLATE_ISLAND_SWITCH.png', 'en': './assets/cn/island/TEMPLATE_ISLAND_SWITCH.png', 'jp': './assets/cn/island/TEMPLATE_ISLAND_SWITCH.png', 'tw': './assets/cn/island/TEMPLATE_ISLAND_SWITCH.png'}) TEMPLATE_ISLAND_SWITCH = Template(file={'cn': './assets/cn/island/TEMPLATE_ISLAND_SWITCH.png', 'en': './assets/cn/island/TEMPLATE_ISLAND_SWITCH.png', 'jp': './assets/cn/island/TEMPLATE_ISLAND_SWITCH.png', 'tw': './assets/cn/island/TEMPLATE_ISLAND_SWITCH.png'})
TEMPLATE_PROJECT_LOCKED = Template(file={'cn': './assets/cn/island/TEMPLATE_PROJECT_LOCKED.png', 'en': './assets/cn/island/TEMPLATE_PROJECT_LOCKED.png', 'jp': './assets/cn/island/TEMPLATE_PROJECT_LOCKED.png', 'tw': './assets/cn/island/TEMPLATE_PROJECT_LOCKED.png'}) TEMPLATE_PROJECT_LOCKED = Template(file={'cn': './assets/cn/island/TEMPLATE_PROJECT_LOCKED.png', 'en': './assets/cn/island/TEMPLATE_PROJECT_LOCKED.png', 'jp': './assets/cn/island/TEMPLATE_PROJECT_LOCKED.png', 'tw': './assets/cn/island/TEMPLATE_PROJECT_LOCKED.png'})
TEMPLATE_SLOT_LOCKED = Template(file={'cn': './assets/cn/island/TEMPLATE_SLOT_LOCKED.png', 'en': './assets/cn/island/TEMPLATE_SLOT_LOCKED.png', 'jp': './assets/cn/island/TEMPLATE_SLOT_LOCKED.png', 'tw': './assets/cn/island/TEMPLATE_SLOT_LOCKED.png'}) TEMPLATE_SLOT_LOCKED = Template(file={'cn': './assets/cn/island/TEMPLATE_SLOT_LOCKED.png', 'en': './assets/cn/island/TEMPLATE_SLOT_LOCKED.png', 'jp': './assets/cn/island/TEMPLATE_SLOT_LOCKED.png', 'tw': './assets/cn/island/TEMPLATE_SLOT_LOCKED.png'})
TRANSPORT_LOCKED = Button(area={'cn': (659, 380, 683, 412), 'en': (659, 380, 683, 412), 'jp': (659, 380, 683, 412), 'tw': (659, 380, 683, 412)}, color={'cn': (192, 192, 190), 'en': (192, 192, 190), 'jp': (192, 192, 190), 'tw': (192, 192, 190)}, button={'cn': (659, 380, 683, 412), 'en': (659, 380, 683, 412), 'jp': (659, 380, 683, 412), 'tw': (659, 380, 683, 412)}, file={'cn': './assets/cn/island/TRANSPORT_LOCKED.png', 'en': './assets/cn/island/TRANSPORT_LOCKED.png', 'jp': './assets/cn/island/TRANSPORT_LOCKED.png', 'tw': './assets/cn/island/TRANSPORT_LOCKED.png'})
TRANSPORT_RECEIVE = Button(area={'cn': (938, 206, 1065, 235), 'en': (938, 206, 1065, 235), 'jp': (938, 206, 1065, 235), 'tw': (938, 206, 1065, 235)}, color={'cn': (76, 195, 255), 'en': (76, 195, 255), 'jp': (76, 195, 255), 'tw': (76, 195, 255)}, button={'cn': (938, 206, 1065, 235), 'en': (938, 206, 1065, 235), 'jp': (938, 206, 1065, 235), 'tw': (938, 206, 1065, 235)}, file={'cn': './assets/cn/island/TRANSPORT_RECEIVE.png', 'en': './assets/cn/island/TRANSPORT_RECEIVE.png', 'jp': './assets/cn/island/TRANSPORT_RECEIVE.png', 'tw': './assets/cn/island/TRANSPORT_RECEIVE.png'})
TRANSPORT_START = Button(area={'cn': (1142, 170, 1174, 281), 'en': (1142, 170, 1174, 281), 'jp': (1142, 170, 1174, 281), 'tw': (1142, 170, 1174, 281)}, color={'cn': (98, 202, 255), 'en': (98, 202, 255), 'jp': (98, 202, 255), 'tw': (98, 202, 255)}, button={'cn': (1142, 170, 1174, 281), 'en': (1142, 170, 1174, 281), 'jp': (1142, 170, 1174, 281), 'tw': (1142, 170, 1174, 281)}, file={'cn': './assets/cn/island/TRANSPORT_START.png', 'en': './assets/cn/island/TRANSPORT_START.png', 'jp': './assets/cn/island/TRANSPORT_START.png', 'tw': './assets/cn/island/TRANSPORT_START.png'})
TRANSPORT_STATUS_PENDING = Button(area={'cn': (459, 138, 522, 156), 'en': (459, 138, 522, 156), 'jp': (459, 138, 522, 156), 'tw': (459, 138, 522, 156)}, color={'cn': (120, 121, 121), 'en': (120, 121, 121), 'jp': (120, 121, 121), 'tw': (120, 121, 121)}, button={'cn': (459, 138, 522, 156), 'en': (459, 138, 522, 156), 'jp': (459, 138, 522, 156), 'tw': (459, 138, 522, 156)}, file={'cn': './assets/cn/island/TRANSPORT_STATUS_PENDING.png', 'en': './assets/cn/island/TRANSPORT_STATUS_PENDING.png', 'jp': './assets/cn/island/TRANSPORT_STATUS_PENDING.png', 'tw': './assets/cn/island/TRANSPORT_STATUS_PENDING.png'})
TRANSPORT_STATUS_RUNNING = Button(area={'cn': (459, 138, 522, 156), 'en': (459, 138, 522, 156), 'jp': (459, 138, 522, 156), 'tw': (459, 138, 522, 156)}, color={'cn': (137, 136, 133), 'en': (137, 136, 133), 'jp': (137, 136, 133), 'tw': (137, 136, 133)}, button={'cn': (459, 138, 522, 156), 'en': (459, 138, 522, 156), 'jp': (459, 138, 522, 156), 'tw': (459, 138, 522, 156)}, file={'cn': './assets/cn/island/TRANSPORT_STATUS_RUNNING.png', 'en': './assets/cn/island/TRANSPORT_STATUS_RUNNING.png', 'jp': './assets/cn/island/TRANSPORT_STATUS_RUNNING.png', 'tw': './assets/cn/island/TRANSPORT_STATUS_RUNNING.png'})

View File

@@ -1,389 +1,14 @@
import cv2
import numpy as np
from scipy import signal
import module.config.server as server import module.config.server as server
from module.base.timer import Timer
from module.base.utils import color_similarity_2d, random_rectangle_vector, rgb2gray
from module.config.deep import deep_get
from module.island.assets import * from module.island.assets import *
from module.island.project_data import * from module.island.project_data import *
from module.island.project import IslandItem, IslandProduct, IslandProject from module.island.project import IslandProjectRun
from module.island.ui import IslandUI from module.island.transport import IslandTransportRun
from module.logger import logger from module.logger import logger
from module.map.map_grids import SelectedGrids
from module.ui.page import page_dormmenu, page_island, page_island_phone, page_main from module.ui.page import page_dormmenu, page_island, page_island_phone, page_main
class Island(IslandUI): class Island(IslandProjectRun, IslandTransportRun):
project = SelectedGrids([])
total = SelectedGrids([])
def project_detect(self, image):
"""
Get all projects from an image.
Args:
image (np.ndarray):
Returns:
SelectedGrids:
"""
image_gray = rgb2gray(image)
projects = SelectedGrids([IslandProject(image, image_gray, button)
for button in TEMPLATE_ISLAND_SWITCH.match_multi(image_gray)])
return projects.select(valid=True)
def project_receive(self, button, skip_first_screenshot=True):
"""
Receive and start a project.
Args:
button (Button): project button to click
Returns:
bool: if received.
"""
logger.hr('Island Project', level=2)
self.device.click_record_clear()
self.interval_clear([ISLAND_MANAGEMENT_CHECK, PROJECT_COMPLETE,
GET_ITEMS_ISLAND, ROLE_SELECT_ENTER])
received = False
enter = True
timeout = Timer(3, count=6).start()
while 1:
if skip_first_screenshot:
skip_first_screenshot = False
else:
self.device.screenshot()
if self.island_in_management(interval=5):
self.device.click(button)
timeout.reset()
continue
if self.handle_info_bar():
timeout.reset()
continue
if enter and self.appear_then_click(ROLE_SELECT_ENTER, offset=(5, 5), interval=2):
received = True
self.interval_clear(GET_ITEMS_ISLAND)
timeout.reset()
continue
if self.appear_then_click(PROJECT_COMPLETE, offset=(20, 20), interval=2):
received = True
enter = False
self.interval_clear(GET_ITEMS_ISLAND)
self.interval_reset(ROLE_SELECT_ENTER)
timeout.reset()
continue
if self.appear_then_click(GET_ITEMS_ISLAND, offset=(20, 20), interval=2):
enter = True
self.interval_clear(ROLE_SELECT_ENTER)
timeout.reset()
continue
if self.appear(ROLE_SELECT_CONFIRM, offset=(20, 20)):
break
if timeout.reached():
break
if not received:
product = IslandProduct(self.device.image)
if product.valid:
self.total = self.total.add_by_eq(SelectedGrids([product]))
self.device.click(ISLAND_CLICK_SAFE_AREA)
break
else:
self.interval_clear(ROLE_SELECT_ENTER)
return received
def island_select_manjuu(self, button):
"""
Args:
button (Button): role button to click
"""
self.interval_clear([ROLE_SELECT_CONFIRM, ISLAND_AMOUNT_MAX])
for _ in self.loop():
if self.appear(ROLE_SELECT_CHECK, offset=(20, 20)):
break
if self.appear(ROLE_SELECT_CONFIRM, offset=(20, 20), interval=5):
self.device.click(button)
continue
self.ui_click(
click_button=ROLE_SELECT_CONFIRM,
check_button=ISLAND_AMOUNT_MAX,
offset=(20, 20),
retry_wait=3,
skip_first_screenshot=True
)
def island_select_role(self, skip_first_screenshot=True):
"""
Select a role to produce.
Args:
skip_first_screenshot (bool):
Returns:
bool: if selected
"""
logger.info('Island select role')
timeout = Timer(1.5, count=3).start()
while 1:
if skip_first_screenshot:
skip_first_screenshot = False
else:
self.device.screenshot()
if timeout.reached():
self.island_product_quit()
return False
image = self.image_crop((0, 0, 910, 1280), copy=False)
sim, button = TEMPLATE_ISLAND_MANJUU.match_result(image)
if sim > 0.9:
self.island_select_manjuu(button)
return True
else:
logger.info('No manjuu found')
continue
def island_current_product(self):
"""
Get currently selected product on self.device.image.
Returns:
IslandItem: currently selected item
"""
image = self.image_crop(ISLAND_PRODUCT_ITEMS, copy=False)
y_top = ISLAND_PRODUCT_ITEMS.area[1]
line = cv2.reduce(image, 1, cv2.REDUCE_AVG)
# blue line
line = color_similarity_2d(line, color=(57, 189, 255))[:, 0]
parameters = {
'height': 200,
'distance': 50,
}
peaks, _ = signal.find_peaks(line, **parameters)
peaks = np.array(peaks) + y_top
return IslandItem(self.device.image, peaks)
def island_select_product(self, option, trial=2, skip_first_screenshot=True):
"""
Select a product in items list.
Args:
option (str): option to select
trail (int): retry times
skip_first_screenshot (bool):
Returns:
bool: if selected
"""
logger.hr('Island Select Product')
last = None
click_interval = Timer(1)
while 1:
if skip_first_screenshot:
skip_first_screenshot = False
else:
self.device.screenshot()
current = self.island_current_product()
if trial > 0 and not len(current.items):
trial -= 1
continue
if trial <= 0:
self.island_product_quit()
return False
if option == current.name:
logger.info(f'Selected item {option}')
return True
drag = True
for item in current.items:
if option == item.name:
if click_interval.reached():
self.device.click(item.button)
self.device.sleep(0.2)
click_interval.reset()
drag = False
if last == current.items[-1]:
logger.info(f'Reach the bottom of items, dit not match item {option}')
self.island_product_quit()
return False
if drag:
last = current.items[-1]
self.device.click(last.button)
self.island_drag_next_page((0, -300), ISLAND_PRODUCT_ITEMS.area, 0.5)
def island_product_confirm(self, skip_first_screenshot=True):
"""
Start the product after product selected.
Args:
skip_first_screenshot (bool):
"""
logger.info('Island product confirm')
last = None
success = False
timeout = Timer(1.5, count=3).start()
while 1:
if skip_first_screenshot:
skip_first_screenshot = False
else:
self.device.screenshot()
if timeout.reached():
break
if self.image_color_count(PROJECT_START, color=(151, 155, 155), threshold=221, count=200):
self.island_product_quit()
break
if not success:
if self.appear_then_click(ISLAND_AMOUNT_MAX, offset=(5, 5), interval=5):
timeout.reset()
continue
product = IslandProduct(self.device.image, new=True)
if product == last:
success = True
self.total = self.total.add_by_eq(SelectedGrids([product]))
timeout.reset()
continue
last = product
else:
if self.appear_then_click(PROJECT_START, offset=(20,20), interval=2):
timeout.reset()
self.interval_reset(ISLAND_MANAGEMENT_CHECK)
continue
if self.info_bar_count():
self.island_product_quit()
break
if self.island_in_management():
break
def island_drag_next_page(self, vector, box, sleep=0.5):
"""
Drag to the next page.
Args:
vector (tuple):
box (tuple):
sleep (float):
"""
logger.info('Island drag to next page')
p1, p2 = random_rectangle_vector(vector, box=box, random_range=(0, -5, 0, 5))
self.device.drag(p1, p2, segments=2, shake=(0, 25), point_random=(0, 0, 0, 0), shake_random=(0, -5, 0, 5))
self.device.sleep(sleep)
def ensure_project(self, project: IslandProject, trial=7, skip_first_screenshot=True):
logger.hr('Project ensure')
for _ in range(trial):
if skip_first_screenshot:
skip_first_screenshot = False
else:
self.device.screenshot()
projects = self.project_detect(self.device.image)
if not projects:
continue
if project.name in projects.get('name'):
logger.info(f'Ensured project: {project}')
break
self.island_drag_next_page((0, -500), ISLAND_PROJECT_SWIPE.area, 0.6)
def island_project_run(self, names, trial=2, skip_first_screenshot=True):
"""
Execute island run to receive and start project.
Args:
names (list[str]): a list of name for island receive
trial (int): retry times
skip_first_screenshot (bool):
Returns:
list[timedelta]: future finish timedelta
"""
logger.hr('Island Project Run', level=1)
end = False
timeout = Timer(3, count=3).start()
while 1:
if skip_first_screenshot:
skip_first_screenshot = False
else:
self.device.screenshot()
if timeout.reached():
break
projects = self.project_detect(self.device.image)
if trial > 0 and not projects:
trial -= 1
continue
projects: SelectedGrids = projects.filter(
lambda proj: proj.name in names and proj.name not in self.project.get('name'))
self.project = self.project.add_by_eq(projects)
for proj in projects:
if proj.name == names[-1]:
end = True
proj_config = self.island_project_config(proj)
for button, option, index in zip(
proj.slot_buttons.buttons, proj_config, range(len(proj_config))):
if option is None:
continue
if self.project_receive(button):
if self.island_select_role():
if self.island_select_product(option):
self.island_product_confirm()
self.ui_ensure_management_page()
if not end or index != len(proj_config) - 1:
self.ensure_project(proj)
timeout.reset()
if end:
break
self.island_drag_next_page((0, -500), ISLAND_PROJECT_SWIPE.area, 0.6)
# task delay
future_finish = sorted([f for f in self.total.get('finish_time') if f is not None])
logger.info(f'Project finish: {[str(f) for f in future_finish]}')
if not len(future_finish):
logger.info('No island project running')
return future_finish
def island_project_config(self, project: IslandProject):
"""
Args:
project (IslandProject):
Returns:
list[str]: a list of options for production
"""
slot_option = []
proj_id = project.id
for proj_slot in range(1, project.slot + 1):
option = self.config.__getattribute__(f'Island{proj_id}_Option{proj_slot}')
if option == 0:
slot_option.append(None)
continue
slot_option.append(deep_get(items_data_cn, [proj_id, option]))
return slot_option
@staticmethod @staticmethod
def island_config_to_names(config): def island_config_to_names(config):
""" """
@@ -398,12 +23,10 @@ class Island(IslandUI):
else: else:
return [] return []
def island_transport_run(self):
return []
def island_run(self, transport=False, project=True, names=None): def island_run(self, transport=False, project=True, names=None):
""" """
Execute island routine.
Args: Args:
transport (bool): transport (bool):
project (bool): project (bool):
@@ -425,6 +48,7 @@ class Island(IslandUI):
self.config.Scheduler_Enable = False self.config.Scheduler_Enable = False
return False return False
# task delay
if len(future_finish): if len(future_finish):
self.config.task_delay(target=future_finish) self.config.task_delay(target=future_finish)
else: else:

View File

@@ -1,13 +1,19 @@
from datetime import datetime, timedelta from datetime import datetime, timedelta
import cv2
import re import re
import numpy as np
from scipy import signal
from module.base.button import Button, ButtonGrid from module.base.button import Button, ButtonGrid
from module.base.utils import crop from module.base.timer import Timer
from module.config.deep import deep_values from module.base.utils import color_similarity_2d, crop, random_rectangle_vector, rgb2gray
from module.config.deep import deep_get, deep_values
from module.island.assets import * from module.island.assets import *
from module.island.project_data import * from module.island.project_data import *
from module.island.ui import OCR_PRODUCTION_TIME, OCR_PRODUCTION_TIME_REMAIN from module.island.ui import IslandUI
from module.ocr.ocr import Ocr from module.logger import logger
from module.map.map_grids import SelectedGrids
from module.ocr.ocr import Duration, Ocr
class ProjectNameOcr(Ocr): class ProjectNameOcr(Ocr):
@@ -18,11 +24,17 @@ class ProjectNameOcr(Ocr):
class IslandProject: class IslandProject:
# If success to parse project
valid: bool valid: bool
# OCR result
name: str name: str
# Project workplace id
id: int id: int
# max slot that the workplace has
max_slot: int max_slot: int
# available slots that the workplace has
slot: int slot: int
# buttons of all available slots
slot_buttons: ButtonGrid slot_buttons: ButtonGrid
def __init__(self, image, image_gray, button): def __init__(self, image, image_gray, button):
@@ -109,15 +121,27 @@ class ItemNameOcr(Ocr):
return result return result
class IslandProductionTime(Duration):
def after_process(self, result):
result = super().after_process(result)
if result == '0:40:00':
result = '01:40:00'
return result
class IslandProduct: class IslandProduct:
# Duration to run this product
duration: timedelta duration: timedelta
# If success to parse product duration
valid: bool valid: bool
def __init__(self, image, new=False): def __init__(self, image, new=False):
if new: if new:
self.duration = OCR_PRODUCTION_TIME.ocr(image) ocr = IslandProductionTime(OCR_PRODUCTION_TIME, lang='azur_lane_jp', name='OCR_PRODUCTION_TIME')
self.duration = ocr.ocr(image)
else: else:
self.duration = OCR_PRODUCTION_TIME_REMAIN.ocr(image) ocr = Duration(OCR_PRODUCTION_TIME_REMAIN, name='OCR_PRODUCTION_TIME_REMAIN')
self.duration = ocr.ocr(image)
self.valid = True self.valid = True
if not self.duration.total_seconds(): if not self.duration.total_seconds():
@@ -151,6 +175,15 @@ class IslandProduct:
return True return True
class IslandItem: class IslandItem:
# OCR result
name: str
# If success to parse item name
valid: bool
# Button to click for the current item
button: Button
# All buttons on this page to click
item_buttons: ButtonGrid
def __init__(self, image, y, get_button=True): def __init__(self, image, y, get_button=True):
self.image = image self.image = image
self.y = y self.y = y
@@ -239,3 +272,373 @@ class IslandItem:
return False return False
return True return True
class IslandProjectRun(IslandUI):
project = SelectedGrids([])
total = SelectedGrids([])
def project_detect(self, image):
"""
Get all projects from an image.
Args:
image (np.ndarray):
Returns:
SelectedGrids:
"""
image_gray = rgb2gray(image)
projects = SelectedGrids([IslandProject(image, image_gray, button)
for button in TEMPLATE_ISLAND_SWITCH.match_multi(image_gray)])
return projects.select(valid=True)
def project_receive(self, button, skip_first_screenshot=True):
"""
Receive and start a project.
Args:
button (Button): project button to click
Returns:
bool: if received.
"""
logger.hr('Island Project', level=2)
self.device.click_record_clear()
self.interval_clear([ISLAND_MANAGEMENT_CHECK, PROJECT_COMPLETE,
GET_ITEMS_ISLAND, ROLE_SELECT_ENTER])
received = False
enter = True
timeout = Timer(3, count=6).start()
while 1:
if skip_first_screenshot:
skip_first_screenshot = False
else:
self.device.screenshot()
if self.island_in_management(interval=5):
self.device.click(button)
timeout.reset()
continue
if self.handle_info_bar():
timeout.reset()
continue
if enter and self.appear_then_click(ROLE_SELECT_ENTER, offset=(5, 5), interval=2):
received = True
self.interval_clear(GET_ITEMS_ISLAND)
timeout.reset()
continue
if self.appear_then_click(PROJECT_COMPLETE, offset=(20, 20), interval=2):
received = True
enter = False
self.interval_clear(GET_ITEMS_ISLAND)
self.interval_reset(ROLE_SELECT_ENTER)
timeout.reset()
continue
if self.appear_then_click(GET_ITEMS_ISLAND, offset=(20, 20), interval=2):
enter = True
self.interval_clear(ROLE_SELECT_ENTER)
timeout.reset()
continue
if self.appear(ROLE_SELECT_CONFIRM, offset=(20, 20)):
break
if timeout.reached():
break
if not received:
product = IslandProduct(self.device.image)
if product.valid:
self.total = self.total.add_by_eq(SelectedGrids([product]))
self.device.click(ISLAND_CLICK_SAFE_AREA)
break
else:
self.interval_clear(ROLE_SELECT_ENTER)
return received
def island_select_manjuu(self, button):
"""
Args:
button (Button): role button to click
"""
self.interval_clear([ROLE_SELECT_CONFIRM, ISLAND_AMOUNT_MAX])
for _ in self.loop():
if self.appear(ROLE_SELECT_CHECK, offset=(20, 20)):
break
if self.appear(ROLE_SELECT_CONFIRM, offset=(20, 20), interval=5):
self.device.click(button)
continue
self.ui_click(
click_button=ROLE_SELECT_CONFIRM,
check_button=ISLAND_AMOUNT_MAX,
offset=(20, 20),
retry_wait=3,
skip_first_screenshot=True
)
def island_select_role(self, skip_first_screenshot=True):
"""
Select a role to produce.
Args:
skip_first_screenshot (bool):
Returns:
bool: if selected
"""
logger.info('Island select role')
timeout = Timer(1.5, count=3).start()
while 1:
if skip_first_screenshot:
skip_first_screenshot = False
else:
self.device.screenshot()
if timeout.reached():
self.island_product_quit()
return False
image = self.image_crop((0, 0, 910, 1280), copy=False)
sim, button = TEMPLATE_ISLAND_MANJUU.match_result(image)
if sim > 0.9:
self.island_select_manjuu(button)
return True
else:
logger.info('No manjuu found')
continue
def island_current_product(self):
"""
Get currently selected product on self.device.image.
Returns:
IslandItem: currently selected item
"""
image = self.image_crop(ISLAND_PRODUCT_ITEMS, copy=False)
y_top = ISLAND_PRODUCT_ITEMS.area[1]
line = cv2.reduce(image, 1, cv2.REDUCE_AVG)
# blue line
line = color_similarity_2d(line, color=(57, 189, 255))[:, 0]
parameters = {
'height': 200,
'distance': 50,
}
peaks, _ = signal.find_peaks(line, **parameters)
peaks = np.array(peaks) + y_top
return IslandItem(self.device.image, peaks)
def island_select_product(self, option, trial=2, skip_first_screenshot=True):
"""
Select a product in items list.
Args:
option (str): option to select
trail (int): retry times
skip_first_screenshot (bool):
Returns:
bool: if selected
"""
logger.hr('Island Select Product')
last = None
click_interval = Timer(1)
while 1:
if skip_first_screenshot:
skip_first_screenshot = False
else:
self.device.screenshot()
current = self.island_current_product()
if trial > 0 and not len(current.items):
trial -= 1
continue
if trial <= 0:
self.island_product_quit()
return False
if option == current.name:
logger.info(f'Selected item {option}')
return True
drag = True
for item in current.items:
if option == item.name:
if click_interval.reached():
self.device.click(item.button)
self.device.sleep(0.2)
click_interval.reset()
drag = False
if last == current.items[-1]:
logger.info(f'Reach the bottom of items, dit not match item {option}')
self.island_product_quit()
return False
if drag:
last = current.items[-1]
self.device.click(last.button)
self.island_drag_next_page((0, -300), ISLAND_PRODUCT_ITEMS.area, 0.5)
def island_product_confirm(self, skip_first_screenshot=True):
"""
Start the product after product selected.
Args:
skip_first_screenshot (bool):
"""
logger.info('Island product confirm')
last = None
success = False
timeout = Timer(1.5, count=3).start()
while 1:
if skip_first_screenshot:
skip_first_screenshot = False
else:
self.device.screenshot()
if timeout.reached():
break
if self.image_color_count(PROJECT_START, color=(151, 155, 155), threshold=221, count=200):
self.island_product_quit()
break
if not success:
if self.appear_then_click(ISLAND_AMOUNT_MAX, offset=(5, 5), interval=5):
timeout.reset()
continue
product = IslandProduct(self.device.image, new=True)
if product == last:
success = True
self.total = self.total.add_by_eq(SelectedGrids([product]))
timeout.reset()
continue
last = product
else:
if self.appear_then_click(PROJECT_START, offset=(20,20), interval=2):
timeout.reset()
self.interval_reset(ISLAND_MANAGEMENT_CHECK)
continue
if self.info_bar_count():
self.island_product_quit()
break
if self.island_in_management():
break
def island_drag_next_page(self, vector, box, sleep=0.5):
"""
Drag to the next page.
Args:
vector (tuple):
box (tuple):
sleep (float):
"""
logger.info('Island drag to next page')
p1, p2 = random_rectangle_vector(vector, box=box, random_range=(0, -5, 0, 5))
self.device.drag(p1, p2, segments=2, shake=(0, 25), point_random=(0, 0, 0, 0), shake_random=(0, -5, 0, 5))
self.device.sleep(sleep)
def ensure_project(self, project: IslandProject, trial=7, skip_first_screenshot=True):
logger.hr('Project ensure')
for _ in range(trial):
if skip_first_screenshot:
skip_first_screenshot = False
else:
self.device.screenshot()
projects = self.project_detect(self.device.image)
if not projects:
continue
if project.name in projects.get('name'):
logger.info(f'Ensured project: {project}')
break
self.island_drag_next_page((0, -500), ISLAND_PROJECT_SWIPE.area, 0.6)
def island_project_config(self, project: IslandProject):
"""
Args:
project (IslandProject):
Returns:
list[str]: a list of options for production
"""
slot_option = []
proj_id = project.id
for proj_slot in range(1, project.slot + 1):
option = self.config.__getattribute__(f'Island{proj_id}_Option{proj_slot}')
if option == 0:
slot_option.append(None)
continue
slot_option.append(deep_get(items_data_cn, [proj_id, option]))
return slot_option
def island_project_run(self, names, trial=2, skip_first_screenshot=True):
"""
Execute island run to receive and start project.
Args:
names (list[str]): a list of name for island receive
trial (int): retry times
skip_first_screenshot (bool):
Returns:
list[timedelta]: future finish timedelta
"""
logger.hr('Island Project Run', level=1)
end = False
timeout = Timer(3, count=3).start()
while 1:
if skip_first_screenshot:
skip_first_screenshot = False
else:
self.device.screenshot()
if timeout.reached():
break
projects = self.project_detect(self.device.image)
if trial > 0 and not projects:
trial -= 1
continue
projects: SelectedGrids = projects.filter(
lambda proj: proj.name in names and proj.name not in self.project.get('name'))
self.project = self.project.add_by_eq(projects)
for proj in projects:
if proj.name == names[-1]:
end = True
proj_config = self.island_project_config(proj)
for button, option, index in zip(
proj.slot_buttons.buttons, proj_config, range(len(proj_config))):
if option is None:
continue
if self.project_receive(button):
if self.island_select_role():
if self.island_select_product(option):
self.island_product_confirm()
self.ui_ensure_management_page()
if not end or index != len(proj_config) - 1:
self.ensure_project(proj)
timeout.reset()
if end:
break
self.island_drag_next_page((0, -500), ISLAND_PROJECT_SWIPE.area, 0.6)
# task delay
future_finish = sorted([f for f in self.total.get('finish_time') if f is not None])
logger.info(f'Project finish: {[str(f) for f in future_finish]}')
if not len(future_finish):
logger.info('No island project running')
return future_finish

View File

@@ -1,18 +1,11 @@
from datetime import datetime, timedelta from datetime import datetime, timedelta
import numpy as np
import re
from cached_property import cached_property from module.base.utils import area_offset
from module.base.button import ButtonGrid
from module.base.timer import Timer
from module.base.utils import area_offset, crop, image_color_count, rgb2gray
from module.island.assets import * from module.island.assets import *
from module.island.ui import IslandUI from module.island.ui import IslandUI
from module.logger import logger from module.logger import logger
from module.map.map_grids import SelectedGrids from module.map.map_grids import SelectedGrids
from module.ocr.ocr import Duration from module.ocr.ocr import Duration
from module.ui_white.assets import POPUP_CANCEL_WHITE, POPUP_CONFIRM_WHITE
class IslandTransport: class IslandTransport:
@@ -20,37 +13,20 @@ class IslandTransport:
index: int index: int
# If success to parse transport commission # If success to parse transport commission
valid: bool valid: bool
# If the commission is locked
locked: bool
# Duration to run this transport commission # Duration to run this transport commission
duration: timedelta duration: timedelta
# Status of transport commission # Status of transport commission
# Value: finished, running, pending, refreshing, unknown # Value: finished, running, pending, unknown
status: str status: str
# If the transprt commission need to start
start: bool
# If the transprt commission need to refresh
refresh: bool
def __init__(self, main, index, blacklist): def __init__(self, main, index):
"""
Args:
main:
index (int):
blacklist (list[Template]): a blacklist of templates of items to submit
"""
self.index = index self.index = index
self.blacklist = blacklist
self.image = main.device.image
self.valid = True self.valid = True
self.locked = False
self.duration = None self.duration = None
self.start = True self.can_start = True
self.refresh = False
self.items = SelectedGrids([])
self.parse_transport(main) self.parse_transport(main)
if not self.valid: if not self.valid:
self.start = False self.can_start = False
self.create_time = datetime.now() self.create_time = datetime.now()
def parse_transport(self, main): def parse_transport(self, main):
@@ -61,7 +37,7 @@ class IslandTransport:
# commission locked # commission locked
lock_offset = area_offset(offset, (0, delta * (self.index - 1))) lock_offset = area_offset(offset, (0, delta * (self.index - 1)))
if self.index >= 1 and main.appear(TRANSPORT_LOCKED, lock_offset): if self.index >= 1 and main.appear(TRANSPORT_LOCKED, lock_offset):
self.locked = True self.valid = False
return return
self.status = self.get_transport_status(main) self.status = self.get_transport_status(main)
@@ -71,42 +47,25 @@ class IslandTransport:
elif self.status == 'pending': elif self.status == 'pending':
button = OCR_TRANSPORT_TIME.move((0, self.offset[1] + 20)) button = OCR_TRANSPORT_TIME.move((0, self.offset[1] + 20))
ocr = Duration(button, lang='cnocr', letter=(207, 207, 207), name='OCR_TRANSPORT_TIME') ocr = Duration(button, lang='cnocr', letter=(207, 207, 207), name='OCR_TRANSPORT_TIME')
self.duration = ocr.ocr(self.image) self.duration = ocr.ocr(main.device.image)
if not self.duration.total_seconds(): if not self.duration.total_seconds():
self.valid = False self.valid = False
return return
# items info
origin_y = 174 + delta * self.index
grids = ButtonGrid(origin=(481, origin_y), delta=(105, 0),
button_shape=(86, 86), grid_shape=(3, 1), name='ITEMS')
self.items = SelectedGrids([TransportItem(self.image, button, self.blacklist)
for button in grids.buttons]).select(valid=True)
self.start = self.items.select(load=True).count == self.items.count
self.refresh = main.appear(TRANSPORT_REFRESH, offset=self.offset) and \
bool(self.items.select(refresh=True).count)
# detect items first because we need to get refresh info
if not main.match_template_color(TRANSPORT_START, offset=self.offset): if not main.match_template_color(TRANSPORT_START, offset=self.offset):
self.start = False self.can_start = False
return
elif self.status == 'running': elif self.status == 'running':
self.start = False self.can_start = False
button = OCR_TRANSPORT_TIME_REMAIN.move((0, self.offset[1] + 20)) button = OCR_TRANSPORT_TIME_REMAIN.move((0, self.offset[1] + 20))
ocr = Duration(button, name='OCR_TRANSPORT_TIME') ocr = Duration(button, name='OCR_TRANSPORT_TIME')
self.duration = ocr.ocr(self.image) self.duration = ocr.ocr(main.device.image)
if not self.duration.total_seconds(): if not self.duration.total_seconds():
self.valid = False self.valid = False
return return
elif self.status == 'finished': elif self.status == 'finished':
self.start = False self.can_start = False
elif self.status == 'refreshing':
self.start = False
button = OCR_TRANSPORT_REFRESH.move((0, self.offset[1] + 20))
ocr = Duration(button, letter=(63, 64, 66), name='OCR_TRANSPORT_REFRESH')
self.duration = ocr.ocr(self.image)
if not self.duration.total_seconds():
self.valid = False
return
def get_transport_status(self, main): def get_transport_status(self, main):
if main.appear(TRANSPORT_STATUS_PENDING, offset=self.offset): if main.appear(TRANSPORT_STATUS_PENDING, offset=self.offset):
@@ -115,24 +74,12 @@ class IslandTransport:
return 'running' return 'running'
elif main.appear(TRANSPORT_RECEIVE, offset=self.offset): elif main.appear(TRANSPORT_RECEIVE, offset=self.offset):
return 'finished' return 'finished'
elif main.appear(TRANSPORT_REFRESH_CHECK, offset=self.offset):
return 'refreshing'
else: else:
return 'unknown' return 'unknown'
def convert_to_refreshing(self):
if self.valid:
self.status = 'refreshing'
self.start = False
self.refresh = False
self.duration = timedelta(hours=0, minutes=30, seconds=0)
self.create_time = datetime.now()
def convert_to_running(self): def convert_to_running(self):
if self.valid: if self.valid:
self.status = 'running' self.status = 'running'
self.start = False
self.refresh = False
self.create_time = datetime.now() self.create_time = datetime.now()
@property @property
@@ -145,87 +92,15 @@ class IslandTransport:
def __str__(self): def __str__(self):
if not self.valid: if not self.valid:
return f'Index: {self.index} (Invalid)' return f'Index: {self.index} (Invalid)'
if self.locked:
return f'Index: {self.index} (Locked)'
info = {'Index': self.index, 'Status': self.status} info = {'Index': self.index, 'Status': self.status}
if self.duration: if self.duration:
info['Duration'] = self.duration info['Duration'] = self.duration
info['Start'] = self.start info['can_start'] = self.can_start
info['Refresh'] = self.refresh
info = ', '.join([f'{k}: {v}' for k, v in info.items()])
return info
class TransportItem:
# If the item is enough to submit and not in blacklist
load: bool
# If the item is in blacklist
refresh: bool
def __init__(self, image, button, blacklist):
"""
Args:
image:
button:
blacklist:
"""
self.image_raw = image
self.button = button
self.blacklist = blacklist
self.image = crop(image, button.area)
self.valid = self.predict_valid()
self.refresh = False
self.load = self.predict_load()
def predict_valid(self):
# gray item means an empty item
mean = np.mean(np.max(self.image, axis=2) > 234)
# blue bar on top of the item means already loaded
blue_bar_check = image_color_count(self.image[:10, :, :], color=(90, 201, 255), threshold=221, count=500)
return mean > 0.3 and not blue_bar_check
def predict_load(self):
if not self.valid:
return False
self.refresh = self.handle_blacklist_items()
if self.refresh:
return False
if not TEMPLATE_ITEM_SATISFIED.match(rgb2gray(self.image)):
return False
return True
def handle_blacklist_items(self):
"""
Check if current item is a blacklist item.
Returns:
bool: if any blacklist item
"""
for template in self.blacklist:
if template.match(self.image):
return True
return False
def __str__(self):
if not self.valid:
return '(Invalid)'
info = {'Load': self.load, 'Refresh': self.refresh}
info = ', '.join([f'{k}: {v}' for k, v in info.items()]) info = ', '.join([f'{k}: {v}' for k, v in info.items()])
return info return info
class IslandTransportRun(IslandUI): class IslandTransportRun(IslandUI):
@cached_property
def blacklist(self):
blacklist = []
for k, v in self.config.cross_get(keys='Island.IslandTransport').items():
if k.startswith('Submit') and not v:
item = k.split('Submit')[-1]
item = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', item)
item = re.sub('([a-z0-9])([A-Z])', r'\1_\2', item)
blacklist.append(globals()[f'TEMPLATE_{item.upper()}'])
return blacklist
def _transport_detect(self): def _transport_detect(self):
""" """
Get all commissions from self.device.image. Get all commissions from self.device.image.
@@ -236,10 +111,8 @@ class IslandTransportRun(IslandUI):
logger.hr('Transport Commission detect') logger.hr('Transport Commission detect')
commission = [] commission = []
for index in range(3): for index in range(3):
comm = IslandTransport(main=self, index=index, blacklist=self.blacklist) comm = IslandTransport(main=self, index=index)
logger.attr(f'Transport Commission', comm) logger.attr(f'Transport Commission', comm)
for item in comm.items:
logger.attr(item.button, item)
commission.append(comm) commission.append(comm)
return SelectedGrids(commission) return SelectedGrids(commission)
@@ -262,11 +135,8 @@ class IslandTransportRun(IslandUI):
self.device.screenshot() self.device.screenshot()
commissions = self._transport_detect() commissions = self._transport_detect()
if not commissions.count: if commissions.count >= 2 and commissions.select(valid=False).count == 1:
logger.warning('No commission detected, retry commission detect') logger.warning('Found 1 invalid commission, retry commission detect')
continue
elif commissions.select(valid=False).count:
logger.warning('Found 1 invalid commission at least, retry commission detect')
continue continue
else: else:
return commissions.select(valid=True) return commissions.select(valid=True)
@@ -274,154 +144,12 @@ class IslandTransportRun(IslandUI):
logger.info('trials of transport commission detect exhausted, stop') logger.info('trials of transport commission detect exhausted, stop')
return commissions.select(valid=True) return commissions.select(valid=True)
def transport_receive(self):
"""
Receive all transport missions from transport page.
Returns:
bool: if received
"""
logger.hr('Island Transport', level=2)
self.device.click_record_clear()
self.interval_clear([GET_ITEMS_ISLAND, TRANSPORT_RECEIVE, POPUP_CANCEL_WHITE])
success = True
click_timer = Timer(5, count=10).start()
confirm_timer = Timer(1, count=2).start()
for _ in self.loop():
if self.handle_info_bar():
click_timer.reset()
confirm_timer.reset()
continue
if self.appear_then_click(TRANSPORT_RECEIVE, offset=(-20, -20, 20, 400), interval=2):
success = False
click_timer.reset()
confirm_timer.reset()
continue
if self.handle_get_items():
success = True
click_timer.reset()
confirm_timer.reset()
continue
if self.handle_popup_cancel('REFRESH_CANCEL', offset=(30, 30)):
click_timer.reset()
confirm_timer.reset()
continue
# handle island level up
if click_timer.reached():
success = True
self.device.click(GET_ITEMS_ISLAND)
self.device.sleep(0.3)
click_timer.reset()
confirm_timer.reset()
continue
if self.island_in_transport():
if success and confirm_timer.reached():
break
click_timer.reset()
else:
confirm_timer.reset()
return success
def transport_refresh(self, comm):
"""
Refresh the specific transport mission from transport page.
Args:
comm (IslandTransport): the commission to refresh
Returns:
bool: if success
"""
logger.info('Transport commission refresh')
self.interval_clear([TRANSPORT_REFRESH, POPUP_CONFIRM_WHITE])
success = True
confirm_timer = Timer(1, count=2).start()
for _ in self.loop():
if self.appear_then_click(TRANSPORT_REFRESH, offset=comm.offset, interval=2):
continue
if self.handle_popup_confirm('REFRESH_CONFIRM', offset=(30, 30)):
success = True
confirm_timer.reset()
continue
if self.island_in_transport():
if success and confirm_timer.reached():
break
else:
confirm_timer.reset()
return success
def transport_start(self, comm):
"""
Start the specific transport mission from transport page.
Args:
comm (IslandTransport): the commission to start
Returns:
bool: if success
"""
logger.info('Transport commission start')
self.interval_clear([GET_ITEMS_ISLAND, TRANSPORT_START, POPUP_CANCEL_WHITE])
success = True
confirm_timer = Timer(1, count=2).start()
for _ in self.loop():
if self.appear_then_click(TRANSPORT_START, offset=comm.offset, interval=2):
success = False
confirm_timer.reset()
continue
if self.handle_get_items():
success = True
confirm_timer.reset()
continue
if self.handle_popup_cancel('REFRESH_CANCEL', offset=(30, 30)):
confirm_timer.reset()
continue
if self.island_in_transport():
if success and confirm_timer.reached():
break
else:
confirm_timer.reset()
return success
def island_transport_run(self): def island_transport_run(self):
"""
Execute island run to receive and start transport commissions.
Returns:
list[timedelta]: future finish timedelta
"""
logger.hr('Island Transport Run', level=1) logger.hr('Island Transport Run', level=1)
future_finish = [] future_finish = []
self.transport_receive() commissions = self.transport_detect(trial=2)
commissions = self.transport_detect(trial=5)
comm_refresh = commissions.select(status='pending', refresh=True) future_finish = sorted([f for f in commissions.select(status='running').get('finish_time') if f is not None])
comm_choose = commissions.select(status='pending', start=True)
for comm in comm_refresh:
if self.transport_refresh(comm):
comm.convert_to_refreshing()
for comm in comm_choose:
if self.transport_start(comm):
comm.convert_to_running()
logger.hr('Showing transport commission', level=2)
for comm in commissions:
logger.attr(f'Transport Commission', comm)
running_finish = [f for f in commissions.select(status='running').get('finish_time') if f is not None]
refreshing_finish = [f for f in commissions.select(status='refreshing').get('finish_time') if f is not None]
future_finish = sorted(running_finish + refreshing_finish)
logger.info(f'Transport finish: {[str(f) for f in future_finish]}') logger.info(f'Transport finish: {[str(f) for f in future_finish]}')
if not len(future_finish): if not len(future_finish):
logger.info('No island transport running') logger.info('No island transport running')

View File

@@ -1,24 +1,11 @@
from module.base.timer import Timer from module.base.timer import Timer
from module.island.assets import * from module.island.assets import *
from module.logger import logger from module.logger import logger
from module.ocr.ocr import Duration
from module.ui.assets import SHOP_BACK_ARROW from module.ui.assets import SHOP_BACK_ARROW
from module.ui.page import page_island_phone from module.ui.page import page_island_phone
from module.ui.ui import UI from module.ui.ui import UI
class IslandProductionTime(Duration):
def after_process(self, result):
result = super().after_process(result)
if result == '0:40:00':
result = '01:40:00'
return result
OCR_PRODUCTION_TIME = IslandProductionTime(OCR_PRODUCTION_TIME, lang='azur_lane_jp', name='OCR_PRODUCTION_TIME')
OCR_PRODUCTION_TIME_REMAIN = Duration(OCR_PRODUCTION_TIME_REMAIN, name='OCR_PRODUCTION_TIME_REMAIN')
class IslandUI(UI): class IslandUI(UI):
def island_in_management(self, interval=0): def island_in_management(self, interval=0):
""" """