线索改进

This commit is contained in:
zhbaor 2025-06-29 20:28:54 +08:00
parent fe6a59b0f6
commit 6d3640aea0
13 changed files with 118 additions and 132 deletions

BIN
mower/resources/clue/filter_all_on.png (Stored with Git LFS) Normal file

Binary file not shown.

View file

@ -1,15 +1,13 @@
from datetime import timedelta
from mower.solvers.infra.base_mixin import BaseMixin
from mower.solvers.infra.enter_room import EnterRoomSolver
from mower.utils.log import logger
from mower.utils.recognize import Scene
from mower.utils.solver import BaseSolver, TransitionOn
from .utils import clue_cls
from .utils import ClueMainSolver, clue_cls
class DailySolver(BaseSolver, BaseMixin):
class DailySolver(BaseSolver):
solver_name = "每日线索领取"
solver_max_duration = timedelta(minutes=2)
solver_default_scene = None
@ -18,19 +16,12 @@ class DailySolver(BaseSolver, BaseMixin):
self.success = False
super().run()
@TransitionOn(Scene.INFRA_DETAILS)
def _(self):
if self.detect_room() != "meeting":
EnterRoomSolver().run("meeting", detail=False)
return
self.tap((500, 1000))
@TransitionOn(Scene.INFRA_CONFIDENTIAL)
def _(self):
if self.animation():
return
if self.success:
return True
if self.animation():
return
# 检查是否领过线索
daily_scope = ((1822, 208), (1886, 243))
if self.find("clue/badge_new", scope=daily_scope):
@ -53,17 +44,10 @@ class DailySolver(BaseSolver, BaseMixin):
self.tap(exit_pos)
self.success = True
@TransitionOn(Scene.CLUE_MESSAGE_BOARD)
def _(self):
self.cback(3, id="infra_back")
@TransitionOn(BaseSolver.waiting_scene)
def _(self):
self.waiting_solver()
@TransitionOn()
def _(self):
if self.detect_room() != "meeting":
EnterRoomSolver().run("meeting", detail=False)
return
self.tap((500, 1000))
ClueMainSolver().run()

View file

@ -1,12 +1,13 @@
from datetime import timedelta
from mower.solvers.infra.base_mixin import BaseMixin
from mower.solvers.infra.enter_room import EnterRoomSolver
from mower.utils import config
from mower.utils.log import logger
from mower.utils.recognize import Scene
from mower.utils.solver import BaseSolver, TransitionOn
from .utils import MeetingSolver
class GetClueCountSolver(BaseSolver, BaseMixin):
solver_name = "线索数量"
@ -22,13 +23,12 @@ class GetClueCountSolver(BaseSolver, BaseMixin):
@TransitionOn(Scene.INFRA_DETAILS)
def _(self):
if self.find("meeting_arrange_check_in"):
self.res = self.read_screen(
config.recog.img, limit=10, cord=((476, 985), (519, 1020))
)
logger.info(f"当前拥有线索数量为{self.res}")
return True
self.cback(3, id="infra_back")
MeetingSolver().run()
self.res = self.read_screen(
config.recog.img, limit=10, cord=((476, 985), (519, 1020))
)
logger.info(f"当前拥有线索数量为{self.res}")
return True
@TransitionOn(BaseSolver.waiting_scene)
def _(self):
@ -36,4 +36,4 @@ class GetClueCountSolver(BaseSolver, BaseMixin):
@TransitionOn()
def _(self):
EnterRoomSolver().run("meeting", detail=False)
MeetingSolver().run()

View file

@ -1,7 +1,5 @@
from datetime import timedelta
from mower.solvers.infra.base_mixin import BaseMixin
from mower.solvers.infra.enter_room import EnterRoomSolver
from mower.utils import config
from mower.utils.image import cmatch, crop2content, cropimg, loadres, thres2
from mower.utils.log import logger
@ -10,10 +8,10 @@ from mower.utils.recognize import Scene
from mower.utils.solver import BaseSolver, TransitionOn
from mower.utils.vector import va
from .utils import clue_cls, clue_scope
from .utils import ClueMainSolver, clue_cls, clue_scope
class GiveAwaySolver(BaseSolver, BaseMixin):
class GiveAwaySolver(BaseSolver):
solver_name = "传递线索"
solver_max_duration = timedelta(minutes=2)
solver_default_scene = None
@ -24,13 +22,6 @@ class GiveAwaySolver(BaseSolver, BaseMixin):
return
super().run()
@TransitionOn(Scene.INFRA_DETAILS)
def _(self):
if self.detect_room() != "meeting":
EnterRoomSolver().run("meeting", detail=False)
return
self.tap((500, 1000))
@TransitionOn(Scene.INFRA_CONFIDENTIAL)
def _(self):
self.ctap((1799, 578))
@ -38,19 +29,15 @@ class GiveAwaySolver(BaseSolver, BaseMixin):
@TransitionOn(Scene.CLUE_GIVE_AWAY)
def _(self):
if not (config.conf.leifeng_mode or self.clue_count > 9):
self.tap((1868, 54))
return True
if self.animation():
return
if (c := clue_cls("give_away")) is None:
self.tap((1868, 54))
return True
if config.recog.gray[230][600] < 90:
self.ctap(clue_scope["give_away"], 5)
return
if self.find("clue/icon_notification"):
return
if self.detect_product_complete():
if self.find("product_complete"):
return
orange = False
for i in range(4):
@ -79,7 +66,4 @@ class GiveAwaySolver(BaseSolver, BaseMixin):
@TransitionOn()
def _(self):
if self.detect_room() != "meeting":
EnterRoomSolver().run("meeting", detail=False)
return
self.tap((500, 1000))
ClueMainSolver().run()

