feat(task): 培育支持处理 AP 不足的情况

This commit is contained in:
XcantloadX 2025-02-13 20:47:36 +08:00
parent 1a8346d0e3
commit c0100ce69e
6 changed files with 35 additions and 18 deletions

View File

@ -203,16 +203,19 @@ class UntilText:
sd: 'SimpleDispatcher',
text: str | StringMatchFunction,
*,
rect: Rect | None = None
rect: Rect | None = None,
result: Any | None = None
):
self.text = text
self.sd = sd
self.rect = rect
self.result = result
def __call__(self):
from kotonebot import ocr
if ocr.find(self.text, rect=self.rect):
self.sd.finished = True
self.sd.result = self.result
class UntilImage:
def __init__(
@ -220,11 +223,13 @@ class UntilImage:
sd: 'SimpleDispatcher',
image: Image,
*,
rect: Rect | None = None
rect: Rect | None = None,
result: Any | None = None
):
self.image = image
self.sd = sd
self.rect = rect
self.result = result
def __call__(self):
from kotonebot import image
@ -232,6 +237,7 @@ class UntilImage:
logger.warning(f'UntilImage with rect is deprecated. Use UntilText instead.')
if image.find(self.image):
self.sd.finished = True
self.sd.result = self.result
class SimpleDispatcher:
def __init__(self, name: str, *, interval: float = 0.2):
@ -239,6 +245,7 @@ class SimpleDispatcher:
self.logger = logging.getLogger(f'SimpleDispatcher of {name}')
self.blocks: list[Callable] = []
self.finished: bool = False
self.result: Any | None = None
self.interval = interval
self.__last_run_time: float = 0
@ -277,17 +284,19 @@ class SimpleDispatcher:
self,
text: StringMatchFunction | Image,
*,
rect: Rect | None = None
rect: Rect | None = None,
result: Any | None = None
):
if isinstance(text, Image):
self.blocks.append(UntilImage(self, text, rect=rect))
self.blocks.append(UntilImage(self, text, rect=rect, result=result))
else:
self.blocks.append(UntilText(self, text, rect=rect))
self.blocks.append(UntilText(self, text, rect=rect, result=result))
return self
def run(self):
from kotonebot import device, sleep
while True:
logger.debug(f'Running dispatcher "{self.name}"')
time_delta = time.time() - self.__last_run_time
if time_delta < self.interval:
sleep(self.interval - time_delta)
@ -297,6 +306,7 @@ class SimpleDispatcher:
break
self.__last_run_time = time.time()
device.screenshot()
return self.result
if __name__ == '__main__':
from .context.task_action import action

View File

@ -115,7 +115,7 @@ def resume_produce():
device.click(image.expect_wait(R.Produce.ButtonResume))
@action('执行培育', screenshot_mode='manual-inherit')
def do_produce(idol: PIdol, mode: Literal['regular', 'pro']):
def do_produce(idol: PIdol, mode: Literal['regular', 'pro']) -> bool:
"""
进行培育流程
@ -124,6 +124,7 @@ def do_produce(idol: PIdol, mode: Literal['regular', 'pro']):
:param idol: 要培育的偶像如果为 None则使用配置文件中的偶像
:param mode: 培育模式
:return: 是否因为 AP 不足而跳过本次培育
"""
if not at_home():
goto_home()
@ -133,15 +134,20 @@ def do_produce(idol: PIdol, mode: Literal['regular', 'pro']):
if ocr.find(contains('プロデュース中'), rect=R.Produce.BoxProduceOngoing):
logger.info('Ongoing produce found. Try to resume produce.')
resume_produce()
return
return True
# 0. 进入培育页面
mode_text = 'REGULAR' if mode == 'regular' else 'PRO'
(SimpleDispatcher('enter_produce')
result = (SimpleDispatcher('enter_produce')
.click(R.Produce.ButtonProduce)
.click(contains(mode_text))
.until(R.Produce.ButtonPIdolOverview)
.until(R.Produce.ButtonPIdolOverview, result=True)
.until(R.Produce.TextAPInsufficient, result=False)
).run()
if not result:
logger.info('AP insufficient. Exiting produce.')
device.click(image.expect_wait(R.InPurodyuusu.ButtonCancel))
return False
# 1. 选择 PIdol [screenshots/produce/select_p_idol.png]
select_idol(idol.value)
device.click(image.expect_wait(R.Common.ButtonNextNoIcon))
@ -177,6 +183,7 @@ def do_produce(idol: PIdol, mode: Literal['regular', 'pro']):
hajime_regular()
else:
hajime_pro()
return True
@task('培育')
def produce_task(
@ -207,9 +214,12 @@ def produce_task(
return
idol_iterator = cycle(idols)
for _ in range(count):
for i in range(count):
start_time = time.time()
do_produce(next(idol_iterator), mode)
if not do_produce(next(idol_iterator), mode):
user.info(f'由于 AP 不足,跳过了 {count - i} 次培育。')
logger.info('%d produce(s) skipped because of insufficient AP.', count - i)
break
end_time = time.time()
logger.info(f"Produce time used: {format_time(end_time - start_time)}")
@ -229,11 +239,7 @@ if __name__ == '__main__':
from kotonebot.backend.context import init_context
from kotonebot.tasks.common import BaseConfig
init_context(config_type=BaseConfig)
from kotonebot.backend.util import Profiler
pf = Profiler('profiler')
pf.begin()
do_produce(conf().produce.idols[0], 'regular')
pf.end()
pf.snakeviz()
conf().produce.enabled = True
produce_task()
# a()
# select_idol(PIdol.藤田ことね_学園生活)

View File

@ -19,7 +19,7 @@ def ask(
def info(
message: str,
images: list[MatLike],
images: list[MatLike] | None = None,
*,
once: bool = False
):

Binary file not shown.

After

Width:  |  Height:  |  Size: 519 KiB

View File

@ -0,0 +1 @@
{"definitions":{"4883c564-f950-4a29-9f5f-6f924123cd22":{"name":"Produce.TextAPInsufficient","displayName":"培育 AP 不足提示弹窗 标题","type":"template","annotationId":"4883c564-f950-4a29-9f5f-6f924123cd22","useHintRect":false},"eaba6ebe-f0df-4918-aee5-ef4e3ffedcf0":{"name":"Produce.ButtonRefillAP","displayName":"确认恢复AP按钮","type":"template","annotationId":"eaba6ebe-f0df-4918-aee5-ef4e3ffedcf0","useHintRect":false}},"annotations":[{"id":"4883c564-f950-4a29-9f5f-6f924123cd22","type":"rect","data":{"x1":50,"y1":952,"x2":179,"y2":996}},{"id":"eaba6ebe-f0df-4918-aee5-ef4e3ffedcf0","type":"rect","data":{"x1":389,"y1":1140,"x2":585,"y2":1185}}]}

Binary file not shown.

After

Width:  |  Height:  |  Size: 362 KiB