feat(task): 新增支持指定回忆编成编号

This commit is contained in:
XcantloadX 2025-02-28 23:19:21 +08:00
parent f146038d36
commit 64829624bb
6 changed files with 116 additions and 15 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 955 KiB

View File

@ -0,0 +1 @@
{"definitions":{"7e3e3a94-e05c-477e-bd92-0afc172bdb94":{"name":"Produce.BoxSetCountIndicator","displayName":"培育开始页面 当前编成编号","type":"hint-box","annotationId":"7e3e3a94-e05c-477e-bd92-0afc172bdb94","useHintRect":false},"389bdefb-4b76-4ac3-9460-d59c144f8de7":{"name":"Produce.PointProduceNextSet","displayName":"培育开始页面 下一个编成","type":"hint-point","annotationId":"389bdefb-4b76-4ac3-9460-d59c144f8de7","useHintRect":false},"745d904e-19eb-4e15-b734-ef116e6e7c48":{"name":"Produce.PointProducePrevSet","displayName":"培育开始页面 上一个编成","type":"hint-point","annotationId":"745d904e-19eb-4e15-b734-ef116e6e7c48","useHintRect":false}},"annotations":[{"id":"7e3e3a94-e05c-477e-bd92-0afc172bdb94","type":"rect","data":{"x1":17,"y1":671,"x2":119,"y2":707}},{"id":"389bdefb-4b76-4ac3-9460-d59c144f8de7","type":"point","data":{"x":702,"y":832}},{"id":"745d904e-19eb-4e15-b734-ef116e6e7c48","type":"point","data":{"x":14,"y":832}}]}

View File

@ -320,7 +320,6 @@ class ProduceConfig(ConfigBaseModel):
memory_sets: list[int] = []
"""要使用的回忆编成编号,从 1 开始。将会按顺序循环选择使用。"""
support_card_sets: list[int] = []
"""要使用的支援卡编成编号,从 1 开始。将会按顺序循环选择使用。"""
auto_set_memory: bool = False
"""是否自动编成回忆。此选项优先级高于回忆编成编号。"""

View File

@ -185,6 +185,7 @@ class CommuEventButtonUI:
img = device.screenshot()
rects = filter_rectangles(img, (WHITE_LOW, WHITE_HIGH), 3, 1000, rect=self.rect)
rects.sort(key=lambda x: x[1])
# TODO: 这里 rects 可能为空,需要加入判断重试
ocr_result = ocr.raw().ocr(img, rect=rects[0])
return ocr_result.squash().text

View File