View file

@ -1,22 +1,20 @@
from datetime import timedelta
from mower.solvers.infra.base_mixin import BaseMixin
from mower.solvers.infra.enter_room import EnterRoomSolver
from mower.utils import config
from mower.utils.scene import Scene
from mower.utils.solver import BaseSolver, TransitionOn
from .utils import MeetingSolver
class MessageBoard(BaseSolver, BaseMixin):
class MessageBoard(BaseSolver):
solver_name = "留言板"
solver_max_duration = timedelta(minutes=2)
solver_default_scene = None
@TransitionOn(Scene.INFRA_DETAILS)
def _(self):
if self.detect_room() != "meeting":
EnterRoomSolver().run("meeting", detail=False)
return
MeetingSolver().run()
if pos := self.find("clue/title_party"):
self.tap(pos)
return
@ -35,23 +33,10 @@ class MessageBoard(BaseSolver, BaseMixin):
return
return True
@TransitionOn(
[
Scene.INFRA_CONFIDENTIAL,
Scene.CLUE_MESSAGE_BOARD_FRIEND,
Scene.CLUE_ACCESS_RECORD,
]
)
def _(self):
self.cback(3, id="infra_back")
@TransitionOn(BaseSolver.waiting_scene)
def _(self):
self.waiting_solver()
@TransitionOn()
def _(self):
if self.detect_room() != "meeting":
EnterRoomSolver().run("meeting", detail=False)
return
self.tap((500, 1000))
MeetingSolver().run()

View file

@ -1,12 +1,13 @@
from datetime import timedelta
from mower.solvers.infra.base_mixin import BaseMixin
from mower.solvers.infra.enter_room import EnterRoomSolver
from mower.utils import config
from mower.utils.log import logger
from mower.utils.recognize import Scene
from mower.utils.solver import BaseSolver, TransitionOn
from .utils import MeetingSolver
class PartyTimeSolver(BaseSolver, BaseMixin):
solver_name = "线索交流结束时间"
@ -15,9 +16,7 @@ class PartyTimeSolver(BaseSolver, BaseMixin):
@TransitionOn(Scene.INFRA_DETAILS)
def _(self):
if self.detect_room() != "meeting":
EnterRoomSolver().run("meeting", detail=False)
return
MeetingSolver().run()
if not self.find("clue/party_on"):
config.party_time = None
logger.info("线索交流未开启")
@ -28,16 +27,11 @@ class PartyTimeSolver(BaseSolver, BaseMixin):
return True
if pos := self.find("clue/show_party_details"):
self.tap(pos)
return
@TransitionOn(BaseSolver.waiting_scene)
def _(self):
self.waiting_solver()
@TransitionOn(Scene.INFRA_CONFIDENTIAL)
def _(self):
self.cback(3, id="infra_back")
@TransitionOn()
def _(self):
EnterRoomSolver().run("meeting", detail=False)
MeetingSolver().run()

View file

