Add: Support for event assignments
BIN
assets/cn/assignment/dispatch/ASSIGNMENT_START.SEARCH.png
Normal file
After Width: | Height: | Size: 24 KiB |
BIN
assets/cn/assignment/dispatch/CHARACTER_SUPPORT_LIST.png
Normal file
After Width: | Height: | Size: 9.0 KiB |
BIN
assets/en/assignment/dispatch/ASSIGNMENT_START.SEARCH.png
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
assets/en/assignment/dispatch/CHARACTER_SUPPORT_LIST.png
Normal file
After Width: | Height: | Size: 9.8 KiB |
BIN
assets/share/assignment/claim/REPORT.png
Normal file
After Width: | Height: | Size: 27 KiB |
BIN
assets/share/assignment/dispatch/CHARACTER_SUPPORT.png
Normal file
After Width: | Height: | Size: 38 KiB |
BIN
assets/share/assignment/dispatch/CHARACTER_SUPPORT_SELECTED.png
Normal file
After Width: | Height: | Size: 5.4 KiB |
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 34 KiB |
BIN
assets/share/assignment/dispatch/EMPTY_SLOT_SUPPORT.png
Normal file
After Width: | Height: | Size: 6.8 KiB |
Before Width: | Height: | Size: 8.4 KiB |
Before Width: | Height: | Size: 10 KiB |
BIN
assets/share/assignment/ui/LOCKED.png
Normal file
After Width: | Height: | Size: 60 KiB |
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 33 KiB |
Before Width: | Height: | Size: 8.2 KiB |
@ -1,7 +1,6 @@
|
|||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import typing as t
|
import typing as t
|
||||||
from collections import namedtuple
|
|
||||||
from functools import cached_property
|
from functools import cached_property
|
||||||
|
|
||||||
from module.base.code_generator import CodeGenerator
|
from module.base.code_generator import CodeGenerator
|
||||||
@ -254,14 +253,19 @@ class KeywordExtract:
|
|||||||
self.clear_keywords()
|
self.clear_keywords()
|
||||||
|
|
||||||
def generate_assignment_keywords(self):
|
def generate_assignment_keywords(self):
|
||||||
KeywordFromFile = namedtuple('KeywordFromFile', ('file', 'class_name', 'output_file'))
|
self.load_keywords(['空间站特派'])
|
||||||
for keyword in (
|
self.write_keywords(
|
||||||
KeywordFromFile('ExpeditionGroup.json', 'AssignmentGroup', './tasks/assignment/keywords/group.py'),
|
keyword_class='AssignmentEventGroup',
|
||||||
KeywordFromFile('ExpeditionData.json', 'AssignmentEntry', './tasks/assignment/keywords/entry.py')
|
output_file='./tasks/assignment/keywords/event_group.py'
|
||||||
|
)
|
||||||
|
for file_name, class_name, output_file in (
|
||||||
|
('ExpeditionGroup.json', 'AssignmentGroup', './tasks/assignment/keywords/group.py'),
|
||||||
|
('ExpeditionData.json', 'AssignmentEntry', './tasks/assignment/keywords/entry.py'),
|
||||||
|
('ActivityExpedition.json', 'AssignmentEventEntry', './tasks/assignment/keywords/event_entry.py'),
|
||||||
):
|
):
|
||||||
file = os.path.join(TextMap.DATA_FOLDER, 'ExcelOutput', keyword.file)
|
file = os.path.join(TextMap.DATA_FOLDER, 'ExcelOutput', file_name)
|
||||||
self.load_keywords(deep_get(data, 'Name.Hash') for data in read_file(file).values())
|
self.load_keywords(deep_get(data, 'Name.Hash') for data in read_file(file).values())
|
||||||
self.write_keywords(keyword_class=keyword.class_name, output_file=keyword.output_file)
|
self.write_keywords(keyword_class=class_name, output_file=output_file)
|
||||||
|
|
||||||
def generate_map_planes(self):
|
def generate_map_planes(self):
|
||||||
planes = {
|
planes = {
|
||||||
|
@ -375,17 +375,17 @@ class Duration(Ocr):
|
|||||||
def timedelta_regex(cls, lang):
|
def timedelta_regex(cls, lang):
|
||||||
regex_str = {
|
regex_str = {
|
||||||
'cn': r'^(?P<prefix>.*?)'
|
'cn': r'^(?P<prefix>.*?)'
|
||||||
r'((?P<days>\d{1,2})天)?'
|
r'((?P<days>\d{1,2})\s*天\s*)?'
|
||||||
r'((?P<hours>\d{1,2})小时)?'
|
r'((?P<hours>\d{1,2})\s*小时\s*)?'
|
||||||
r'((?P<minutes>\d{1,2})分钟)?'
|
r'((?P<minutes>\d{1,2})\s*分钟\s*)?'
|
||||||
r'((?P<seconds>\d{1,2})秒)?'
|
r'((?P<seconds>\d{1,2})\s*秒)?'
|
||||||
r'$',
|
r'(?P<suffix>[^天时钟秒]*?)$',
|
||||||
'en': r'^(?P<prefix>.*?)'
|
'en': r'^(?P<prefix>.*?)'
|
||||||
r'((?P<days>\d{1,2})\s*d\s*)?'
|
r'((?P<days>\d{1,2})\s*d\s*)?'
|
||||||
r'((?P<hours>\d{1,2})\s*h\s*)?'
|
r'((?P<hours>\d{1,2})\s*h\s*)?'
|
||||||
r'((?P<minutes>\d{1,2})\s*m\s*)?'
|
r'((?P<minutes>\d{1,2})\s*m\s*)?'
|
||||||
r'((?P<seconds>\d{1,2})\s*s)?'
|
r'((?P<seconds>\d{1,2})\s*s)?'
|
||||||
r'$'
|
r'(?P<suffix>[^dhms]*?)$'
|
||||||
}[lang]
|
}[lang]
|
||||||
return re.compile(regex_str)
|
return re.compile(regex_str)
|
||||||
|
|
||||||
|
@ -42,9 +42,11 @@ class DraggableList:
|
|||||||
self.name = name
|
self.name = name
|
||||||
self.keyword_class = keyword_class
|
self.keyword_class = keyword_class
|
||||||
self.ocr_class = ocr_class
|
self.ocr_class = ocr_class
|
||||||
if isinstance(keyword_class, list):
|
if not isinstance(keyword_class, list):
|
||||||
keyword_class = keyword_class[0]
|
keyword_class = [keyword_class]
|
||||||
self.known_rows = list(keyword_class.instances.values())
|
self.known_rows = [
|
||||||
|
kw for kc in keyword_class for kw in kc.instances.values()
|
||||||
|
]
|
||||||
self.search_button = search_button
|
self.search_button = search_button
|
||||||
self.check_row_order = check_row_order
|
self.check_row_order = check_row_order
|
||||||
self.active_color = active_color
|
self.active_color = active_color
|
||||||
|
@ -43,3 +43,13 @@ REDISPATCH = ButtonWrapper(
|
|||||||
button=(779, 592, 905, 629),
|
button=(779, 592, 905, 629),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
REPORT = ButtonWrapper(
|
||||||
|
name='REPORT',
|
||||||
|
share=Button(
|
||||||
|
file='./assets/share/assignment/claim/REPORT.png',
|
||||||
|
area=(0, 154, 266, 542),
|
||||||
|
search=(0, 134, 286, 562),
|
||||||
|
color=(33, 34, 37),
|
||||||
|
button=(0, 154, 266, 542),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
@ -8,14 +8,14 @@ ASSIGNMENT_START = ButtonWrapper(
|
|||||||
cn=Button(
|
cn=Button(
|
||||||
file='./assets/cn/assignment/dispatch/ASSIGNMENT_START.png',
|
file='./assets/cn/assignment/dispatch/ASSIGNMENT_START.png',
|
||||||
area=(581, 321, 699, 349),
|
area=(581, 321, 699, 349),
|
||||||
search=(561, 301, 719, 369),
|
search=(573, 299, 707, 412),
|
||||||
color=(93, 84, 66),
|
color=(93, 84, 66),
|
||||||
button=(581, 321, 699, 349),
|
button=(581, 321, 699, 349),
|
||||||
),
|
),
|
||||||
en=Button(
|
en=Button(
|
||||||
file='./assets/en/assignment/dispatch/ASSIGNMENT_START.png',
|
file='./assets/en/assignment/dispatch/ASSIGNMENT_START.png',
|
||||||
area=(679, 323, 784, 347),
|
area=(679, 323, 784, 347),
|
||||||
search=(659, 303, 804, 367),
|
search=(669, 297, 794, 416),
|
||||||
color=(93, 83, 65),
|
color=(93, 83, 65),
|
||||||
button=(679, 323, 784, 347),
|
button=(679, 323, 784, 347),
|
||||||
),
|
),
|
||||||
@ -87,6 +87,43 @@ CHARACTER_LIST = ButtonWrapper(
|
|||||||
button=(91, 163, 136, 180),
|
button=(91, 163, 136, 180),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
CHARACTER_SUPPORT = ButtonWrapper(
|
||||||
|
name='CHARACTER_SUPPORT',
|
||||||
|
share=Button(
|
||||||
|
file='./assets/share/assignment/dispatch/CHARACTER_SUPPORT.png',
|
||||||
|
area=(103, 212, 435, 302),
|
||||||
|
search=(83, 192, 455, 322),
|
||||||
|
color=(62, 60, 63),
|
||||||
|
button=(103, 212, 435, 302),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
CHARACTER_SUPPORT_LIST = ButtonWrapper(
|
||||||
|
name='CHARACTER_SUPPORT_LIST',
|
||||||
|
cn=Button(
|
||||||
|
file='./assets/cn/assignment/dispatch/CHARACTER_SUPPORT_LIST.png',
|
||||||
|
area=(91, 166, 171, 186),
|
||||||
|
search=(71, 146, 191, 206),
|
||||||
|
color=(147, 146, 143),
|
||||||
|
button=(91, 166, 171, 186),
|
||||||
|
),
|
||||||
|
en=Button(
|
||||||
|
file='./assets/en/assignment/dispatch/CHARACTER_SUPPORT_LIST.png',
|
||||||
|
area=(90, 167, 267, 189),
|
||||||
|
search=(70, 147, 287, 209),
|
||||||
|
color=(169, 168, 165),
|
||||||
|
button=(90, 167, 267, 189),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
CHARACTER_SUPPORT_SELECTED = ButtonWrapper(
|
||||||
|
name='CHARACTER_SUPPORT_SELECTED',
|
||||||
|
share=Button(
|
||||||
|
file='./assets/share/assignment/dispatch/CHARACTER_SUPPORT_SELECTED.png',
|
||||||
|
area=(190, 270, 266, 295),
|
||||||
|
search=(170, 250, 286, 315),
|
||||||
|
color=(39, 39, 39),
|
||||||
|
button=(190, 270, 266, 295),
|
||||||
|
),
|
||||||
|
)
|
||||||
CONFIRM_ASSIGNMENT = ButtonWrapper(
|
CONFIRM_ASSIGNMENT = ButtonWrapper(
|
||||||
name='CONFIRM_ASSIGNMENT',
|
name='CONFIRM_ASSIGNMENT',
|
||||||
cn=Button(
|
cn=Button(
|
||||||
@ -149,8 +186,18 @@ EMPTY_SLOT = ButtonWrapper(
|
|||||||
share=Button(
|
share=Button(
|
||||||
file='./assets/share/assignment/dispatch/EMPTY_SLOT.png',
|
file='./assets/share/assignment/dispatch/EMPTY_SLOT.png',
|
||||||
area=(1075, 562, 1110, 597),
|
area=(1075, 562, 1110, 597),
|
||||||
search=(1054, 542, 1220, 616),
|
search=(873, 543, 1099, 609),
|
||||||
color=(200, 200, 195),
|
color=(200, 200, 195),
|
||||||
button=(1075, 562, 1110, 597),
|
button=(1075, 562, 1110, 597),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
EMPTY_SLOT_SUPPORT = ButtonWrapper(
|
||||||
|
name='EMPTY_SLOT_SUPPORT',
|
||||||
|
share=Button(
|
||||||
|
file='./assets/share/assignment/dispatch/EMPTY_SLOT_SUPPORT.png',
|
||||||
|
area=(1152, 561, 1187, 592),
|
||||||
|
search=(1132, 541, 1207, 612),
|
||||||
|
color=(203, 202, 198),
|
||||||
|
button=(1152, 561, 1187, 592),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
@ -3,16 +3,6 @@ from module.base.button import Button, ButtonWrapper
|
|||||||
# This file was auto-generated, do not modify it manually. To generate:
|
# This file was auto-generated, do not modify it manually. To generate:
|
||||||
# ``` python -m dev_tools.button_extract ```
|
# ``` python -m dev_tools.button_extract ```
|
||||||
|
|
||||||
CHARACTER_MATERIALS = ButtonWrapper(
|
|
||||||
name='CHARACTER_MATERIALS',
|
|
||||||
share=Button(
|
|
||||||
file='./assets/share/assignment/ui/CHARACTER_MATERIALS.png',
|
|
||||||
area=(146, 91, 255, 124),
|
|
||||||
search=(126, 71, 275, 144),
|
|
||||||
color=(213, 213, 208),
|
|
||||||
button=(146, 91, 255, 124),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
DISPATCHED = ButtonWrapper(
|
DISPATCHED = ButtonWrapper(
|
||||||
name='DISPATCHED',
|
name='DISPATCHED',
|
||||||
cn=Button(
|
cn=Button(
|
||||||
@ -40,14 +30,14 @@ ENTRY_LOADED = ButtonWrapper(
|
|||||||
button=(467, 235, 498, 619),
|
button=(467, 235, 498, 619),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
EXP_MATERIALS_CREDITS = ButtonWrapper(
|
LOCKED = ButtonWrapper(
|
||||||
name='EXP_MATERIALS_CREDITS',
|
name='LOCKED',
|
||||||
share=Button(
|
share=Button(
|
||||||
file='./assets/share/assignment/ui/EXP_MATERIALS_CREDITS.png',
|
file='./assets/share/assignment/ui/LOCKED.png',
|
||||||
area=(310, 85, 447, 134),
|
area=(1051, 480, 1237, 630),
|
||||||
search=(290, 65, 467, 154),
|
search=(1031, 460, 1257, 650),
|
||||||
color=(214, 214, 210),
|
color=(53, 48, 40),
|
||||||
button=(310, 85, 447, 134),
|
button=(1051, 480, 1237, 630),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
OCR_ASSIGNMENT_ENTRY_LIST = ButtonWrapper(
|
OCR_ASSIGNMENT_ENTRY_LIST = ButtonWrapper(
|
||||||
@ -64,10 +54,10 @@ OCR_ASSIGNMENT_GROUP_LIST = ButtonWrapper(
|
|||||||
name='OCR_ASSIGNMENT_GROUP_LIST',
|
name='OCR_ASSIGNMENT_GROUP_LIST',
|
||||||
share=Button(
|
share=Button(
|
||||||
file='./assets/share/assignment/ui/OCR_ASSIGNMENT_GROUP_LIST.png',
|
file='./assets/share/assignment/ui/OCR_ASSIGNMENT_GROUP_LIST.png',
|
||||||
area=(106, 70, 848, 135),
|
area=(116, 81, 827, 131),
|
||||||
search=(86, 50, 868, 155),
|
search=(96, 61, 847, 151),
|
||||||
color=(73, 72, 70),
|
color=(80, 79, 77),
|
||||||
button=(106, 70, 848, 135),
|
button=(116, 81, 827, 131),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
OCR_ASSIGNMENT_LIMIT = ButtonWrapper(
|
OCR_ASSIGNMENT_LIMIT = ButtonWrapper(
|
||||||
@ -90,13 +80,3 @@ OCR_ASSIGNMENT_TIME = ButtonWrapper(
|
|||||||
button=(605, 564, 886, 589),
|
button=(605, 564, 886, 589),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
SYNTHESIS_MATERIALS = ButtonWrapper(
|
|
||||||
name='SYNTHESIS_MATERIALS',
|
|
||||||
share=Button(
|
|
||||||
file='./assets/share/assignment/ui/SYNTHESIS_MATERIALS.png',
|
|
||||||
area=(521, 91, 603, 128),
|
|
||||||
search=(501, 71, 623, 148),
|
|
||||||
color=(208, 208, 203),
|
|
||||||
button=(521, 91, 603, 128),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
@ -1,17 +1,12 @@
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
from module.logger import logger
|
from module.logger import logger
|
||||||
from module.ocr.ocr import Duration
|
|
||||||
from tasks.assignment.assets.assets_assignment_claim import CLAIM
|
from tasks.assignment.assets.assets_assignment_claim import CLAIM
|
||||||
from tasks.assignment.assets.assets_assignment_ui import (
|
from tasks.assignment.assets.assets_assignment_dispatch import EMPTY_SLOT
|
||||||
DISPATCHED,
|
from tasks.assignment.assets.assets_assignment_ui import DISPATCHED, LOCKED
|
||||||
OCR_ASSIGNMENT_TIME,
|
|
||||||
)
|
|
||||||
from tasks.assignment.claim import AssignmentClaim
|
from tasks.assignment.claim import AssignmentClaim
|
||||||
from tasks.assignment.keywords import (
|
from tasks.assignment.keywords import (KEYWORDS_ASSIGNMENT_GROUP,
|
||||||
AssignmentEntry,
|
AssignmentEntry, AssignmentEventGroup)
|
||||||
KEYWORDS_ASSIGNMENT_GROUP,
|
|
||||||
)
|
|
||||||
from tasks.base.page import page_assignment, page_menu
|
from tasks.base.page import page_assignment, page_menu
|
||||||
from tasks.battle_pass.keywords import KEYWORD_BATTLE_PASS_QUEST
|
from tasks.battle_pass.keywords import KEYWORD_BATTLE_PASS_QUEST
|
||||||
from tasks.daily.keywords import KEYWORDS_DAILY_QUEST
|
from tasks.daily.keywords import KEYWORDS_DAILY_QUEST
|
||||||
@ -19,7 +14,7 @@ from tasks.daily.synthesize import SynthesizeUI
|
|||||||
|
|
||||||
|
|
||||||
class Assignment(AssignmentClaim, SynthesizeUI):
|
class Assignment(AssignmentClaim, SynthesizeUI):
|
||||||
def run(self, assignments: list[AssignmentEntry] = None, duration: int = None):
|
def run(self, assignments: list[AssignmentEntry] = None, duration: int = None, event_first: bool = None):
|
||||||
self.config.update_battle_pass_quests()
|
self.config.update_battle_pass_quests()
|
||||||
self.config.update_daily_quests()
|
self.config.update_daily_quests()
|
||||||
|
|
||||||
@ -35,14 +30,25 @@ class Assignment(AssignmentClaim, SynthesizeUI):
|
|||||||
'There are duplicate assignments in config, check it out')
|
'There are duplicate assignments in config, check it out')
|
||||||
if duration is None:
|
if duration is None:
|
||||||
duration = self.config.Assignment_Duration
|
duration = self.config.Assignment_Duration
|
||||||
|
if event_first is None:
|
||||||
|
event_first = self.config.Assignment_WhenEventAssignmentsArePresent == 'event_first'
|
||||||
|
|
||||||
self.dispatched = dict()
|
self.dispatched = dict()
|
||||||
self.has_new_dispatch = False
|
self.has_new_dispatch = False
|
||||||
self.ensure_scroll_top(page_menu)
|
self.ensure_scroll_top(page_menu)
|
||||||
self.ui_ensure(page_assignment)
|
self.ui_ensure(page_assignment)
|
||||||
# Iterate in user-specified order, return undispatched ones
|
event_ongoing = next((
|
||||||
undispatched = list(self._check_inlist(assignments, duration))
|
g for g in self._iter_groups()
|
||||||
remain = self._check_all()
|
if isinstance(g, AssignmentEventGroup)
|
||||||
|
), None)
|
||||||
|
if event_first and event_ongoing is not None:
|
||||||
|
undispatched = assignments
|
||||||
|
remain = self._check_all()
|
||||||
|
remain = self._dispatch_event(remain)
|
||||||
|
else:
|
||||||
|
# Iterate in user-specified order, return undispatched ones
|
||||||
|
undispatched = list(self._check_inlist(assignments, duration))
|
||||||
|
remain = self._check_all()
|
||||||
# There are unchecked assignments
|
# There are unchecked assignments
|
||||||
if remain > 0:
|
if remain > 0:
|
||||||
for assignment in undispatched[:remain]:
|
for assignment in undispatched[:remain]:
|
||||||
@ -61,7 +67,8 @@ class Assignment(AssignmentClaim, SynthesizeUI):
|
|||||||
quests = self.config.stored.BattlePassTodayQuest.load_quests()
|
quests = self.config.stored.BattlePassTodayQuest.load_quests()
|
||||||
if self.has_new_dispatch:
|
if self.has_new_dispatch:
|
||||||
if KEYWORD_BATTLE_PASS_QUEST.Dispatch_1_assignments in quests:
|
if KEYWORD_BATTLE_PASS_QUEST.Dispatch_1_assignments in quests:
|
||||||
logger.info('Achieved battle pass quest Dispatch_1_assignments')
|
logger.info(
|
||||||
|
'Achieved battle pass quest Dispatch_1_assignments')
|
||||||
self.config.task_call('BattlePass')
|
self.config.task_call('BattlePass')
|
||||||
# Check daily
|
# Check daily
|
||||||
quests = self.config.stored.DailyQuest.load_quests()
|
quests = self.config.stored.DailyQuest.load_quests()
|
||||||
@ -93,6 +100,8 @@ class Assignment(AssignmentClaim, SynthesizeUI):
|
|||||||
f'User specified assignments: {", ".join([x.name for x in assignments])}')
|
f'User specified assignments: {", ".join([x.name for x in assignments])}')
|
||||||
_, remain, _ = self._limit_status
|
_, remain, _ = self._limit_status
|
||||||
for assignment in assignments:
|
for assignment in assignments:
|
||||||
|
if assignment in self.dispatched:
|
||||||
|
continue
|
||||||
logger.hr('Assignment inlist', level=2)
|
logger.hr('Assignment inlist', level=2)
|
||||||
logger.info(f'Check assignment inlist: {assignment}')
|
logger.info(f'Check assignment inlist: {assignment}')
|
||||||
self.goto_entry(assignment)
|
self.goto_entry(assignment)
|
||||||
@ -100,8 +109,8 @@ class Assignment(AssignmentClaim, SynthesizeUI):
|
|||||||
self.claim(assignment, duration, should_redispatch=True)
|
self.claim(assignment, duration, should_redispatch=True)
|
||||||
continue
|
continue
|
||||||
if self.appear(DISPATCHED):
|
if self.appear(DISPATCHED):
|
||||||
self.dispatched[assignment] = datetime.now() + Duration(
|
self.dispatched[assignment] = datetime.now() + \
|
||||||
OCR_ASSIGNMENT_TIME).ocr_single_line(self.device.image)
|
self._get_assignment_time()
|
||||||
continue
|
continue
|
||||||
if remain > 0:
|
if remain > 0:
|
||||||
self.dispatch(assignment, duration)
|
self.dispatch(assignment, duration)
|
||||||
@ -123,9 +132,7 @@ class Assignment(AssignmentClaim, SynthesizeUI):
|
|||||||
return remain
|
return remain
|
||||||
for group in self._iter_groups():
|
for group in self._iter_groups():
|
||||||
self.goto_group(group)
|
self.goto_group(group)
|
||||||
entries = self._iter_entries()
|
for assignment in self._iter_entries():
|
||||||
for _ in range(len(group.entries)):
|
|
||||||
assignment = next(entries)
|
|
||||||
if assignment in self.dispatched:
|
if assignment in self.dispatched:
|
||||||
continue
|
continue
|
||||||
logger.hr('Assignment all', level=2)
|
logger.hr('Assignment all', level=2)
|
||||||
@ -136,8 +143,8 @@ class Assignment(AssignmentClaim, SynthesizeUI):
|
|||||||
remain += 1
|
remain += 1
|
||||||
continue
|
continue
|
||||||
if self.appear(DISPATCHED):
|
if self.appear(DISPATCHED):
|
||||||
self.dispatched[assignment] = datetime.now() + Duration(
|
self.dispatched[assignment] = datetime.now() + \
|
||||||
OCR_ASSIGNMENT_TIME).ocr_single_line(self.device.image)
|
self._get_assignment_time()
|
||||||
if total == len(self.dispatched):
|
if total == len(self.dispatched):
|
||||||
return remain
|
return remain
|
||||||
continue
|
continue
|
||||||
@ -174,3 +181,27 @@ class Assignment(AssignmentClaim, SynthesizeUI):
|
|||||||
remain -= 1
|
remain -= 1
|
||||||
if remain <= 0:
|
if remain <= 0:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
def _dispatch_event(self, remain: int):
|
||||||
|
if remain <= 0:
|
||||||
|
return remain
|
||||||
|
logger.hr('Assignment dispatch event', level=1)
|
||||||
|
for group in self._iter_groups():
|
||||||
|
if not isinstance(group, AssignmentEventGroup):
|
||||||
|
continue
|
||||||
|
self.goto_group(group)
|
||||||
|
for assignment in self._iter_entries():
|
||||||
|
if assignment in self.dispatched:
|
||||||
|
continue
|
||||||
|
logger.hr('Assignment event', level=2)
|
||||||
|
logger.info(f'Check assignment event: {assignment}')
|
||||||
|
self.goto_entry(assignment)
|
||||||
|
if self.appear(LOCKED):
|
||||||
|
logger.info('Assignment is locked')
|
||||||
|
break
|
||||||
|
if self.appear(EMPTY_SLOT):
|
||||||
|
self.dispatch(assignment, None)
|
||||||
|
remain -= 1
|
||||||
|
if remain <= 0:
|
||||||
|
return remain
|
||||||
|
return remain
|
||||||
|
@ -41,7 +41,7 @@ class AssignmentClaim(AssignmentDispatch):
|
|||||||
"""
|
"""
|
||||||
Pages:
|
Pages:
|
||||||
in: CLAIM
|
in: CLAIM
|
||||||
out: REDISPATCH
|
out: REPORT
|
||||||
"""
|
"""
|
||||||
skip_first_screenshot = True
|
skip_first_screenshot = True
|
||||||
while 1:
|
while 1:
|
||||||
@ -50,7 +50,9 @@ class AssignmentClaim(AssignmentDispatch):
|
|||||||
else:
|
else:
|
||||||
self.device.screenshot()
|
self.device.screenshot()
|
||||||
# End
|
# End
|
||||||
if self.appear(REDISPATCH):
|
# Neither CLOSE_REPORT nor REDISPATCH is shown
|
||||||
|
# If it is an EVENT assignment
|
||||||
|
if self.appear(REPORT):
|
||||||
logger.info('Assignment report appears')
|
logger.info('Assignment report appears')
|
||||||
break
|
break
|
||||||
# Claim rewards
|
# Claim rewards
|
||||||
@ -63,7 +65,7 @@ class AssignmentClaim(AssignmentDispatch):
|
|||||||
should_redispatch (bool): determined by user config and duration in report
|
should_redispatch (bool): determined by user config and duration in report
|
||||||
|
|
||||||
Pages:
|
Pages:
|
||||||
in: CLOSE_REPORT and REDISPATCH
|
in: REPORT
|
||||||
out: page_assignment
|
out: page_assignment
|
||||||
"""
|
"""
|
||||||
click_button = REDISPATCH if should_redispatch else CLOSE_REPORT
|
click_button = REDISPATCH if should_redispatch else CLOSE_REPORT
|
||||||
@ -80,6 +82,9 @@ class AssignmentClaim(AssignmentDispatch):
|
|||||||
# Close report
|
# Close report
|
||||||
if self.appear_then_click(click_button, interval=2):
|
if self.appear_then_click(click_button, interval=2):
|
||||||
continue
|
continue
|
||||||
|
# Only for EVENT assignments
|
||||||
|
if self.appear_then_click(REPORT, interval=2):
|
||||||
|
continue
|
||||||
|
|
||||||
def _is_duration_expected(self, duration: int) -> bool:
|
def _is_duration_expected(self, duration: int) -> bool:
|
||||||
"""
|
"""
|
||||||
|
@ -47,21 +47,25 @@ class AssignmentDispatch(AssignmentUI):
|
|||||||
dispatched: dict[AssignmentEntry, datetime] = dict()
|
dispatched: dict[AssignmentEntry, datetime] = dict()
|
||||||
has_new_dispatch: bool = False
|
has_new_dispatch: bool = False
|
||||||
|
|
||||||
def dispatch(self, assignment: AssignmentEntry, duration: int):
|
def dispatch(self, assignment: AssignmentEntry, duration: int | None):
|
||||||
"""
|
"""
|
||||||
Dispatch assignment.
|
Dispatch assignment.
|
||||||
Should be called only when limit is checked
|
Should be called only when limit is checked
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
assignment (AssignmentEntry):
|
assignment (AssignmentEntry):
|
||||||
duration (int): user specified duration
|
duration (int | None): user specified duration, None for event assignments
|
||||||
|
|
||||||
Pages:
|
Pages:
|
||||||
in: EMPTY_SLOT
|
in: EMPTY_SLOT
|
||||||
out: DISPATCHED
|
out: DISPATCHED
|
||||||
"""
|
"""
|
||||||
self._select_characters()
|
self._select_characters()
|
||||||
self._select_duration(duration)
|
if isinstance(assignment, AssignmentEventEntry):
|
||||||
|
self._select_support()
|
||||||
|
duration = self._get_assignment_time().total_seconds() / 3600
|
||||||
|
else:
|
||||||
|
self._select_duration(duration)
|
||||||
self._confirm_assignment()
|
self._confirm_assignment()
|
||||||
self._wait_until_assignment_started()
|
self._wait_until_assignment_started()
|
||||||
future = now() + timedelta(hours=duration)
|
future = now() + timedelta(hours=duration)
|
||||||
@ -103,6 +107,30 @@ class AssignmentDispatch(AssignmentUI):
|
|||||||
if not self.image_color_count(CHARACTER_2_SELECTED, (240, 240, 240)):
|
if not self.image_color_count(CHARACTER_2_SELECTED, (240, 240, 240)):
|
||||||
self.device.click(CHARACTER_2)
|
self.device.click(CHARACTER_2)
|
||||||
|
|
||||||
|
def _select_support(self):
|
||||||
|
skip_first_screenshot = True
|
||||||
|
self.interval_clear(
|
||||||
|
(CHARACTER_SUPPORT_LIST, CHARACTER_SUPPORT_SELECTED), interval=2)
|
||||||
|
while 1:
|
||||||
|
if skip_first_screenshot:
|
||||||
|
skip_first_screenshot = False
|
||||||
|
else:
|
||||||
|
self.device.screenshot()
|
||||||
|
# End
|
||||||
|
if self.match_color(CHARACTER_SUPPORT_SELECTED):
|
||||||
|
logger.info('Support character is selected')
|
||||||
|
break
|
||||||
|
# Ensure support list
|
||||||
|
if not self.appear(CHARACTER_SUPPORT_LIST):
|
||||||
|
if self.interval_is_reached(CHARACTER_SUPPORT_LIST, interval=2):
|
||||||
|
self.interval_reset(CHARACTER_SUPPORT_LIST, interval=2)
|
||||||
|
self.device.click(EMPTY_SLOT_SUPPORT)
|
||||||
|
continue
|
||||||
|
# Select
|
||||||
|
if self.interval_is_reached(CHARACTER_SUPPORT_SELECTED, interval=2):
|
||||||
|
self.interval_reset(CHARACTER_SUPPORT_SELECTED, interval=2)
|
||||||
|
self.device.click(CHARACTER_SUPPORT)
|
||||||
|
|
||||||
def _select_duration(self, duration: int):
|
def _select_duration(self, duration: int):
|
||||||
if duration not in {4, 8, 12, 20}:
|
if duration not in {4, 8, 12, 20}:
|
||||||
logger.warning(
|
logger.warning(
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
import tasks.assignment.keywords.entry as KEYWORDS_ASSIGNMENT_ENTRY
|
import tasks.assignment.keywords.entry as KEYWORDS_ASSIGNMENT_ENTRY
|
||||||
import tasks.assignment.keywords.group as KEYWORDS_ASSIGNMENT_GROUP
|
import tasks.assignment.keywords.group as KEYWORDS_ASSIGNMENT_GROUP
|
||||||
from tasks.assignment.keywords.classes import AssignmentEntry, AssignmentGroup
|
import tasks.assignment.keywords.event_entry as KEYWORDS_ASSIGNMENT_EVENT_ENTRY
|
||||||
|
import tasks.assignment.keywords.event_group as KEYWORDS_ASSIGNMENT_EVENT_GROUP
|
||||||
|
from tasks.assignment.keywords.classes import *
|
||||||
|
|
||||||
KEYWORDS_ASSIGNMENT_GROUP.Character_Materials.entries = (
|
KEYWORDS_ASSIGNMENT_GROUP.Character_Materials.entries = (
|
||||||
KEYWORDS_ASSIGNMENT_ENTRY.Nine_Billion_Names,
|
KEYWORDS_ASSIGNMENT_ENTRY.Nine_Billion_Names,
|
||||||
@ -23,10 +25,37 @@ KEYWORDS_ASSIGNMENT_GROUP.Synthesis_Materials.entries = (
|
|||||||
KEYWORDS_ASSIGNMENT_ENTRY.Legend_of_the_Puppet_Master,
|
KEYWORDS_ASSIGNMENT_ENTRY.Legend_of_the_Puppet_Master,
|
||||||
KEYWORDS_ASSIGNMENT_ENTRY.The_Wages_of_Humanity,
|
KEYWORDS_ASSIGNMENT_ENTRY.The_Wages_of_Humanity,
|
||||||
)
|
)
|
||||||
|
KEYWORDS_ASSIGNMENT_EVENT_GROUP.Space_Station_Task_Force.entries = (
|
||||||
|
KEYWORDS_ASSIGNMENT_EVENT_ENTRY.Repulsion_Bridge_Errors,
|
||||||
|
KEYWORDS_ASSIGNMENT_EVENT_ENTRY.Meal_Delivery_Robot_Check_Up,
|
||||||
|
KEYWORDS_ASSIGNMENT_EVENT_ENTRY.Noise_Complaint,
|
||||||
|
KEYWORDS_ASSIGNMENT_EVENT_ENTRY.Interior_Temperature_Modulator,
|
||||||
|
KEYWORDS_ASSIGNMENT_EVENT_ENTRY.Researcher_Health_Reports,
|
||||||
|
KEYWORDS_ASSIGNMENT_EVENT_ENTRY.Confidential_Investigation,
|
||||||
|
KEYWORDS_ASSIGNMENT_EVENT_ENTRY.Borrowed_Equipment,
|
||||||
|
KEYWORDS_ASSIGNMENT_EVENT_ENTRY.Booking_System,
|
||||||
|
KEYWORDS_ASSIGNMENT_EVENT_ENTRY.Non_Digital_Documents,
|
||||||
|
KEYWORDS_ASSIGNMENT_EVENT_ENTRY.Drip_Feed_Errors,
|
||||||
|
KEYWORDS_ASSIGNMENT_EVENT_ENTRY.Pet_Movement_Route_Planning,
|
||||||
|
KEYWORDS_ASSIGNMENT_EVENT_ENTRY.Food_Improvement_Plan,
|
||||||
|
KEYWORDS_ASSIGNMENT_EVENT_ENTRY.Curio_Distribution,
|
||||||
|
KEYWORDS_ASSIGNMENT_EVENT_ENTRY.Super_Urgent_Waiting_Online,
|
||||||
|
KEYWORDS_ASSIGNMENT_EVENT_ENTRY.Ventilation_Problem,
|
||||||
|
KEYWORDS_ASSIGNMENT_EVENT_ENTRY.Unstable_Connection,
|
||||||
|
KEYWORDS_ASSIGNMENT_EVENT_ENTRY.Chronology_Checks,
|
||||||
|
KEYWORDS_ASSIGNMENT_EVENT_ENTRY.Supply_Chain_Management,
|
||||||
|
KEYWORDS_ASSIGNMENT_EVENT_ENTRY.Malicious_Occupation_of_Public_Space,
|
||||||
|
KEYWORDS_ASSIGNMENT_EVENT_ENTRY.Uniform_Material,
|
||||||
|
KEYWORDS_ASSIGNMENT_EVENT_ENTRY.Virus_Re_creation_Report,
|
||||||
|
KEYWORDS_ASSIGNMENT_EVENT_ENTRY.Abnormal_Signal,
|
||||||
|
KEYWORDS_ASSIGNMENT_EVENT_ENTRY.Flexible_Working_Approval,
|
||||||
|
KEYWORDS_ASSIGNMENT_EVENT_ENTRY.Lighting_Issue,
|
||||||
|
)
|
||||||
for group in (
|
for group in (
|
||||||
KEYWORDS_ASSIGNMENT_GROUP.Character_Materials,
|
KEYWORDS_ASSIGNMENT_GROUP.Character_Materials,
|
||||||
KEYWORDS_ASSIGNMENT_GROUP.EXP_Materials_Credits,
|
KEYWORDS_ASSIGNMENT_GROUP.EXP_Materials_Credits,
|
||||||
KEYWORDS_ASSIGNMENT_GROUP.Synthesis_Materials,
|
KEYWORDS_ASSIGNMENT_GROUP.Synthesis_Materials,
|
||||||
|
KEYWORDS_ASSIGNMENT_EVENT_GROUP.Space_Station_Task_Force,
|
||||||
):
|
):
|
||||||
for entry in group.entries:
|
for entry in group.entries:
|
||||||
assert entry.group is None
|
assert entry.group is None
|
||||||
|
@ -15,6 +15,19 @@ class AssignmentGroup(Keyword):
|
|||||||
class AssignmentEntry(Keyword):
|
class AssignmentEntry(Keyword):
|
||||||
instances: ClassVar = {}
|
instances: ClassVar = {}
|
||||||
group: AssignmentGroup = None
|
group: AssignmentGroup = None
|
||||||
|
|
||||||
def __hash__(self) -> int:
|
def __hash__(self) -> int:
|
||||||
return super().__hash__()
|
return super().__hash__()
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(repr=False)
|
||||||
|
class AssignmentEventGroup(AssignmentGroup):
|
||||||
|
instances: ClassVar = {}
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(repr=False)
|
||||||
|
class AssignmentEventEntry(AssignmentEntry):
|
||||||
|
instances: ClassVar = {}
|
||||||
|
|
||||||
|
def __hash__(self) -> int:
|
||||||
|
return super().__hash__()
|
||||||
|
197
tasks/assignment/keywords/event_entry.py
Normal file
@ -0,0 +1,197 @@
|
|||||||
|
from .classes import AssignmentEventEntry
|
||||||
|
|
||||||
|
# This file was auto-generated, do not modify it manually. To generate:
|
||||||
|
# ``` python -m dev_tools.keyword_extract ```
|
||||||
|
|
||||||
|
Repulsion_Bridge_Errors = AssignmentEventEntry(
|
||||||
|
id=1,
|
||||||
|
name='Repulsion_Bridge_Errors',
|
||||||
|
cn='斥力桥报错',
|
||||||
|
cht='斥力橋錯誤',
|
||||||
|
en='Repulsion Bridge Errors',
|
||||||
|
jp='斥力ブリッジエラー',
|
||||||
|
)
|
||||||
|
Meal_Delivery_Robot_Check_Up = AssignmentEventEntry(
|
||||||
|
id=2,
|
||||||
|
name='Meal_Delivery_Robot_Check_Up',
|
||||||
|
cn='送餐机器人检修',
|
||||||
|
cht='送餐機器人檢修',
|
||||||
|
en='Meal-Delivery Robot Check-Up',
|
||||||
|
jp='配膳ロボット点検修理',
|
||||||
|
)
|
||||||
|
Noise_Complaint = AssignmentEventEntry(
|
||||||
|
id=3,
|
||||||
|
name='Noise_Complaint',
|
||||||
|
cn='噪音投诉问题',
|
||||||
|
cht='噪音投訴問題',
|
||||||
|
en='Noise Complaint',
|
||||||
|
jp='騒音苦情問題',
|
||||||
|
)
|
||||||
|
Interior_Temperature_Modulator = AssignmentEventEntry(
|
||||||
|
id=4,
|
||||||
|
name='Interior_Temperature_Modulator',
|
||||||
|
cn='室内温度调节器',
|
||||||
|
cht='室內溫度調節器',
|
||||||
|
en='Interior Temperature Modulator',
|
||||||
|
jp='室内温度調節器',
|
||||||
|
)
|
||||||
|
Researcher_Health_Reports = AssignmentEventEntry(
|
||||||
|
id=5,
|
||||||
|
name='Researcher_Health_Reports',
|
||||||
|
cn='科员的体检报告',
|
||||||
|
cht='組員的體檢報告',
|
||||||
|
en="Researchers' Health Reports",
|
||||||
|
jp='スタッフの健康診断報告',
|
||||||
|
)
|
||||||
|
Confidential_Investigation = AssignmentEventEntry(
|
||||||
|
id=6,
|
||||||
|
name='Confidential_Investigation',
|
||||||
|
cn='秘密调查行动',
|
||||||
|
cht='秘密調查行動',
|
||||||
|
en='Confidential Investigation',
|
||||||
|
jp='秘密裏の調査',
|
||||||
|
)
|
||||||
|
Borrowed_Equipment = AssignmentEventEntry(
|
||||||
|
id=7,
|
||||||
|
name='Borrowed_Equipment',
|
||||||
|
cn='实验器械借用',
|
||||||
|
cht='實驗器械借用',
|
||||||
|
en='Borrowed Equipment',
|
||||||
|
jp='実験機器借用',
|
||||||
|
)
|
||||||
|
Booking_System = AssignmentEventEntry(
|
||||||
|
id=8,
|
||||||
|
name='Booking_System',
|
||||||
|
cn='会议室预约系统',
|
||||||
|
cht='會議室預約系統',
|
||||||
|
en='Booking System',
|
||||||
|
jp='会議室予約システム',
|
||||||
|
)
|
||||||
|
Non_Digital_Documents = AssignmentEventEntry(
|
||||||
|
id=9,
|
||||||
|
name='Non_Digital_Documents',
|
||||||
|
cn='非电子版文件',
|
||||||
|
cht='非電子版文件',
|
||||||
|
en='Non-Digital Documents',
|
||||||
|
jp='非デジタル版ファイル',
|
||||||
|
)
|
||||||
|
Drip_Feed_Errors = AssignmentEventEntry(
|
||||||
|
id=10,
|
||||||
|
name='Drip_Feed_Errors',
|
||||||
|
cn='液滴系统报错',
|
||||||
|
cht='液滴系統錯誤',
|
||||||
|
en='Drip-Feed Errors',
|
||||||
|
jp='水やりシステムエラー',
|
||||||
|
)
|
||||||
|
Pet_Movement_Route_Planning = AssignmentEventEntry(
|
||||||
|
id=11,
|
||||||
|
name='Pet_Movement_Route_Planning',
|
||||||
|
cn='宠物行动路线规划',
|
||||||
|
cht='寵物行動路線規劃',
|
||||||
|
en='Pet Movement Route Planning',
|
||||||
|
jp='ペットの行動ルート規制',
|
||||||
|
)
|
||||||
|
Food_Improvement_Plan = AssignmentEventEntry(
|
||||||
|
id=12,
|
||||||
|
name='Food_Improvement_Plan',
|
||||||
|
cn='餐饮优化方案',
|
||||||
|
cht='餐飲改良方案',
|
||||||
|
en='Food Improvement Plan',
|
||||||
|
jp='飲食優良化法案',
|
||||||
|
)
|
||||||
|
Curio_Distribution = AssignmentEventEntry(
|
||||||
|
id=13,
|
||||||
|
name='Curio_Distribution',
|
||||||
|
cn='奇物借用问题',
|
||||||
|
cht='奇物借用問題',
|
||||||
|
en='Curio Distribution',
|
||||||
|
jp='奇物借用問題',
|
||||||
|
)
|
||||||
|
Super_Urgent_Waiting_Online = AssignmentEventEntry(
|
||||||
|
id=14,
|
||||||
|
name='Super_Urgent_Waiting_Online',
|
||||||
|
cn='来活人很急在线等',
|
||||||
|
cht='急,線上等',
|
||||||
|
en='Super Urgent, Waiting Online',
|
||||||
|
jp='緊急助っ人求むオンラインにて待つ',
|
||||||
|
)
|
||||||
|
Ventilation_Problem = AssignmentEventEntry(
|
||||||
|
id=15,
|
||||||
|
name='Ventilation_Problem',
|
||||||
|
cn='空气流通问题',
|
||||||
|
cht='空氣流通問題',
|
||||||
|
en='Ventilation Problem',
|
||||||
|
jp='換気問題',
|
||||||
|
)
|
||||||
|
Unstable_Connection = AssignmentEventEntry(
|
||||||
|
id=16,
|
||||||
|
name='Unstable_Connection',
|
||||||
|
cn='连接不稳定问题',
|
||||||
|
cht='連線不穩定問題',
|
||||||
|
en='Unstable Connection',
|
||||||
|
jp='接続不安定問題',
|
||||||
|
)
|
||||||
|
Chronology_Checks = AssignmentEventEntry(
|
||||||
|
id=17,
|
||||||
|
name='Chronology_Checks',
|
||||||
|
cn='编年史校对',
|
||||||
|
cht='編年史校對',
|
||||||
|
en='Chronology Checks',
|
||||||
|
jp='編年史校正',
|
||||||
|
)
|
||||||
|
Supply_Chain_Management = AssignmentEventEntry(
|
||||||
|
id=18,
|
||||||
|
name='Supply_Chain_Management',
|
||||||
|
cn='物流供应链管理',
|
||||||
|
cht='物流供應鏈管理',
|
||||||
|
en='Supply Chain Management',
|
||||||
|
jp='物流供給路線管理',
|
||||||
|
)
|
||||||
|
Malicious_Occupation_of_Public_Space = AssignmentEventEntry(
|
||||||
|
id=19,
|
||||||
|
name='Malicious_Occupation_of_Public_Space',
|
||||||
|
cn='公共区域被恶意侵占',
|
||||||
|
cht='公共區域被惡意侵佔',
|
||||||
|
en='Malicious Occupation of Public Space',
|
||||||
|
jp='公共区域の悪意による独占',
|
||||||
|
)
|
||||||
|
Uniform_Material = AssignmentEventEntry(
|
||||||
|
id=20,
|
||||||
|
name='Uniform_Material',
|
||||||
|
cn='科室服装面料',
|
||||||
|
cht='科室服裝材質',
|
||||||
|
en='Uniform Material',
|
||||||
|
jp='スタッフ制服の素材',
|
||||||
|
)
|
||||||
|
Virus_Re_creation_Report = AssignmentEventEntry(
|
||||||
|
id=21,
|
||||||
|
name='Virus_Re_creation_Report',
|
||||||
|
cn='病毒溯源报告',
|
||||||
|
cht='病毒溯源報告',
|
||||||
|
en='Virus Re-creation Report',
|
||||||
|
jp='ウイルス根源報告',
|
||||||
|
)
|
||||||
|
Abnormal_Signal = AssignmentEventEntry(
|
||||||
|
id=22,
|
||||||
|
name='Abnormal_Signal',
|
||||||
|
cn='舱段信号异常',
|
||||||
|
cht='艙段訊號異常',
|
||||||
|
en='Abnormal Signal',
|
||||||
|
jp='部分の信号異常',
|
||||||
|
)
|
||||||
|
Flexible_Working_Approval = AssignmentEventEntry(
|
||||||
|
id=23,
|
||||||
|
name='Flexible_Working_Approval',
|
||||||
|
cn='轮休审批流程',
|
||||||
|
cht='輪休審批流程',
|
||||||
|
en='Flexible Working Approval',
|
||||||
|
jp='交代休み審査フロー',
|
||||||
|
)
|
||||||
|
Lighting_Issue = AssignmentEventEntry(
|
||||||
|
id=24,
|
||||||
|
name='Lighting_Issue',
|
||||||
|
cn='灯光照明问题',
|
||||||
|
cht='燈光照明問題',
|
||||||
|
en='Lighting Issue',
|
||||||
|
jp='照明の色問題',
|
||||||
|
)
|
13
tasks/assignment/keywords/event_group.py
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
from .classes import AssignmentEventGroup
|
||||||
|
|
||||||
|
# This file was auto-generated, do not modify it manually. To generate:
|
||||||
|
# ``` python -m dev_tools.keyword_extract ```
|
||||||
|
|
||||||
|
Space_Station_Task_Force = AssignmentEventGroup(
|
||||||
|
id=1,
|
||||||
|
name='Space_Station_Task_Force',
|
||||||
|
cn='空间站特派',
|
||||||
|
cht='太空站特派',
|
||||||
|
en='Space Station Task Force',
|
||||||
|
jp='ステーション特派',
|
||||||
|
)
|
@ -1,6 +1,7 @@
|
|||||||
import re
|
import re
|
||||||
|
from collections.abc import Iterator
|
||||||
|
from datetime import timedelta
|
||||||
from functools import cached_property
|
from functools import cached_property
|
||||||
from typing import Iterator
|
|
||||||
|
|
||||||
from module.base.timer import Timer
|
from module.base.timer import Timer
|
||||||
from module.exception import ScriptError
|
from module.exception import ScriptError
|
||||||
@ -26,6 +27,14 @@ class AssignmentOcr(Ocr):
|
|||||||
(KEYWORDS_ASSIGNMENT_ENTRY.Akashic_Records.name, '阿[未][夏复]记录'),
|
(KEYWORDS_ASSIGNMENT_ENTRY.Akashic_Records.name, '阿[未][夏复]记录'),
|
||||||
(KEYWORDS_ASSIGNMENT_ENTRY.Legend_of_the_Puppet_Master.name, '^师传说'),
|
(KEYWORDS_ASSIGNMENT_ENTRY.Legend_of_the_Puppet_Master.name, '^师传说'),
|
||||||
(KEYWORDS_ASSIGNMENT_ENTRY.The_Wages_of_Humanity.name, '[赠]养人类'),
|
(KEYWORDS_ASSIGNMENT_ENTRY.The_Wages_of_Humanity.name, '[赠]养人类'),
|
||||||
|
(KEYWORDS_ASSIGNMENT_EVENT_GROUP.Space_Station_Task_Force.name,
|
||||||
|
'[新0]空间站特派[新]'),
|
||||||
|
],
|
||||||
|
'en': [
|
||||||
|
(KEYWORDS_ASSIGNMENT_EVENT_ENTRY.Food_Improvement_Plan.name,
|
||||||
|
'Food\s*[I]{0}mprovement Plan'),
|
||||||
|
(KEYWORDS_ASSIGNMENT_EVENT_GROUP.Space_Station_Task_Force.name,
|
||||||
|
'^(S[np]ace Station Ta[^sk]{0,3})?[F-]orce')
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -39,7 +48,15 @@ class AssignmentOcr(Ocr):
|
|||||||
def filter_detected(self, result) -> bool:
|
def filter_detected(self, result) -> bool:
|
||||||
# Drop duration rows
|
# Drop duration rows
|
||||||
res = Duration.timedelta_regex(self.lang).search(result.ocr_text)
|
res = Duration.timedelta_regex(self.lang).search(result.ocr_text)
|
||||||
return not bool(res.group('seconds'))
|
if res.group('hours') or res.group('seconds'):
|
||||||
|
return False
|
||||||
|
# Locked event assignments
|
||||||
|
locked_pattern = {
|
||||||
|
'cn': '解锁$',
|
||||||
|
'en': 'Locked$',
|
||||||
|
}[self.lang]
|
||||||
|
res = re.search(locked_pattern, result.ocr_text)
|
||||||
|
return not res
|
||||||
|
|
||||||
def after_process(self, result: str):
|
def after_process(self, result: str):
|
||||||
result = super().after_process(result)
|
result = super().after_process(result)
|
||||||
@ -50,7 +67,17 @@ class AssignmentOcr(Ocr):
|
|||||||
if matched is None:
|
if matched is None:
|
||||||
return result
|
return result
|
||||||
keyword_lang = self.lang
|
keyword_lang = self.lang
|
||||||
matched = getattr(KEYWORDS_ASSIGNMENT_ENTRY, matched.lastgroup)
|
for keyword_class in (
|
||||||
|
KEYWORDS_ASSIGNMENT_ENTRY, KEYWORDS_ASSIGNMENT_EVENT_ENTRY,
|
||||||
|
KEYWORDS_ASSIGNMENT_GROUP, KEYWORDS_ASSIGNMENT_EVENT_GROUP,
|
||||||
|
):
|
||||||
|
try:
|
||||||
|
matched = getattr(keyword_class, matched.lastgroup)
|
||||||
|
break
|
||||||
|
except AttributeError:
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
raise ScriptError(f'No keyword found for {matched.lastgroup}')
|
||||||
matched = getattr(matched, keyword_lang)
|
matched = getattr(matched, keyword_lang)
|
||||||
logger.attr(name=f'{self.name} after_process',
|
logger.attr(name=f'{self.name} after_process',
|
||||||
text=f'{result} -> {matched}')
|
text=f'{result} -> {matched}')
|
||||||
@ -59,15 +86,16 @@ class AssignmentOcr(Ocr):
|
|||||||
|
|
||||||
ASSIGNMENT_GROUP_LIST = DraggableList(
|
ASSIGNMENT_GROUP_LIST = DraggableList(
|
||||||
'AssignmentGroupList',
|
'AssignmentGroupList',
|
||||||
keyword_class=AssignmentGroup,
|
keyword_class=[AssignmentGroup, AssignmentEventGroup],
|
||||||
ocr_class=Ocr,
|
ocr_class=AssignmentOcr,
|
||||||
search_button=OCR_ASSIGNMENT_GROUP_LIST,
|
search_button=OCR_ASSIGNMENT_GROUP_LIST,
|
||||||
|
check_row_order=False,
|
||||||
active_color=(240, 240, 240),
|
active_color=(240, 240, 240),
|
||||||
drag_direction='right'
|
drag_direction='right'
|
||||||
)
|
)
|
||||||
ASSIGNMENT_ENTRY_LIST = DraggableList(
|
ASSIGNMENT_ENTRY_LIST = DraggableList(
|
||||||
'AssignmentEntryList',
|
'AssignmentEntryList',
|
||||||
keyword_class=AssignmentEntry,
|
keyword_class=[AssignmentEntry, AssignmentEventEntry],
|
||||||
ocr_class=AssignmentOcr,
|
ocr_class=AssignmentOcr,
|
||||||
search_button=OCR_ASSIGNMENT_ENTRY_LIST,
|
search_button=OCR_ASSIGNMENT_ENTRY_LIST,
|
||||||
check_row_order=False,
|
check_row_order=False,
|
||||||
@ -86,7 +114,11 @@ class AssignmentUI(UI):
|
|||||||
self.device.screenshot()
|
self.device.screenshot()
|
||||||
self.goto_group(KEYWORDS_ASSIGNMENT_GROUP.Character_Materials)
|
self.goto_group(KEYWORDS_ASSIGNMENT_GROUP.Character_Materials)
|
||||||
"""
|
"""
|
||||||
|
selected = ASSIGNMENT_GROUP_LIST.get_selected_row(self)
|
||||||
|
if selected and selected.matched_keyword == group:
|
||||||
|
return
|
||||||
logger.hr('Assignment group goto', level=3)
|
logger.hr('Assignment group goto', level=3)
|
||||||
|
self._wait_until_group_loaded()
|
||||||
if ASSIGNMENT_GROUP_LIST.select_row(group, self):
|
if ASSIGNMENT_GROUP_LIST.select_row(group, self):
|
||||||
self._wait_until_entry_loaded()
|
self._wait_until_entry_loaded()
|
||||||
|
|
||||||
@ -112,6 +144,23 @@ class AssignmentUI(UI):
|
|||||||
self.goto_group(entry.group)
|
self.goto_group(entry.group)
|
||||||
ASSIGNMENT_ENTRY_LIST.select_row(entry, self)
|
ASSIGNMENT_ENTRY_LIST.select_row(entry, self)
|
||||||
|
|
||||||
|
def _wait_until_group_loaded(self):
|
||||||
|
skip_first_screenshot = True
|
||||||
|
timeout = Timer(2, count=3).start()
|
||||||
|
while 1:
|
||||||
|
if skip_first_screenshot:
|
||||||
|
skip_first_screenshot = False
|
||||||
|
else:
|
||||||
|
self.device.screenshot()
|
||||||
|
|
||||||
|
if timeout.reached():
|
||||||
|
logger.warning('Wait group loaded timeout')
|
||||||
|
break
|
||||||
|
if self.image_color_count(OCR_ASSIGNMENT_GROUP_LIST, (40, 40, 40), count=20000) and \
|
||||||
|
self.image_color_count(OCR_ASSIGNMENT_GROUP_LIST, (240, 240, 240), count=7000):
|
||||||
|
logger.info('Group loaded')
|
||||||
|
break
|
||||||
|
|
||||||
def _wait_until_entry_loaded(self):
|
def _wait_until_entry_loaded(self):
|
||||||
skip_first_screenshot = True
|
skip_first_screenshot = True
|
||||||
timeout = Timer(2, count=3).start()
|
timeout = Timer(2, count=3).start()
|
||||||
@ -142,8 +191,13 @@ class AssignmentUI(UI):
|
|||||||
self.config.stored.Assignment.set(0, 0)
|
self.config.stored.Assignment.set(0, 0)
|
||||||
return current, remain, total
|
return current, remain, total
|
||||||
|
|
||||||
|
def _get_assignment_time(self) -> timedelta:
|
||||||
|
return Duration(OCR_ASSIGNMENT_TIME).ocr_single_line(self.device.image)
|
||||||
|
|
||||||
def _iter_groups(self) -> Iterator[AssignmentGroup]:
|
def _iter_groups(self) -> Iterator[AssignmentGroup]:
|
||||||
ASSIGNMENT_GROUP_LIST.load_rows(main=self)
|
self._wait_until_group_loaded()
|
||||||
|
ASSIGNMENT_GROUP_LIST.insight_row(
|
||||||
|
KEYWORDS_ASSIGNMENT_GROUP.Character_Materials, self)
|
||||||
for button in ASSIGNMENT_GROUP_LIST.cur_buttons:
|
for button in ASSIGNMENT_GROUP_LIST.cur_buttons:
|
||||||
yield button.matched_keyword
|
yield button.matched_keyword
|
||||||
|
|
||||||
@ -152,5 +206,8 @@ class AssignmentUI(UI):
|
|||||||
Iterate entries from top to bottom
|
Iterate entries from top to bottom
|
||||||
"""
|
"""
|
||||||
ASSIGNMENT_ENTRY_LIST.load_rows(main=self)
|
ASSIGNMENT_ENTRY_LIST.load_rows(main=self)
|
||||||
for button in ASSIGNMENT_ENTRY_LIST.cur_buttons:
|
# Freeze ocr results here
|
||||||
yield button.matched_keyword
|
yield from [
|
||||||
|
button.matched_keyword
|
||||||
|
for button in ASSIGNMENT_ENTRY_LIST.cur_buttons
|
||||||
|
]
|
||||||
|