@ -99,6 +99,56 @@ def select_idol(target_titles: list[str] | PIdol):
device.click(image.expect(R.Common.ButtonConfirmNoIcon))
return found
@action('培育开始.编成翻页', screenshot_mode='manual-inherit')
def select_set(index: int):
"""
选择指定编号的支援卡/回忆编成
前置条件STEP 2/3 页面
结束状态STEP 2/3 页面
:param index: 支援卡/回忆编成的编号 1 开始
"""
def _current():
numbers = []
while not numbers:
device.screenshot()
numbers = ocr.ocr(rect=R.Produce.BoxSetCountIndicator).squash().numbers()
if not numbers:
logger.warning('Failed to get current set number. Retrying...')
sleep(0.2)
return numbers[0]
max_retries = 3
retry_count = 0
while retry_count < max_retries:
current = _current()
logger.info(f'Navigate to set #{index}. Now at set #{current}.')
# 计算需要点击的次数
click_count = abs(index - current)
if click_count == 0:
logger.info(f'Already at set #{current}.')
return
click_target = R.Produce.PointProduceNextSet if current < index else R.Produce.PointProducePrevSet
# 点击
for _ in range(click_count):
device.click(click_target)
sleep(0.1)
# 确认
final_current = _current()
if final_current == index:
logger.info(f'Arrived at set #{final_current}.')
return
else:
retry_count += 1
logger.warning(f'Failed to navigate to set #{index}. Current set is #{final_current}. Retrying... ({retry_count}/{max_retries})')
logger.error(f'Failed to navigate to set #{index} after {max_retries} retries.')
@action('继续当前培育')
def resume_produce():
"""
@ -119,7 +169,11 @@ def resume_produce():
resume_regular_produce()
@action('执行培育', screenshot_mode='manual-inherit')
def do_produce(idol: PIdol, mode: Literal['regular', 'pro']) -> bool:
def do_produce(
idol: PIdol,
mode: Literal['regular', 'pro'],
memory_set_index: Optional[int] = None
) -> bool:
"""
进行培育流程
@ -171,24 +225,32 @@ def do_produce(idol: PIdol, mode: Literal['regular', 'pro']) -> bool:
it.wait()
# 3. 选择回忆 自动编成 [screenshots/produce/select_memory.png]
ocr.expect_wait(contains('メモリー'), rect=R.Produce.BoxStepIndicator)
device.click(image.expect_wait(R.Produce.ButtonAutoSet))
wait(0.5, before='screenshot')
device.screenshot()
# 自动编成
if memory_set_index is not None and not 1 <= memory_set_index <= 10:
raise ValueError('`memory_set_index` must be in range [1, 10].')
if memory_set_index is None:
device.click(image.expect_wait(R.Produce.ButtonAutoSet))
wait(0.5, before='screenshot')
device.screenshot()
# 指定编号
else:
select_set(memory_set_index)
(SimpleDispatcher('do_produce.step_3')
.click(R.Common.ButtonNextNoIcon)
.click(R.Common.ButtonConfirm)
.until(contains('開始確認'), rect=R.Produce.BoxStepIndicator)
).run()
# 4. 选择道具 [screenshots/produce/select_end.png]
# TODO: 如果道具不足,这里加入推送提醒
if conf().produce.use_note_boost:
if image.find(R.Produce.CheckboxIconNoteBoost):
device.click()
sleep(0.2)
sleep(0.1)
if conf().produce.use_pt_boost:
if image.find(R.Produce.CheckboxIconSupportPtBoost):
device.click()
sleep(0.2)
sleep(0.1)
device.click(image.expect_wait(R.Produce.ButtonProduceStart))
# 5. 相关设置弹窗 [screenshots/produce/skip_commu.png]
cd = Countdown(5).start()
@ -206,9 +268,10 @@ def do_produce(idol: PIdol, mode: Literal['regular', 'pro']) -> bool:
@task('培育')
def produce_task(
mode: Literal['regular', 'pro'] | None = None,
mode: Optional[Literal['regular', 'pro']] = None,
count: Optional[int] = None,
idols: Optional[list[PIdol]] = None
idols: Optional[list[PIdol]] = None,
memory_sets: Optional[list[int]] = None
):
"""
培育任务
@ -225,6 +288,8 @@ def produce_task(
count = conf().produce.produce_count
if idols is None:
idols = conf().produce.idols
if memory_sets is None:
memory_sets = conf().produce.memory_sets
if mode is None:
mode = conf().produce.mode
# 数据验证
@ -233,9 +298,19 @@ def produce_task(
return
idol_iterator = cycle(idols)
memory_set_iterator = cycle(memory_sets)
for i in range(count):
start_time = time.time()
if not do_produce(next(idol_iterator), mode):
idol = next(idol_iterator)
if conf().produce.auto_set_memory:
memory_set = None
else:
memory_set = next(memory_set_iterator, None)
logger.info(
f'Produce start with: '
f'idol: {idol.value}, mode: {mode}, memory_set: #{memory_set}'
)
if not do_produce(idol, mode, memory_set):
user.info('AP 不足', f'由于 AP 不足,跳过了 {count - i} 次培育。')
logger.info('%d produce(s) skipped because of insufficient AP.', count - i)
break
@ -261,7 +336,14 @@ if __name__ == '__main__':
init_context(config_type=BaseConfig)
conf().produce.enabled = True
conf().produce.mode = 'pro'
# conf().produce.idols = [PIdol.花海佑芽_学園生活]
conf().produce.produce_count = 1
conf().produce.idols = [PIdol.月村手毬_アイヴイ]
conf().produce.memory_sets = [5]
conf().produce.auto_set_memory = False
# do_produce(PIdol.月村手毬_初声, 'pro', 5)
produce_task()
# a()
# select_idol(PIdol.藤田ことね_学園生活)
# select_idol(PIdol.藤田ことね_学園生活)
# select_set(10)
# manual_context().begin()
# print(ocr.ocr(rect=R.Produce.BoxSetCountIndicator).squash().numbers())

View File

@ -242,6 +242,7 @@ class KotoneBotUI:
produce_mode: Literal["regular"],
produce_count: int,
produce_idols: List[str],
memory_sets: List[str],
auto_set_memory: bool,
auto_set_support: bool,
use_pt_boost: bool,
@ -294,6 +295,7 @@ class KotoneBotUI:
mode=produce_mode,
produce_count=produce_count,
idols=[PIdol[idol] for idol in produce_idols],
memory_sets=[int(i) for i in memory_sets],
auto_set_memory=auto_set_memory,
auto_set_support_card=auto_set_support,
use_pt_boost=use_pt_boost,
@ -323,7 +325,7 @@ class KotoneBotUI:
with gr.Row():
run_btn = gr.Button("启动", scale=1)
debug_btn = gr.Button("调试", scale=1)
gr.Markdown("脚本报错或者卡住?点击“日志”选项卡中的“一键导出报告”可以快速反馈!")
gr.Markdown('脚本报错或者卡住?点击"日志"选项卡中的"一键导出报告"可以快速反馈!')
task_status = gr.Dataframe(
headers=["任务", "状态"],
@ -493,7 +495,7 @@ class KotoneBotUI:
)
return assignment_enabled, mini_live_reassign, mini_live_duration, online_live_reassign, online_live_duration
def _create_produce_settings(self) -> Tuple[gr.Checkbox, gr.Dropdown, gr.Number, gr.Dropdown, gr.Checkbox, gr.Checkbox, gr.Checkbox, gr.Checkbox, gr.Checkbox]:
def _create_produce_settings(self) -> Tuple[gr.Checkbox, gr.Dropdown, gr.Number, gr.Dropdown, gr.Dropdown, gr.Checkbox, gr.Checkbox, gr.Checkbox, gr.Checkbox, gr.Checkbox]:
with gr.Column():
gr.Markdown("### 培育设置")
produce_enabled = gr.Checkbox(
@ -531,6 +533,16 @@ class KotoneBotUI:
value=self.current_config.options.produce.auto_set_memory,
info=ProduceConfig.model_fields['auto_set_memory'].description
)
# 添加回忆编成选择
with gr.Group(visible=not self.current_config.options.produce.auto_set_memory) as memory_sets_group:
memory_sets = gr.Dropdown(
choices=[str(i) for i in range(1, 11)], # 假设最多10个编成位
value=[str(i) for i in self.current_config.options.produce.memory_sets],
label="回忆编成编号",
multiselect=True,
interactive=True,
info=ProduceConfig.model_fields['memory_sets'].description
)
auto_set_support = gr.Checkbox(
label="自动编成支援卡",
value=self.current_config.options.produce.auto_set_support_card,
@ -557,7 +569,13 @@ class KotoneBotUI:
inputs=[produce_enabled],
outputs=[produce_group]
)
return produce_enabled, produce_mode, produce_count, produce_idols, auto_set_memory, auto_set_support, use_pt_boost, use_note_boost, follow_producer
auto_set_memory.change(
fn=lambda x: gr.Group(visible=not x),
inputs=[auto_set_memory],
outputs=[memory_sets_group]
)
return produce_enabled, produce_mode, produce_count, produce_idols, memory_sets, auto_set_memory, auto_set_support, use_pt_boost, use_note_boost, follow_producer
def _create_settings_tab(self) -> None:
with gr.Tab("设置"):