From 8250ed4be688887f57b696d2b73004fb13f3715a Mon Sep 17 00:00:00 2001 From: weinibuliu Date: Thu, 19 Feb 2026 21:49:17 +0800 Subject: [PATCH 1/4] =?UTF-8?q?feat:=20=E6=94=AF=E6=8C=81=20new=20anchor?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/MaaDebugger/maafw/__init__.py | 1 + .../webpage/index_page/runtime_control.py | 32 ++++++++++++++----- 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/src/MaaDebugger/maafw/__init__.py b/src/MaaDebugger/maafw/__init__.py index f5df0e9..4cc504b 100644 --- a/src/MaaDebugger/maafw/__init__.py +++ b/src/MaaDebugger/maafw/__init__.py @@ -448,6 +448,7 @@ def on_node_next_list( "msg": f"NextList.{msg_suffix}", "name": detail.name, "next_list": [attr.name for attr in detail.next_list], + "anchor_flags": [attr.anchor for attr in detail.next_list], } if debug_mode: print(f"[DEBUG EventSink] {msg}") diff --git a/src/MaaDebugger/webpage/index_page/runtime_control.py b/src/MaaDebugger/webpage/index_page/runtime_control.py index d849344..3ccaad5 100644 --- a/src/MaaDebugger/webpage/index_page/runtime_control.py +++ b/src/MaaDebugger/webpage/index_page/runtime_control.py @@ -44,6 +44,8 @@ class ItemData: name: str reco_id: int = 0 status: Status = Status.PENDING + # 是否通过 anchor 解析得到 + is_anchor: bool = False # 嵌套子项的容器引用(用于 RecognitionNode 添加子识别项) nested_container: Optional[Any] = field(default=None, repr=False) # 嵌套子项列表 @@ -59,6 +61,7 @@ class ListData: row_len: int current: str next_list: List[str] + anchor_flags: List[bool] = field(default_factory=list) def main(): @@ -193,8 +196,8 @@ def on_page_change(self, page: int): for row_len in row_len_list[start_index:end_index]: self.create_list(self.other_page_row, self.list_data_map[row_len]) - def add_item_data(self, index, name, row_len: int): - data = ItemData(row_len, index, name) + def add_item_data(self, index, name, row_len: int, is_anchor: bool = False): + data = ItemData(row_len, index, name, is_anchor=is_anchor) self.data[row_len][index] = data def create_list(self, row: ui.row, data: ListData): @@ -227,7 +230,14 @@ def create_items(self, index: int, name: str, row_len: int): StatusIndicator(data, "status") with ui.item_section(): - ui.item_label(name) + if data.is_anchor: + with ui.row(wrap=False).classes("items-center gap-1"): + ui.item_label(name) + ui.badge("⚓", color="blue-grey-4").props("rounded").tooltip( + "Anchor" + ) + else: + ui.item_label(name) with ui.item_section().props("side"): ui.item_label().bind_text_from(data, "reco_id").bind_visibility_from( @@ -296,9 +306,12 @@ async def _handle_message(self, msg: Dict[str, Any]): if msg_type == "NextList.Starting": name = msg.get("name", "") next_names = msg.get("next_list", []) + anchor_flags = msg.get("anchor_flags", []) if debug_mode: - print(f"[DEBUG] NextList.Starting: name={name}, next_list={next_names}") - self._on_next_list_starting(name, next_names) + print( + f"[DEBUG] NextList.Starting: name={name}, next_list={next_names}, anchor_flags={anchor_flags}" + ) + self._on_next_list_starting(name, next_names, anchor_flags) await maafw.screenshotter.refresh(False) # RecognitionNode.Starting - 标记进入嵌套识别模式 @@ -458,11 +471,13 @@ def _on_reco_node_ended(self): f"[DEBUG] RecognitionNode depth decreased to {self._reco_node_depth}, stack size: {len(self._recognition_stack)}" ) - def _on_next_list_starting(self, current: str, next_list: List[str]): + def _on_next_list_starting( + self, current: str, next_list: List[str], anchor_flags: List[bool] = [] + ): """处理 NextList 开始事件""" self.row_len += 1 - list_data = ListData(self.row_len, current, next_list) + list_data = ListData(self.row_len, current, next_list, anchor_flags) self.add_list_data(list_data) # 299/300 -> page:1 | 300/300 -> page:2 @@ -507,7 +522,8 @@ def add_list_data(self, data: ListData): self.list_data_map[data.row_len] = data for index in range(len(data.next_list)): name = data.next_list[index] - self.add_item_data(index, name, data.row_len) + is_anchor = index < len(data.anchor_flags) and data.anchor_flags[index] + self.add_item_data(index, name, data.row_len, is_anchor=is_anchor) def on_resource_loading( self, From 7285ba4ebfff00bbb41c952044092dd5e4aaa60b Mon Sep 17 00:00:00 2001 From: weinibuliu Date: Fri, 20 Feb 2026 23:34:46 +0800 Subject: [PATCH 2/4] vibe --- .../webpage/index_page/runtime_control.py | 104 ++++++++++++++++-- 1 file changed, 97 insertions(+), 7 deletions(-) diff --git a/src/MaaDebugger/webpage/index_page/runtime_control.py b/src/MaaDebugger/webpage/index_page/runtime_control.py index 3ccaad5..8a39421 100644 --- a/src/MaaDebugger/webpage/index_page/runtime_control.py +++ b/src/MaaDebugger/webpage/index_page/runtime_control.py @@ -46,6 +46,12 @@ class ItemData: status: Status = Status.PENDING # 是否通过 anchor 解析得到 is_anchor: bool = False + # 锚点名称(如 "锚点"),仅当 is_anchor=True 时有效 + anchor_name: str = "" + # 锚点指向的目标节点名称 + anchor_target: str = "" + # 锚点设置者节点名称(即定义 anchor 的节点) + anchor_setter: str = "" # 嵌套子项的容器引用(用于 RecognitionNode 添加子识别项) nested_container: Optional[Any] = field(default=None, repr=False) # 嵌套子项列表 @@ -62,6 +68,10 @@ class ListData: current: str next_list: List[str] anchor_flags: List[bool] = field(default_factory=list) + # 每个 next_list 项对应的锚点名称(空字符串表示非锚点) + anchor_names: List[str] = field(default_factory=list) + # 每个 next_list 项对应的锚点目标节点名称(空字符串表示非锚点) + anchor_targets: List[str] = field(default_factory=list) def main(): @@ -196,8 +206,25 @@ def on_page_change(self, page: int): for row_len in row_len_list[start_index:end_index]: self.create_list(self.other_page_row, self.list_data_map[row_len]) - def add_item_data(self, index, name, row_len: int, is_anchor: bool = False): - data = ItemData(row_len, index, name, is_anchor=is_anchor) + def add_item_data( + self, + index, + name, + row_len: int, + is_anchor: bool = False, + anchor_name: str = "", + anchor_target: str = "", + anchor_setter: str = "", + ): + data = ItemData( + row_len, + index, + name, + is_anchor=is_anchor, + anchor_name=anchor_name, + anchor_target=anchor_target, + anchor_setter=anchor_setter, + ) self.data[row_len][index] = data def create_list(self, row: ui.row, data: ListData): @@ -232,10 +259,13 @@ def create_items(self, index: int, name: str, row_len: int): with ui.item_section(): if data.is_anchor: with ui.row(wrap=False).classes("items-center gap-1"): - ui.item_label(name) - ui.badge("⚓", color="blue-grey-4").props("rounded").tooltip( - "Anchor" + display_name = data.anchor_target or name + anchor_label = ( + f"{display_name} (anchor:{data.anchor_name or '未知'}, " + f"from:{data.anchor_setter or '未知'})" ) + ui.item_label(anchor_label) + ui.badge("⚓", color="blue-grey-4").props("rounded") else: ui.item_label(name) @@ -477,7 +507,53 @@ def _on_next_list_starting( """处理 NextList 开始事件""" self.row_len += 1 - list_data = ListData(self.row_len, current, next_list, anchor_flags) + # 从 pipeline 的 next 列表中提取 [Anchor] 标记,得到锚点名和目标节点 + anchor_names: List[str] = [] + anchor_targets: List[str] = [] + if any(anchor_flags): + node_data = maafw.get_node_data(current) + node_next = node_data.get("next", []) + anchor_map = ( + node_data.get("anchor", {}) if isinstance(node_data, dict) else {} + ) + for i, _name in enumerate(next_list): + is_anchor = i < len(anchor_flags) and anchor_flags[i] + if not is_anchor: + anchor_names.append("") + anchor_targets.append("") + continue + + anchor_name = "" + anchor_target = "" + + if i < len(node_next) and isinstance(node_next[i], str): + raw_next = node_next[i] + if raw_next.startswith("[Anchor]"): + anchor_name = raw_next.replace("[Anchor]", "", 1) + if isinstance(anchor_map, dict): + anchor_target = anchor_map.get(anchor_name, "") + + if ( + not anchor_name + and isinstance(anchor_map, dict) + and isinstance(_name, str) + ): + if _name in anchor_map: + anchor_name = _name + anchor_target = anchor_map.get(_name, "") + + if not anchor_target and isinstance(_name, str): + anchor_target = _name + + anchor_names.append(anchor_name) + anchor_targets.append(anchor_target) + else: + anchor_names = [""] * len(next_list) + anchor_targets = [""] * len(next_list) + + list_data = ListData( + self.row_len, current, next_list, anchor_flags, anchor_names, anchor_targets + ) self.add_list_data(list_data) # 299/300 -> page:1 | 300/300 -> page:2 @@ -523,7 +599,21 @@ def add_list_data(self, data: ListData): for index in range(len(data.next_list)): name = data.next_list[index] is_anchor = index < len(data.anchor_flags) and data.anchor_flags[index] - self.add_item_data(index, name, data.row_len, is_anchor=is_anchor) + anchor_name = ( + data.anchor_names[index] if index < len(data.anchor_names) else "" + ) + anchor_target = ( + data.anchor_targets[index] if index < len(data.anchor_targets) else "" + ) + self.add_item_data( + index, + name, + data.row_len, + is_anchor=is_anchor, + anchor_name=anchor_name, + anchor_target=anchor_target, + anchor_setter=data.current if is_anchor else "", + ) def on_resource_loading( self, From ab0144ccb757fbb708c9374dba8f5e183ea8f26b Mon Sep 17 00:00:00 2001 From: weinibuliu Date: Fri, 20 Feb 2026 23:37:50 +0800 Subject: [PATCH 3/4] Update runtime_control.py --- .../webpage/index_page/runtime_control.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/MaaDebugger/webpage/index_page/runtime_control.py b/src/MaaDebugger/webpage/index_page/runtime_control.py index 8a39421..58b39bd 100644 --- a/src/MaaDebugger/webpage/index_page/runtime_control.py +++ b/src/MaaDebugger/webpage/index_page/runtime_control.py @@ -450,7 +450,11 @@ def _on_recognized(self, reco_id: int, name: str, hit: bool): # 如果通过 reco_id 没找到,检查当前 row(非嵌套项) if not found: for item in self.data[self.row_len].values(): - if item.status == Status.PENDING and item.name == name: + if item.status != Status.PENDING: + continue + name_matched = item.name == name + anchor_matched = item.is_anchor and item.anchor_target == name + if name_matched or anchor_matched: item.reco_id = reco_id item.status = Status.SUCCEEDED if hit else Status.FAILED matched_item = item @@ -464,7 +468,11 @@ def _on_recognized(self, reco_id: int, name: str, hit: bool): if not found: for row_data in self.data.values(): for item in row_data.values(): - if item.status == Status.PENDING and item.name == name: + if item.status != Status.PENDING: + continue + name_matched = item.name == name + anchor_matched = item.is_anchor and item.anchor_target == name + if name_matched or anchor_matched: item.reco_id = reco_id item.status = Status.SUCCEEDED if hit else Status.FAILED matched_item = item From 177c5ab8048e13a835ce86c41cc1aa011605cb5b Mon Sep 17 00:00:00 2001 From: weinibuliu Date: Sat, 21 Feb 2026 23:45:53 +0800 Subject: [PATCH 4/4] fix --- .../webpage/index_page/runtime_control.py | 31 ++++++++++++++----- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/src/MaaDebugger/webpage/index_page/runtime_control.py b/src/MaaDebugger/webpage/index_page/runtime_control.py index 58b39bd..1d5ff20 100644 --- a/src/MaaDebugger/webpage/index_page/runtime_control.py +++ b/src/MaaDebugger/webpage/index_page/runtime_control.py @@ -510,22 +510,32 @@ def _on_reco_node_ended(self): ) def _on_next_list_starting( - self, current: str, next_list: List[str], anchor_flags: List[bool] = [] + self, + current: str, + next_list: List[str], + anchor_flags: Optional[List[bool]] = None, ): """处理 NextList 开始事件""" self.row_len += 1 + normalized_anchor_flags = anchor_flags or [] + # 从 pipeline 的 next 列表中提取 [Anchor] 标记,得到锚点名和目标节点 anchor_names: List[str] = [] anchor_targets: List[str] = [] - if any(anchor_flags): + if any(normalized_anchor_flags): node_data = maafw.get_node_data(current) - node_next = node_data.get("next", []) - anchor_map = ( - node_data.get("anchor", {}) if isinstance(node_data, dict) else {} - ) + if isinstance(node_data, dict): + node_next = node_data.get("next", []) + anchor_map = node_data.get("anchor", {}) + else: + node_next = [] + anchor_map = {} + for i, _name in enumerate(next_list): - is_anchor = i < len(anchor_flags) and anchor_flags[i] + is_anchor = ( + i < len(normalized_anchor_flags) and normalized_anchor_flags[i] + ) if not is_anchor: anchor_names.append("") anchor_targets.append("") @@ -560,7 +570,12 @@ def _on_next_list_starting( anchor_targets = [""] * len(next_list) list_data = ListData( - self.row_len, current, next_list, anchor_flags, anchor_names, anchor_targets + self.row_len, + current, + next_list, + normalized_anchor_flags, + anchor_names, + anchor_targets, ) self.add_list_data(list_data)