ok-ef API 參考
本文只記錄 ok-end-field 自己定義並由任務複用的介面。ocr、wait_ocr、wait_feature、wait_until、back、sleep、send_key 等框架介面來自 ok-script,其完整引數和返回型別應以當前安裝版本為準,不在此複製。
原始碼權威位置:
- 基類組合:BaseEfTask.py
- 核心能力:src/core/base_mixin/
- 業務能力:src/tasks/mixin/
- 配置:global_config_store.py、BattleConfig.py、KeyConfig.py
1. BaseEfTask 與 MRO
from src.core.BaseEfTask import BaseEfTask
BaseEfTask 的實際基類順序為:
BaseEfTask
├── WindowArrowDrawingMixin src/core/base_mixin/window_arrow_drawing_mixin.py
├── AccountOverrideMixin src/core/base_mixin/account_override_mixin.py
├── GameFlowMixin src/core/base_mixin/game_flow_mixin.py
├── RuntimeMixin src/core/base_mixin/runtime_mixin.py
├── ok.BaseTask
└── ProcessManager src/core/base_mixin/process_manager.py
任務層 Mixin 通常最終繼承 BaseEfTask:
BattleMixin ────────────────> BaseEfTask
MapMixin ───────────────────> BaseEfTask
NavigationMixin ────────────> BaseEfTask
├── LiaisonMixin
└── ZipLineMixin
LoginMixin ─────────────────> BaseEfTask
└── AccountMixin
所有參與多重繼承的 __init__ 必須呼叫 super().__init__(*args, **kwargs)。任務配置應使用 self.default_config.update(...) 等增量方式,避免覆蓋前序 Mixin 已註冊的資料。
初始化後常用屬性:
| 屬性 | 含義 |
|---|---|
self.box |
ScreenPosition(self),提供常用螢幕區域 |
self.key_config |
全域性 Game Hotkey Config 的持久化 Config |
self.key_manager |
KeyConfigManager(self.key_config) |
self.lang |
按執行時 locale 載入 assets/lang/<module>.json 的訪問器 |
self.current_user / self.current_account_id |
當前賬號上下文 |
self.once_sleep_time |
全域性 Ensure Main Once Action Sleep.SingleActionWithDelay |
1.1 座標
def box_of_screen(
self, x=0, y=0, to_x=1.0, to_y=1.0,
width=0.0, height=0.0, name=None,
hcenter=False, vcenter=False, confidence=1.0,
)
def box_of_screen_scaled(
self, original_screen_width, original_screen_height,
x_original, y_original, to_x=0, to_y=0,
width_original=0, height_original=0, name=None,
hcenter=False, vcenter=False, confidence=1.0,
)
前者使用當前螢幕的比例座標;後者將參考解析度座標縮放到當前視窗。BaseEfTask 會將傳入的比例值統一保留三位小數後交給框架。
left_panel = self.box_of_screen(0.0, 0.1, 0.35, 0.9)
button = self.box_of_screen_scaled(1920, 1080, 1600, 900, 1800, 1020)
ScreenPosition 當前提供:top_left、top_right、bottom_left、bottom_right、bottom_right_quarter、left、right、top、bottom、center,以及 nav_b/nav_c/nav_esc/nav_panel、interact_pick_f、combat_skill_1..4、combat_ult_1..4、combat_default_link_skill、combat_skill_bar、combat_ult_bar。
1.2 特徵匹配
定義於 src/core/base_mixin/runtime_mixin.py。
def find_feature(
self, feature_name=None, horizontal_variance=0, vertical_variance=0,
threshold=0, use_gray_scale=False,
x=-1, y=-1, to_x=-1, to_y=-1, width=-1, height=-1,
box=None, canny_lower=0, canny_higher=0,
frame_processor=None, template=None,
match_method=cv2.TM_CCOEFF_NORMED, screenshot=False,
mask_function=None, frame=None, limit=0, target_height=0,
feature=None,
)
def find_one(
self, feature_name=None, horizontal_variance=0, vertical_variance=0,
threshold=0, use_gray_scale=False, box=None,
canny_lower=0, canny_higher=0, frame_processor=None,
template=None, mask_function=None, frame=None,
match_method=cv2.TM_CCOEFF_NORMED, screenshot=False,
limit=1, target_height=0, feature=None,
)
feature=是feature_name=的別名。find_feature接受單個特徵或list/tuple;每個名稱都會先經過解析度適配。- 返回語義沿用框架:
find_feature返回結果列表,find_one返回首個結果或空值。 - 未顯式傳
box時,框架可使用assets/coco_annotations.json的標註區域及src/config.py中的預設 variance/threshold。
from src.data.FeatureList import FeatureList as fL
results = self.find_feature([fL.monthly_card, fL.monthly_card2])
confirm = self.find_one(fL.skip_dialog_confirm, threshold=0.8)
if confirm:
self.click(confirm)
def get_feature_by_resolution(self, base_name: str)
根據 self.width 和 FeatureList 中實際存在的列舉值選擇名稱:
| 視窗寬度 | 嘗試順序 |
|---|---|
>= 3800 |
_4k、_2k、無後綴 |
>= 2500 |
_2k、_4k、無後綴 |
| 其它 | 無後綴、_2k、_4k |
全部不存在時丟擲 AttributeError。傳入值必須能與字串拼接,通常使用 FeatureList(其成員是字串列舉)或字串。
def wait_click_feature(
self, feature, horizontal_variance=0, vertical_variance=0,
threshold=0, relative_x=0.5, relative_y=0.5,
time_out=0, pre_action=None, post_action=None, box=None,
raise_if_not_found=True, use_gray_scale=False,
canny_lower=0, canny_higher=0, click_after_delay=0,
settle_time=-1, after_sleep=0, target_height=0,
alt: bool = False,
)
命中後點擊框內相對位置,成功返回 True,未命中且不拋異常時返回 False。alt=True 走 click_with_alt。
1.3 OCR 與登入截圖
普通 ocr、wait_ocr 來自 ok-script。專案覆蓋了點選等待和登入截圖入口:
def wait_click_ocr(
self, x=0, y=0, to_x=1, to_y=1, width=0, height=0,
box=None, name=None, match=None, threshold=0, frame=None,
target_height=0, time_out=0, raise_if_not_found=False,
recheck_time=0, after_sleep=0, post_action=None, log=False,
screenshot=False, settle_time=-1, lib="default", alt=False,
)
它呼叫 wait_ocr,命中後點擊並返回 OCR 結果;否則記錄日誌並返回 None。注意:recheck_time > 0 時會等待 recheck_time 秒後重新 OCR,以新座標再執行點選。
def login_screenshot(self, need_active=True)
def login_ocr(
self, x=0, y=0, to_x=1, to_y=1, match=None,
width=0, height=0, box=None, name=None, threshold=0,
target_height=0, use_grayscale=False, log=False,
frame_processor=None, lib="default", need_active=True,
)
def login_find_feature(
self, feature=None, horizontal_variance=0, vertical_variance=0,
threshold=0, use_gray_scale=False,
x=-1, y=-1, to_x=-1, to_y=-1, width=-1, height=-1,
box=None, canny_lower=0, canny_higher=0,
frame_processor=None, template=None,
match_method=cv2.TM_CCOEFF_NORMED, screenshot=False,
mask_function=None, frame=None, limit=0, target_height=0,
need_active=True,
)
這些入口使用 Win32 螢幕捕獲繞過登入介面無法由常規 WGC 幀可靠捕獲的問題。login_find_feature 總會獲取新的登入截圖,傳入的 frame 不會成為最終識別幀。
1.4 點選、按鍵和移動
def click(
self, x=-1, y=-1, move_back=False, name=None, interval=-1,
move=True, down_time=0.01, after_sleep=0,
key="left", hcenter=False, vcenter=False,
)
click 在呼叫框架點選前先做危險狀態檢查;檢測到危險圖示會終止遊戲並拋異常。可將 Box 作為第一個位置引數傳入:
self.click(confirm_box, after_sleep=0.5)
self.click(0.5, 0.5)
def click_with_alt(
self, x=-1, y=-1, move_back=False, name=None, interval=-1,
move=True, down_time=0.01, after_sleep=0, key="left",
)
def scroll(self, x: int, y: int, count: int) -> None
def scroll_relative(self, x: float, y: float, count: int) -> None
scroll 使用視窗內畫素位置;scroll_relative 使用 0..1 比例位置。正數向上、負數向下。需要控制遊戲視角滾輪的程式碼當前另有直接呼叫 pyautogui.scroll 的場景,不能假定 UI 滾動封裝適合所有視角操作。
def press_key(self, key: str, down_time=0.02, after_sleep=0, interval=-1)
def press_industry_key(self, key: str, down_time=0.02, after_sleep=0, interval=-1)
def press_combat_key(self, key: str, down_time=0.02, after_sleep=0, interval=-1)
def press_esc(self)
def move_keys(self, keys, duration, need_back=False)
前三個方法分別以 common、industry、combat 型別呼叫 KeyConfigManager.resolve_key,引數傳預設按鍵值,例如 self.press_key("m")。move_keys 用於 w/a/s/d 等持續移動;當前實現不使用 need_back 引數。
press_esc() 僅用於過劇情(對話時)觸發 ESC,底層使用 BaseEfTask 統一初始化的鍵盤控制器。其他返回主介面、關閉頁面等流程不得使用該函式。
def dodge_forward(self, pre_hold=0.004, dodge_down_time=0.003, after_sleep=0.005)
def dodge_backward(self, pre_hold=0.004, dodge_down_time=0.003, after_sleep=0.005)
def move_to_target_once(
self, ocr_obj, max_step=100, min_step=20,
slow_radius=200, deadzone=4,
)
步長、減速半徑和死區會按當前解析度縮放。
1.5 場景與 UI
def is_main(self, esc=False, need_active=True) -> bool
def ensure_main(self, esc=True, time_out=90, after_sleep=2, need_active=True)
def in_world(self)
def in_combat_world(self)
in_world通過esc特徵判斷處於大世界,並設定_logged_in=True。in_combat_world通過top_left_tab特徵判斷戰鬥場景;它不是“非戰鬥大世界”判斷。is_main會依次嘗試大世界檢測、登入獎勵/月卡彈窗處理、已知確認彈窗和 OCR 規則;esc=True時最後按返回。ensure_main反覆呼叫is_main,預設超時為 90 秒,失敗拋異常。
def ensure_map(self, addtional_feature=None, time_out=30)
反覆傳送配置化地圖鍵 m,通過 in_map、transaction_icon、main_centre_icon 或附加特徵確認地圖。引數名原始碼中保留拼寫 addtional_feature。
def wait_ui_stable(
self, method="phash", threshold=5, stable_time=0.5,
max_wait=5, refresh_interval=1, box=None,
)
支援 phash、dhash、pixel、ssim。box 可為 Box 或 (x, y, width, height)。對於 ssim,threshold 是相似度,呼叫方通常應傳如 0.98 的浮點值,而不是預設整數 5。
def safe_back(self, match=None, feature=None, box=None,
time_out=30, once_time_out=2) -> bool
至少提供 match 或 feature;目標未出現時持續返回,成功返回 True,總超時返回 False。
1.6 YOLO
def yolo_detect(
self, name: str | list[str], frame=None, box=None, conf=0.7,
detections=None, model_key=None,
) -> list[Box]
def list_yolo_models(self) -> list[str]
def list_yolo_targets(self, model_key: str | None = None) -> list[str]
def set_yolo_model(self, model_key: str)
def release_yolo_detector(self)
模型註冊以 src/yolo/models.py 為準。未傳 model_key 時,根據第一個目標名稱路由模型;傳 detections 可跳過推理用於測試。ROI 檢測結果會映射回全屏座標,按置信度降序返回。空 name 拋 ValueError。開啟框架 use_overlay 後,原始結果畫黃色框、篩選結果畫紅色框。
2. 配置 API
2.1 任務配置
任務通過框架屬性增量註冊配置:
self.default_config.update({"启用功能": True})
self.config_description.update({"启用功能": "控制是否执行该步骤。"})
self.config_type["模式"] = {
"type": "drop_down",
"options": ["快速", "稳定"],
}
self.default_config_group.update({"常用": ["启用功能", "模式"]})
執行時使用 self.config.get(key, default)。BaseEfTask.load_config() 會按完整 MRO 收集各類的 config_key_migrations,先遷移 configs/<TaskClass>.json 的舊鍵,再呼叫框架載入。
def register_config_groups(self, groups: dict, dropdown_name="配置选择")
該方法建立帶 sub_configs 的下拉配置,併為分組內尚無預設值的鍵補 None。它會直接使用 self.config_description.update(...),呼叫前應確保任務已按框架慣例初始化配置字典。
2.2 全域性配置
from src.core.global_config_store import (
KEY_CONFIG_NAME,
get_global_config,
)
hotkeys = get_global_config(KEY_CONFIG_NAME)
map_key = hotkeys.get("Map Key", "m")
當前全域性配置項:
| 常量/名稱 | 內容 |
|---|---|
Game Hotkey Config |
通用、工業、戰鬥鍵位 |
Battle Config |
DEFAULT_BATTLE_CONFIG 戰鬥引數 |
Ensure Main Once Action Sleep |
SingleActionWithDelay |
Zip Line Config |
送貨/淤積點滑索路線與滾動設定 |
get_global_config(name) 返回持久化 ok.util.config.Config。未知名稱只有在已載入配置中能找到對應鍵時才回退返回該配置,否則拋 RuntimeError。全域性配置頁由 get_all_visible_configs() 和 GlobalConfigTab 構建。
2.3 按鍵配置
class KeyConfigManager:
def __init__(self, key_config: dict = None): ...
def update_config(self, key_config: dict): ...
def resolve_key(self, key: str, key_type: str = "common") -> str: ...
不存在 resolve_common_key、resolve_industry_key 或 resolve_combat_key。resolve_key 在指定預設表中按預設值反查配置名稱,再讀取使用者值;找不到時原樣返回。
當前預設表比舊文件多出以下鍵:
- 通用:
Handbook Key=f8、Recruitment Key=f9 - 工業:
Area Build Key=y、Blueprint Key=f1、Product Icon Toggle Key=f4
所有可改鍵操作應走 press_key/press_industry_key/press_combat_key。固定技能數字、方向鍵和系統修飾鍵等程式碼可按其明確語義使用底層傳送介面。
2.4 戰鬥配置與賬號覆蓋
def get_battle_config(self, key: str, default=None)
BattleMixin 的讀取順序:
BattleConfigManager從全域性Battle Config取值。- 任務配置
战斗配置為使用全局配置時直接返回全域性值。 - 為
使用独立配置時讀取當前任務配置,以全域性值兜底。 AccountOverrideMixin繫結後的self.config.get可再按當前穩定賬號 ID 應用賬號任務覆蓋;賬號覆蓋優先順序最高。
賬號上下文通過以下介面設定:
def set_current_account(self, username, account_id)
def iter_multi_account_context(
self, repeat_times=1, empty_accounts_message=None,
account_log_suffix="", allow_multi_account=True,
)
iter_multi_account_context 在多賬戶模式下解析賬號列表、繫結賬號覆蓋並呼叫 login_flow(username);單賬號模式清空賬號上下文。賬號列表每行只需要賬號,舊 账号, 密码 格式僅取逗號前賬號,密碼被忽略。
3. 業務 Mixin
3.1 BattleMixin
from src.tasks.mixin.battle_mixin import BattleMixin
def in_combat(self, required_yellow=0)
def in_team(self)
def is_combat_ended(self)
def wait_in_combat(self, time_out=3, click=False)
def get_skill_bar_count(self)
def ocr_lv(self)
def use_ult(self, ult_sequence: str = None)
def use_link_skill(self)
def approach_enemy(self)
def auto_battle(self, no_battle: bool = False)
關鍵語義:
in_team從首個框開始匹配skill_1,隨後再命中一個連續技能即確認隊伍狀態(至少 2 個特徵;skill_1位於最後一個框時為單人隊伍,1 個即可)。in_combat要求技能條數量達到閾值、處於隊伍且沒有等級 UI。is_combat_ended要求內部退出條件連續命中兩次;該條件是“出現等級 UI 或不在隊伍”。use_ult(None)按1..4尋找可用終極技;傳值時只嘗試該角色。返回是否釋放成功。use_link_skill僅在識別到連攜技特徵後傳送配置化戰鬥鍵e。auto_battle每輪委託AutoCombatLogic.run,全域性保護超時 420 秒;no_battle=True傳給戰鬥邏輯,使其等待而不主動戰鬥。成功/失敗返回布林值。- 戰鬥結束並非通過 YOLO 單一判斷;當前迴圈還結合戰鬥時間和
battle_space_left/b特徵。
3.2 MapMixin
from src.tasks.mixin.map_mixin import MapMixin
def task_to_transfer_point(self, need_location_list=None)
def clear_icon_in_map(self, need_reserve_icon_name=None, ocr=False)
def to_near_transfer_point(self, after_track, need_location_list=None)
task_to_transfer_point 從任務介面定位地圖,地圖穩定後再呼叫 to_near_transfer_point。to_near_transfer_point 傳送至附近傳送點。
3.3 NavigationMixin
from src.tasks.mixin.navigation_mixin import NavigationMixin
def navigate_until_target(
self, target, nav=None,
target_is_ocr=True, nav_is_ocr=False,
time_out=60, pre_loop_callback=None,
found_special_callback=None,
target_is_yolo=False, nav_is_yolo=False,
box=None, target_vertical_variance=0.0,
need_v=False, max_run_time=-1,
allow_rotate_search=True,
)
持續按 W 前進,目標和導航標識分別可用 OCR、YOLO 或 Feature。nav=None 表示純直線搜尋;found_special_callback 返回非 None 時該值直接作為函式結果。目標需持續穩定 2 秒(OCR)或 1 秒(其它方式)才返回 True。超時返回 False。max_run_time 只限制 ctrl 切換的奔跑累計時間,不限制按住 W:-1 不限制,0 全程步行,正數達到上限後切步行。allow_rotate_search 預設 True,導航連續丟失時旋轉視角整圈搜尋;送禮等不應轉動視角的場景傳 False 跳過旋轉直接按中鍵並後退搜尋。
def start_tracking_and_align_target(
self, target_feature_in_map, target_feature_out_map,
)
在地圖點選目標並啟動追蹤,關閉地圖,等待地圖外圖示並做水平對齊;返回布林值。
def align_ocr_or_find_target_to_center(
self, ocr_match_or_feature_name_list,
only_x=False, only_y=False, box=None, threshold=0.8,
max_time=50, ocr=True, use_yolo=False, back_prev=False,
raise_if_fail=True, is_num=False, need_scroll=False,
max_step=120, min_step=20, slow_radius=350, deadzone=8,
once_time=0.05, tolerance=50,
ocr_frame_processor_list=None, allow_random_move=True,
)
在 OCR、Feature 或 YOLO 模式下將目標對齊螢幕中心。max_time 是演算法嘗試尺度,內部最多迴圈 max_time * 2,不是秒數。失敗時預設拋異常;raise_if_fail=False 返回 False。back_prev 引數當前未被方法體使用。
3.4 LiaisonMixin
from src.tasks.mixin.liaison_mixin import LiaisonMixin
def transfer_to_home_point(self, box=None, should_check_out_boat=False)
def navigate_to_main_hall(self) -> bool
def navigate_to_operator_liaison_station(self)
def perform_operator_liaison(self)
def collect_gifts(self, time_out=30)
def give_gifts(self, time_out=30, gift_entry_clicked=False)
def collect_and_give_gifts(self)
transfer_to_home_point預設在地圖左半屏找傳送點;呼叫方傳box=self.box.right才是右側點。should_check_out_boat=True的實際語義是:若點選不到帝江號入口,則認為已經在帝江號區域並直接返回主介面,不會執行“退出好友船”。navigate_to_main_hall最多向前移動兩次並 OCR 區域名;即使未識別到也記錄日誌後返回True,是寬鬆檢查。navigate_to_operator_liaison_station使用地圖追蹤和navigate_until_target;途中發現聊天圖示可返回LiaisonResult.FIND_CHAT_ICON,因此返回值不只布林值。perform_operator_liaison選擇配置的優先物件,找不到時回退任一可聯絡物件,完成聯絡介面、目標對齊和聊天互動;它不包含收禮/送禮步驟。collect_and_give_gifts處理當前交流介面中的收禮或送禮入口;收禮成功後繼續嘗試送禮。
3.5 ZipLineMixin
from src.tasks.mixin.zip_line_mixin import ZipLineMixin
def on_zip_line_start(
self, delivery_to, need_scroll=None, target=None, need_v=True,
)
def zip_line_list_go(
self, zip_line_list, need_scroll=None, target=None, need_v=False,
)
def ensure_click_on_zip_line(self, max_attempts=5)
on_zip_line_start 先等待滑索 UI,隨後從 self.config[delivery_to] 讀取整數序列並呼叫 zip_line_list_go;它不是接收距離列表的入口。每段距離通過金色/白色 HSV 預處理 OCR 並居中,點選進入滑索後持續傳送固定鍵 e,直到滑索 UI 再次出現。單段等待上限 240 秒;初始滑索 UI 等待上限 60 秒,超時拋異常。
target 為 (目标, "ocr" | "yolo" | 其它),用於最後一段後的目標對齊;其它型別按 Feature 處理。流程末尾確保回到主介面。
3.6 LoginMixin
from src.tasks.mixin.login_mixin import LoginMixin
def login_flow(self, username: str, password: str | None = None)
def click_text(
self, match: str, box=None,
need_wait_disappear=True, success_match=None,
)
login_flow 不是使用者名稱密碼輸入流程。它用於切換到登入介面的“最近賬號”:
- 判斷當前是否已登入,必要時回到主介面並退出當前賬號。
- 等待登入介面的
logout特徵並確認登出。 - 點選“最近”,再用
username後四位 OCR 點選最近賬號。 - 點選“登入”,通過重新出現
logout特徵確認成功。
password 僅為舊呼叫相容引數,當前不儲存、不輸入、也不參與賬號判定。失敗路徑可能返回 False 或拋 RuntimeError;成功無顯式返回值。後四位匹配要求最近賬號列表中後四位唯一。
4. 語言資源 API
from src.data.lang import (
ACTIVE_LOCALES_CONFIG,
SUPPORTED_LOCALES,
get_lang_accessor,
get_lang_module_value,
)
每個模組對應單個 assets/lang/<module>.json:
{
"k_confirm": {
"zh_CN": {"string": "确认"},
"zh_TW": {"string": "確認"}
},
"k_amount": {
"zh_CN": {"pattern": "^\\d+$"},
"zh_TW": {"pattern": "^\\d+$"}
}
}
訪問 self.lang.<module>.<key> 時,string 返回字串、pattern 返回編譯後的正則、terms 返回列表。直接屬性解析的優先順序是 string、pattern、terms;LangNode.as_matcher()/build_matcher() 的優先順序是 pattern、string、terms。正常資源節點應只設置其中一種,避免依賴該差異。
當前活動 OCR locale 只有 zh_CN 和 zh_TW;其它四種 locale 雖可存在於 JSON 和 gettext 目錄,但在 ACTIVE_LOCALES_CONFIG 中關閉,不會進入 SUPPORTED_LOCALES。完整維護流程見 i18n 與 OCR 配置流程。