@ -2,8 +2,6 @@ from datetime import timedelta
import cv2
from mower.solvers.infra.base_mixin import BaseMixin
from mower.solvers.infra.enter_room import EnterRoomSolver
from mower.utils import config
from mower.utils.image import crop2content, cropimg, loadres, thres2
from mower.utils.log import logger
@ -13,9 +11,9 @@ from mower.utils.solver import BaseSolver, TransitionOn
from mower.utils.vector import va
from .utils import (
ClueMainSolver,
clue_cls,
clue_scope,
exit_pos,
is_orange,
main_dots,
main_scope,
@ -29,7 +27,7 @@ filter_receive = (1900, 45)
filter_self = (1610, 70)
class PlaceSolver(BaseSolver, BaseMixin):
class PlaceSolver(BaseSolver):
solver_name = "放置线索"
solver_max_duration = timedelta(minutes=2)
solver_default_scene = None
@ -53,13 +51,6 @@ class PlaceSolver(BaseSolver, BaseMixin):
return cl, st
return None, None
@TransitionOn(Scene.INFRA_DETAILS)
def _(self):
if self.detect_room() != "meeting":
EnterRoomSolver().run("meeting", detail=False)
return
self.tap((500, 1000))
@TransitionOn(Scene.INFRA_CONFIDENTIAL)
def _(self):
if self.animation():
@ -82,8 +73,7 @@ class PlaceSolver(BaseSolver, BaseMixin):
if st in ["available", "self", "available_self_only"]:
self.ctap(main_scope[cl], 1)
return
else:
return True
return True
@TransitionOn(Scene.CLUE_PLACE)
def _(self):
@ -93,9 +83,7 @@ class PlaceSolver(BaseSolver, BaseMixin):
if unlock_pos := self.detect_unlock():
self.tap(unlock_pos)
return
else:
self.tap(exit_pos)
return True
return True
if self.get_color((1328 + 77 * cl, 114))[0] < 150:
# 右上角 1-7
self.tap(clue_scope[cl])
@ -160,7 +148,4 @@ class PlaceSolver(BaseSolver, BaseMixin):
@TransitionOn()
def _(self):
if self.detect_room() != "meeting":
EnterRoomSolver().run("meeting", detail=False)
return
self.tap((500, 1000))
ClueMainSolver().run()

View file

@ -1,7 +1,5 @@
from datetime import timedelta
from mower.solvers.infra.base_mixin import BaseMixin
from mower.solvers.infra.enter_room import EnterRoomSolver
from mower.utils import config
from mower.utils.image import cropimg
from mower.utils.log import logger
@ -9,42 +7,33 @@ from mower.utils.rapidocr import ocr_rec
from mower.utils.recognize import Scene
from mower.utils.solver import BaseSolver, TransitionOn
from .utils import clue_cls, exit_pos
from .utils import ClueMainSolver, clue_cls
class ReceiveSolver(BaseSolver, BaseMixin):
class ReceiveSolver(BaseSolver):
solver_name = "接收好友线索"
solver_max_duration = timedelta(minutes=2)
solver_default_scene = None
@TransitionOn(Scene.INFRA_DETAILS)
def _(self):
if self.detect_room() != "meeting":
EnterRoomSolver().run("meeting", detail=False)
return
self.tap((500, 1000))
@TransitionOn(Scene.INFRA_CONFIDENTIAL)
def _(self):
receive_scope = ((1822, 365), (1886, 400))
if self.find("clue/badge_new", scope=receive_scope):
self.ctap((1800, 430))
else:
return True
return
return True
@TransitionOn(Scene.CLUE_RECEIVE)
def _(self):
if self.find("infra_complete/信用", scope=((1440, 130), (1920, 193))):
self.sleep()
if self.find("product_complete"):
return
if clue := clue_cls("receive"):
name_scope = ((1580, 220), (1880, 255))
name_img = cropimg(config.recog.gray, name_scope)
name = ocr_rec(name_img) or "好友"
logger.info(f"接收{name}{clue}号线索")
self.tap(name_scope)
else:
self.tap(exit_pos)
if (clue := clue_cls("receive")) is None:
return True
name_scope = ((1580, 220), (1880, 255))
name_img = cropimg(config.recog.gray, name_scope)
name = ocr_rec(name_img) or "好友"
logger.info(f"接收{name}{clue}号线索")
self.tap(name_scope)
@TransitionOn(BaseSolver.waiting_scene)
def _(self):
@ -52,7 +41,4 @@ class ReceiveSolver(BaseSolver, BaseMixin):
@TransitionOn()
def _(self):
if self.detect_room() != "meeting":
EnterRoomSolver().run("meeting", detail=False)
return
self.tap((500, 1000))
ClueMainSolver().run()

View file

@ -1,7 +1,15 @@
import cv2
from datetime import timedelta
import cv2
import networkx as nx
from mower.solvers.infra.base_mixin import BaseMixin
from mower.solvers.infra.enter_room import EnterRoomSolver
from mower.utils import config
from mower.utils.graph.utils import DG
from mower.utils.image import cropimg, loadres
from mower.utils.recognize import Scene
from mower.utils.solver import BaseSolver, TransitionOn
from mower.utils.vector import va
clue_size = (162, 216)
@ -45,7 +53,6 @@ for i in range(1, 8):
main_time[i] = va(clue_top_left[i], main_time_offset)
main_scope[i] = tl2p(va(clue_top_left[i], main_offset))
tm_thres = 0.6
exit_pos = (1239, 144)
def clue_cls(scope):
@ -58,3 +65,53 @@ def clue_cls(scope):
if max_val > tm_thres:
return i
return None
class MeetingSolver(BaseSolver, BaseMixin):
solver_name = "会客室"
solver_max_duration = timedelta(minutes=2)
solver_default_scene = None
@TransitionOn(Scene.INFRA_MAIN)
def _(self):
EnterRoomSolver().run("meeting", detail=False)
@TransitionOn(Scene.INFRA_DETAILS)
def _(self):
if self.detect_room() != "meeting":
self.scene_graph_step(Scene.INFRA_MAIN)
return
if self.find("meeting_arrange_check_in"):
return True
self.tap((960, 540))
@TransitionOn()
def _(self):
try:
nx.shortest_path(DG, self.scene(), Scene.INFRA_DETAILS)
self.scene_graph_step(Scene.INFRA_DETAILS)
except nx.NetworkXNoPath:
self.scene_graph_step(Scene.INFRA_MAIN)
class ClueMainSolver(BaseSolver):
solver_name = "主界面"
solver_max_duration = timedelta(minutes=2)
solver_default_scene = None
@TransitionOn(Scene.INFRA_DETAILS)
def _(self):
MeetingSolver().run()
self.tap((500, 1000))
@TransitionOn(Scene.INFRA_CONFIDENTIAL)
def _(self):
return True
@TransitionOn()
def _(self):
try:
nx.shortest_path(DG, self.scene(), Scene.INFRA_CONFIDENTIAL)
self.scene_graph_step(Scene.INFRA_CONFIDENTIAL)
except nx.NetworkXNoPath:
self.scene_graph_step(Scene.INFRA_MAIN)

View file

@ -18,10 +18,10 @@ def todo_complete(solver: BaseSolver):
@edge(Scene.ACTIVITY_ROOM_DETAILS, Scene.INFRA_MAIN)
@edge(Scene.CTRLCENTER_ASSISTANT, Scene.INFRA_MAIN)
@edge(Scene.CLUE_DAILY, Scene.INFRA_CONFIDENTIAL)
@edge(Scene.CLUE_RECEIVE, Scene.INFRA_CONFIDENTIAL)
@edge(Scene.CLUE_RECEIVE, Scene.INFRA_DETAILS)
@edge(Scene.CLUE_GIVE_AWAY, Scene.INFRA_CONFIDENTIAL)
@edge(Scene.CLUE_SUMMARY, Scene.INFRA_CONFIDENTIAL)
@edge(Scene.CLUE_PLACE, Scene.INFRA_CONFIDENTIAL)
@edge(Scene.CLUE_PLACE, Scene.INFRA_DETAILS)
@edge(Scene.CLUE_MESSAGE_BOARD, Scene.INFRA_CONFIDENTIAL)
@edge(Scene.CLUE_MESSAGE_BOARD_FRIEND, Scene.CLUE_MESSAGE_BOARD)
@edge(Scene.CLUE_ACCESS_RECORD, Scene.CLUE_MESSAGE_BOARD)
@ -33,6 +33,12 @@ def infra_back(solver: BaseSolver):
solver.cback(3, id="infra_back")
@edge(Scene.CLUE_RECEIVE, Scene.INFRA_CONFIDENTIAL)
@edge(Scene.CLUE_PLACE, Scene.INFRA_CONFIDENTIAL)
def clue_receive_back(solver: BaseSolver):
solver.tap((960, 1000))
@edge(Scene.RIIC_OPERATOR_SELECT, Scene.INFRA_DETAILS)
def riic_operator_select(solver: BaseSolver):
solver.ctap("confirm_blue", 3)

View file

@ -283,7 +283,7 @@ class Recognizer:
self.scene = Scene.CLUE_GIVE_AWAY
elif self.find("clue/summary"):
self.scene = Scene.CLUE_SUMMARY
elif self.find("clue/filter_all"):
elif self.find("clue/filter_all") or self.find("clue/filter_all_on"):
self.scene = Scene.CLUE_PLACE
elif self.find("clue/message_board_banner"):
self.scene = Scene.CLUE_MESSAGE_BOARD

View file

@ -18,6 +18,7 @@ color = {
"clue/access_records.jpg": (843, 279),
"clue/daily": (526, 623),
"clue/filter_all": (1297, 99),
"clue/filter_all_on": (1299, 100),
"clue/give_away": (25, 18),
"clue/message_board_banner": (19, 1006),
"clue/message_board_collect": (1657, 876),

View file

@ -69,6 +69,7 @@ Res = Literal[
"clue/button_unlock",
"clue/daily",
"clue/filter_all",
"clue/filter_all_on",
"clue/give_away",
"clue/give_away_digit_bg",
"clue/icon_notification",