diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000000..6dcdb8d26e --- /dev/null +++ b/.gitattributes @@ -0,0 +1,11 @@ +* text=auto +*.cs text eol=crlf +*.xaml text eol=crlf + +*.cpp text eol=lf +*.hpp text eol=lf +*.h text eol=lf + +*.json text eol=lf +*.md text eol=lf +*.yaml text eol=lf diff --git a/CMakeLists.txt b/CMakeLists.txt index 6bd6608adc..3cb40613e2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ -cmake_minimum_required(VERSION 2.8) -project(MeoAssistantArknights) +cmake_minimum_required(VERSION 2.8.12) +project(MaaAssistantArknights) option(BUILD_JNI "build jni" OFF) option(BUILD_TEST "build a demo" OFF) @@ -16,8 +16,8 @@ if (WIN32) set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd") endif() -add_compile_options("$<$:/W4>") -add_compile_options("$<$>:-Wall;-Wextra;-Wpedantic>") +add_compile_options("$<$:/W4;/WX>") +add_compile_options("$<$>:-Wall;-Wextra;-Wpedantic;-Werror>") add_definitions(-DASST_DLL_EXPORTS) diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index 89b811f78a..0000000000 --- a/appveyor.yml +++ /dev/null @@ -1,24 +0,0 @@ -version: 0.9.{build} -image: Visual Studio 2022 -configuration: -- RelWithDebInfo -- Release -platform: x64 -clone_depth: 1 -before_build: -- ps: nuget restore -build: - project: MeoAssistantArknights.sln - parallel: true - verbosity: minimal -notifications: -- provider: Email - to: - - mistereo@hotmail.com - subject: 'Build {{status}}: {{projectName}} {{buildVersion}}' - message: 'Commit #{{commitId}} by {{commitAuthor}} on {{commitDate}}: {{commitMessage}}' - on_build_success: true - on_build_failure: true - on_build_status_changed: false -on_failure: -- ps: iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) diff --git a/docs/readme.md b/docs/readme.md deleted file mode 100644 index dd113830ab..0000000000 --- a/docs/readme.md +++ /dev/null @@ -1,600 +0,0 @@ -# MAA使用说明 - -## 详细介绍 - -### 刷理智 - -- 若选项中没有你需要的关卡,请手动进入游戏 **蓝色开始按钮** 界面,并选择 `当前关卡`。 -- 主界面上的 `吃理智`、`吃石头`、`指定次数` 三个选项为短路开关,即三个选项中的任一条件达到,均会视为任务完成,停止刷理智。 - - 举例1:设置 `吃理智药` : `999`、`吃石头` : `10`、`指定次数` : `1`。则在刷完 **一次** 后,由于满足了 `指定次数`:`1` 的条件,视为任务完成,停止刷理智。 - - 举例2:不勾选 `吃理智药`、不勾选 `吃石头`,设置 `指定次数` : `100`。则在当前可用理智全部刷完后(可能只刷了几次),由于满足了 `不吃理智药`、`不吃石头` 的条件,视为任务完成,停止刷理智。 -- 刷完自动上传 [企鹅物流数据统计](https://penguin-stats.cn/) -- 可自定义企鹅物流 ID -- 识别并显示材料掉落 -- 掉线后会重连,继续刷上次的图 -- 凌晨 4 点刷新后也会重连,继续刷上次的图 -- 支持剿灭模式 -- 支持打完升级了的情况 -- 支持代理失败的情况,会自动放弃本次行动 - -### 基建换班 - -#### 换班策略 - -自动计算并选择 **单设施内的最优解**,支持所有通用类技能和特殊技能组合;支持识别经验书、赤金、原石碎片、芯片,分别使用不同的干员组合! - -#### 宿舍入驻心情阈值 - -识别心情进度条的百分比;心情小于该阈值的干员,不会再去上班,直接进驻宿舍。 - -#### 特殊说明 - -- 基建换班目前均为单设施最优解,但非跨设施的全局最优解。例如:`巫恋+龙舌兰`、`红云+稀音` 等这类单设施内的组合,都是可以正常识别并使用的;`迷迭香`、`红松骑士团` 这类多个设施间联动的体系,暂不支持使用。 -- 若 `无人机用途` 选择 `贸易站-龙门币` ,则将额外识别是否有 `巫恋组`,并优先为其使用。 -- 会客室仅缺一个线索时,会选择对应流派的干员;否则会选择通用干员。 -- 会客室仅当自有线索满时,才会送出线索,并且只送三个。有需要的同学可自行修改 `resource/tasks.json` 中 `SelectClue` - `maxTimes` 字段,自定义送出个数。 -- 控制中枢策略太过复杂,目前只考虑 `阿米娅`、`诗怀雅`、`凯尔希`、`彩虹小队` 及其他心情 +0.05 的干员,后续逐步优化。 -- 部分异格干员会在基建内产生冲突,请留意辅助界面上是否有提示 “干员冲突”,若有请手动再查看下基建换班情况(可能会有某个设施没人) - -### 信用商店随缘买 - -从左到右依次买,但不会买 `碳` 和 `家具零件` 。有需要的同学可自行修改 `resource/tasks.json` 中 `CreditShop-NotToBuy` - `text` 字段,自定义不买的物品。后续版本会尝试开放界面选项 - -### 公开招募识别 - -- 自动公招和公招识别是两个独立的功能! -- 自动公招支持使用 `加急许可`,全自动连续公招!请进入设置中选择~ -- 出 5、6 星都会有弹窗提示 - -### 自动肉鸽功能 - -- 设置中的三个选项 - - 尽可能往后打:用于刷蜡烛 - - 刷源石锭投资,第一层商店后直接退出:刷源石锭最高效的模式,建议手动选择 `古堡观光` (简单)模式 - - 刷源石锭投资,投资后退出:兼顾刷蜡烛和刷源石锭投资的模式 -- 肉鸽使用干员是可以自定义的,默认的干员是作者根据自己的练度随手写的,如果经常作战失败,建议按你自己的练度修改一下,请参考 [肉鸽自定义选人方法](https://github.com/MistEO/MeoAssistantArknights/issues/167)。后期将优化这里的选人逻辑 -- 支持掉线重连、支持凌晨 4 点更新后继续回去刷 -- 如果软件出现 bug 卡住了,会自动放弃当次探索并重试。但如果经常在某个地方卡住然后放弃、严重影响效率的,欢迎提个 issue 反馈一下~ - - -### 其他乱七八糟的说明 - -- 主界面上要执行的任务,是可以拖动改变顺序的。同样设置中基建换班的顺序,也是可以拖动改变的。 -- 新的活动关卡刚上线的时候可能无法正常识别,一般一两天内软件会自动 OTA 更新资源,更新后即可正常识别。 -- 活动关卡掉落识别到的 `未知材料`,一般就是活动商店的票据。 -- `resource/config.json` 中有一些自定义选项,可以尝试根据自己的需要进行修改。 -- 所有点击操作,都是点击按钮内随机位置,并模拟泊松分布(按钮偏中间位置点的概率大,越往旁边点到的概率越小)。 -- 底层算法纯 C++ 开发,并设计了多重的缓存技术,最大限度降低 CPU 和内存占用。 -- 软件支持自动更新✿✿ヽ(°▽°)ノ✿ 推荐非杠精的同学使用测试版,一般来说更新快且 bug 少(什么 MIUI (╯‵□′)╯︵┻━┻ -- 如果新版本自动下载失败,可手动下载后,直接把压缩包放到同目录下,会自动更新的。 - -### 我是国际服玩家,可以使用么? - -可以!但是目前只支持少部分功能,请参考 [这个链接](../resource/international/) - -### I'm an international server player, could I use it? - -Yes, but there are few supported features, please refer to [this link](../resource/international/) -## 模拟器支持 - -### 蓝叠模拟器 - -完美支持。需要在模拟器 `设置` - `引擎设置` 中打开 `允许ADB连接` - -### 蓝叠模拟器国际版(推荐使用) - -完美支持。需要在模拟器 `设定` - `进阶` 中打开 `Android调试桥` - -### 蓝叠模拟器 Hyper-V 版本 - -支持 - -1. 在模拟器 `设定` - `进阶` 中打开 `Android调试桥` -2. 下载 [adb](https://dl.google.com/android/repository/platform-tools-latest-windows.zip) ,将 `platform-tools` 文件夹解压到 `MeoAsstGui.exe` 的同级目录 -3. 在软件 `设置` - `连接设置` 中填写蓝叠安装目录下 `bluestacks.conf` 文件的完整路径 - -### 夜神模拟器 - -完美支持 - -### 夜神模拟器 安卓 9 - -完美支持 - -### MuMu 模拟器 - -支持。但是可能会 - -- 一直连接出错:暂时不知道是什么原因,可尝试使用自定义连接 -- 卡在主界面无法识别,过一会提示任务出错:和 MuMu 的渲染方式有关,推荐换模拟器( - -### MuMu 手游助手(星云引擎) - -不支持。没开放 adb 端口 - -### MuMu 模拟器 安卓 9 - -不支持。adb 截图出来是黑的,不知道怎么整 - -### 雷电模拟器 - -勉强支持。雷电总有莫名其妙的问题,可以试试看,不保证能用( - -### 逍遥模拟器 - -支持。但可能有莫名其妙的识别错误问题 - -### 腾讯手游助手 - -不支持。没开放 adb 端口 - -### Win11 WSA - -不支持。WSA 目前没有实现 AOSP screencap 需要的接口,无法进行截图。等微软支持后会尝试适配 - -### AVD - -支持。 - -### 自定义连接 - -1. 下载 [adb](https://dl.google.com/android/repository/platform-tools-latest-windows.zip) ,将 `platform-tools` 文件夹解压到 `MeoAsstGui.exe` 的同级目录 -2. 进入软件 `设置` - `连接设置`,填写自定义 adb 地址(需要填写 IP + 端口,例如 `127.0.0.1:5555` ) - -**注意 :** 若是使用手机,在非 `16:9` 分辨率下,部分功能不稳定(但也凑合能用),尤其是基建,几乎是不可用状态,正在进一步适配中。推荐使用 `16:9` 分辨率,经过的测试验证最多,也最稳定。 -## 常见问题 - -### 软件一打开就闪退 - -- 可能性 1: 运行库问题。 - 请尝试安装 [Visual C++ Redistributable](https://docs.microsoft.com/zh-CN/cpp/windows/latest-supported-vc-redist?view=msvc-160#visual-studio-2015-2017-2019-and-2022)、[.NET Framework 4.8](https://dotnet.microsoft.com/download/dotnet-framework/net48) 后重新运行本软件。 -- 可能性 2: CPU 指令集不支持。 - 项目使用 `PaddleOCR` 对游戏部分界面进行识别。`PaddleOCR` 用到了较新发布的 CPU 才支持的 `AVX` 指令集,而一些较老的 CPU 可能并不支持该指令集。 - 您可以尝试下载 [NoAVX](../3rdparty/ppocr_noavx.zip) 版本的 `PaddleOCR`, 解压后替换本软件中同名的文件。这是对于使用不支持 `AVX` 指令集的 CPU 的用户的性能降低的替代方案,如非必要,请不要使用。 - (具体可以下载 [CPU-Z](https://www.cpuid.com/softwares/cpu-z.html),查看“指令集”中有无 `AVX` 这一项来判断) -- 若上述均没有效果,请提 issue。 - -### 软件可以正常启动,但一点击开始运行就闪退 - -设置中的`bluestacks.conf`, 是给 [蓝叠模拟器 Hyper-V 版本](https://github.com/MistEO/MeoAssistantArknights/blob/master/docs/%E6%A8%A1%E6%8B%9F%E5%99%A8%E6%94%AF%E6%8C%81.md#%E8%93%9D%E5%8F%A0%E6%A8%A1%E6%8B%9F%E5%99%A8-hyper-v-%E7%89%88%E6%9C%AC) 使用的,若非该版本,请不要填写该项。如果确定不是这个问题,请再提 issue ~ - -### 连接错误/捕获模拟器窗口错误 - -提示 : 请根据 [使用说明](../README.md#使用说明) 确定您的模拟器及打开方式正确 - -- 方法 1: 使用 [自定义连接](#自定义连接) 的方式连接模拟器 -- 方法 2: 换模拟器,推荐 [蓝叠国际版](https://www.bluestacks.com/download.html) Nougat 64 bit -- 方法 3: _根本解决方法_ 编辑 `resource/config.json`, 修改(最好是新增)模拟器窗口句柄名,并修改对应的 adb 设置。若您修改后可以提 PR 给我,我会感激不尽的_(:з」∠)_ - -### 识别错误/任务开始后一直不动、没有反应 - -提示 : 依次进行,若问题解决,则无需往下 - -1. 请根据 [模拟器支持情况](模拟器支持.md) 确定您的模拟器是受支持的 -2. 修改模拟器分辨率设置,`320 dpi` -3. 修改模拟器分辨率设置,横屏 `1280 * 720` 分辨率 -4. 换模拟器,推荐 [蓝叠国际版](https://www.bluestacks.com/download.html) Nougat 64 bit ( 请注意蓝叠需要在模拟器设置里开启 adb ) -5. 若仍有问题,请提 issue - -### 自定义连接 - -- 下载 [adb](https://dl.google.com/android/repository/platform-tools-latest-windows.zip) ,将 `platform-tools` 文件夹解压到 `MeoAsstGui.exe` 的同级目录 -- 进入软件 `设置` - `连接设置`,填写自定义 adb 地址(需要填写 IP + 端口,例如 `127.0.0.1:5555` ) - -### 环境变量中已有 adb, 可以不再下载一份么? - -可以!请手动修改 `resource\config.json` - `Custom` - `adb` - `path` 为 `adb.exe`, 或其他 adb 的路径 -## 回调消息协议 - -### 回调函数原型 - -```c++ -typedef void(ASST_CALL* AsstCallback)(int msg, const char* details, void* custom_arg); -``` - -### 参数总览 - -- `int msg` - 消息类型 - - ```c++ - enum class AsstMsg - { - /* Global Info */ - InternalError = 0, // 内部错误 - InitFailed, // 初始化失败 - ConnectionError, // 连接相关错误 - AllTasksCompleted, // 全部任务完成 - /* TaskChain Info */ - TaskChainError = 10000, // 任务链执行/识别错误 - TaskChainStart, // 任务链开始 - TaskChainCompleted, // 任务链完成 - TaskChainExtraInfo, // 任务链额外信息 - /* SubTask Info */ - SubTaskError = 20000, // 原子任务执行/识别错误 - SubTaskStart, // 原子任务开始 - SubTaskCompleted, // 原子任务完成 - SubTaskExtraInfo // 原子任务额外信息 - }; - ``` - -- `const char* details` - 消息详情,json 字符串,详见 [字段解释](#字段解释) -- `void* custom_arg` - 调用方自定义参数,会原样传出 `AsstCreateEx` 接口中的 `custom_arg` 参数,C 系语言可利用该参数传出 `this` 指针 - -### 字段解释 - -#### InternalError - -Todo - -#### InitFailed - -```jsonc -{ - "what": string, // 错误类型 - "details": object, // 错误详情 -} -``` - -#### ConnectionError - -Todo - -#### AllTasksCompleted - -```jsonc -{ - "taskchain": string, // 最后的任务链 - "pre_taskchain": string // 上一个任务链 -} -``` - -##### 常见 `taskchain` 字段 - -- `StartUp` - 开始唤醒 -- `Fight` - 刷理智 -- `Mall` - 信用点及购物 -- `Recruit` - 自动公招 -- `RecruitCalc` - 公招识别 -- `Infrast` - 基建换班 -- `Roguelike` - 无限刷肉鸽 -- `Debug` - 调试 - -#### TaskChain 相关消息 - -```jsonc -{ - "taskchain": string, // 当前的任务链 - "pre_taskchain": string // 上一个任务链 -} -``` - -#### TaskChainExtraInfo - -Todo - -#### SubTask 相关消息 - -```jsonc -{ - "subtask": string, // 子任务名 - "class": string, // 子任务符号名 - "taskchain": string, // 当前任务链 - "details": object, // 详情 -} -``` - -##### 常见 `subtask` 字段 - -- `ProcessTask` - - ```jsonc - // 对应的 details 字段举例 - { - "task": "StartButton2", // 任务名 - "action": 512, - "exec_times": 1, // 已执行次数 - "max_times": 999, // 最大执行次数 - "algorithm": 0 - } - ``` - -- Todo 其他 - -###### 常见 `task` 字段 - -- `StartButton2` - 开始战斗 -- `MedicineConfirm` - 使用理智药 -- `StoneConfirm` - 碎石 -- `RecruitRefreshConfirm` - 公招刷新标签 -- `RecruitConfirm` - 公招确认招募 -- `RecruitNowConfirm` - 公招使用加急许可 -- `ReportToPenguinStats` - 汇报到企鹅数据统计 -- `InfrastDormDoubleConfirmButton` - 基建宿舍的二次确认按钮,仅当干员冲突时才会有,请提示用户 -- `Roguelike1Start` - 肉鸽开始探索 -- `Roguelike1StageTraderInvestConfirm` - 肉鸽投资了源石锭 -- `Roguelike1StageTraderInvestSystemFull` - 肉鸽投资达到了游戏上限 -- `Roguelike1ExitThenAbandon` - 肉鸽放弃了本次探索 -- `Roguelike1MissionCompletedFlag` - 肉鸽战斗完成 -- `Roguelike1MissionFailedFlag` - 肉鸽战斗失败 -- `Roguelike1StageSafeHouseEnter` - 肉鸽关卡:诡异行商 -- `Roguelike1StageSafeHouseEnter` - 肉鸽关卡:安全的角落 -- `Roguelike1StageEncounterEnter` - 肉鸽关卡:不期而遇/古堡馈赠 -- `Roguelike1StageCambatDpsEnter` - 肉鸽关卡:普通作战 -- `Roguelike1StageEmergencyDps` - 肉鸽关卡:紧急作战 -- `Roguelike1StageDreadfulFoe` - 肉鸽关卡:险路恶敌 -- Todo 其他 - -#### SubTaskExtraInfo - -```jsonc -{ - "taskchain": string, // 当前任务链 - "class": string, // 子任务类型 - "what": string, // 信息类型 - "details": object, // 信息详情 -} -``` - -##### 常见 `what` 及 `details` 字段 - -- `StageDrops` - 关卡材料掉落信息 - - ```jsonc - // 对应的 details 字段举例 - { - "exceptions": [], - "resultLabel": true, - "drops": [ // 本次识别到的掉落材料 - { - "dropType": "NORMAL_DROP", - "itemId": "3301", - "quantity": 2, - "itemName": "技巧概要·卷1" - }, - { - "dropType": "NORMAL_DROP", - "itemId": "3302", - "quantity": 1, - "itemName": "技巧概要·卷2" - }, - { - "dropType": "NORMAL_DROP", - "itemId": "3303", - "quantity": 2, - "itemName": "技巧概要·卷3" - } - ], - "dropTypes": [ - { - "dropTypes": "LMB" - }, - { - "dropTypes": "NORMAL_DROP" - } - ], - "stage": { // 关卡信息 - "stageCode": "CA-5", - "stageId": "wk_fly_5" - }, - "stars": 3, // 行动结束星级 - "fingerprint": "e464bafaa3f92877bbc4fb20209e4169ae49d587499c8d2e72026b96356c591f6a17477a5b345518a00b23be78252e0825070585d33f2109390807672c252a0b", - "md5": "b40ea51ec7802afa2e86951bffbbc21f", - "cost": 6.0624, - "stats": [ // 本次执行期间总的材料掉落 - { - "itemId": "3301", - "itemName": "技巧概要·卷1", - "quantity": 4 - }, - { - "itemId": "3302", - "itemName": "技巧概要·卷2", - "quantity": 3 - }, - { - "itemId": "3303", - "itemName": "技巧概要·卷3", - "quantity": 4 - } - ] - } - ``` - -- `RecruitTagsDetected` - 公招识别到了 Tags - - ```jsonc - // 对应的 details 字段举例 - { - "tags": [ - "费用回复", - "防护", - "先锋干员", - "辅助干员", - "近战位" - ] - } - ``` - -- `RecruitSpecialTag` - 公招识别到了特殊 Tag - - ```jsonc - // 对应的 details 字段举例 - { - "tag": "高级资深干员" - } - ``` - -- `RecruitResult` - 公招识别结果 - - ```jsonc - // 对应的 details 字段举例 - { - "level": 4, // 总的星级 - "result": [ - { - "tags": [ - "削弱" - ], - "level": 4, // 这组 tags 的星级 - "opers": [ - { - "name": "初雪", - "level": 5 // 干员星级 - }, - { - "name": "陨星", - "level": 5 - }, - { - "name": "槐琥", - "level": 5 - }, - { - "name": "夜烟", - "level": 4 - }, - { - "name": "流星", - "level": 4 - } - ] - }, - { - "tags": [ - "减速", - "术师干员" - ], - "level": 4, - "opers": [ - { - "name": "夜魔", - "level": 5 - }, - { - "name": "格雷伊", - "level": 4 - } - ] - }, - { - "tags": [ - "削弱", - "术师干员" - ], - "level": 4, - "opers": [ - { - "name": "夜烟", - "level": 4 - } - ] - } - ] - } - ``` - -- `RecruitTagsSelected` - 公招选择了 Tags - - ```jsonc - // 对应的 details 字段举例 - { - "tags": [ - "减速", - "术师干员" - ] - } - ``` - -- `EnterFacility` - 基建进入了设施 - - ```jsonc - // 对应的 details 字段举例 - { - "facility": "Mfg", // 设施名 - "index": 0 // 设施序号 - } - ``` - -- `NotEnoughStaff` - 基建可用干员不足 - - ```jsonc - // 对应的 details 字段举例 - { - "facility": "Mfg", // 设施名 - "index": 0 // 设施序号 - } - ``` - -- `ProductOfFacility` - 基建产物 - - ```jsonc - // 对应的 details 字段举例 - { - "product": "Money", // 产物名 - "facility": "Mfg", // 设施名 - "index": 0 // 设施序号 - } - ``` - -- `StageInfo` - 自动作战关卡信息 - - ```jsonc - // 对应的 details 字段举例 - { - "name": string // 关卡名 - } - ``` - -- `StageInfoError` - 自动作战关卡识别错误 - -- `PenguinId` - 企鹅物流 ID - - ```jsonc - // 对应的 details 字段举例 - { - "id": string - } - ``` - diff --git a/docs/战斗流程协议.md b/docs/战斗流程协议.md index 7b9c5c3491..a2f8094b7d 100644 --- a/docs/战斗流程协议.md +++ b/docs/战斗流程协议.md @@ -105,5 +105,5 @@ ## 举例 -[Sample](../resource/battle/test.json) -[GA-EX8 突袭作业](../resource/battle/GA-EX8-raid.json) +[Sample](../resource/copilot/test.json) +[GA-EX8 突袭作业](../resource/copilot/GA-EX8-raid.json) diff --git a/docs/模拟器支持.md b/docs/模拟器支持.md index 8c9efc2a16..6331e7898f 100644 --- a/docs/模拟器支持.md +++ b/docs/模拟器支持.md @@ -53,7 +53,9 @@ ### Win11 WSA -勉强支持。但 WSA 的截图经常莫名其妙截出来一个白屏,导致识别异常,不推荐使用 +勉强支持。 +- 需要下载 [adb](https://dl.google.com/android/repository/platform-tools-latest-windows.zip) ,将 `platform-tools` 文件夹解压到 `MeoAsstGui.exe` 的同级目录 +- 但 WSA 的截图经常莫名其妙截出来一个白屏,导致识别异常,不推荐使用 ### AVD diff --git a/docs/集成文档.md b/docs/集成文档.md index a2d03269cf..5f847c0da9 100644 --- a/docs/集成文档.md +++ b/docs/集成文档.md @@ -97,17 +97,20 @@ TaskId ASSTAPI AsstAppendTask(AsstHandle handle, const char* type, const char* p 不支持设置参数 - `Mall` - 领取信用及商店购物 + 领取信用及商店购物。 + 会先有序的按 `buy_first` 购买一遍,再从左到右并避开 `blacklist` 购买第二遍 ```jsonc // 对应的任务参数 { "shopping": bool, // 是否购物,可选,默认 false。不支持运行中设置 - "shopping_list": [ // 购物列表,当 shopping 为 true 时必选。不支持运行中设置 + "buy_first": [ // 优先购买列表,可选。不支持运行中设置 + string, // 商品名,如 "招聘许可"、"龙门币" 等 + ], + "blacklist": [ // 黑名单列表,可选。不支持运行中设置 string, // 商品名,如 "加急许可"、"家具零件" 等 ... - ], - "is_black_list": bool // 购物列表是否是黑名单模式,可选,默认 false。不支持运行中设置 + ] } ``` diff --git a/resource/combat_recruit.json b/resource/combat_recruit.json index 597243b9b4..8169abc5c8 100644 --- a/resource/combat_recruit.json +++ b/resource/combat_recruit.json @@ -71,10 +71,6 @@ "subProfession": "pioneer", "position": "MELEE" }, - "预备干员": { - "Doc": "事实上没有叫这个名字的干员,但为了避免肉鸽中,requires设置了但找不到的问题,增设这个干员。", - "level": 3 - }, "翎羽": { "level": 3, "profession": "PIONEER", @@ -297,6 +293,12 @@ "subProfession": "fearless", "position": "MELEE" }, + "断罪者": { + "level": 4, + "profession": "WARRIOR", + "subProfession": "fearless", + "position": "MELEE" + }, "霜叶": { "level": 4, "profession": "WARRIOR", @@ -381,6 +383,12 @@ "subProfession": "healer", "position": "RANGED" }, + "褐果": { + "level": 4, + "profession": "MEDIC", + "subProfession": "wandermedic", + "position": "RANGED" + }, "角峰": { "level": 4, "profession": "TANK", @@ -747,6 +755,12 @@ "subProfession": "funnel", "position": "RANGED" }, + "洛洛": { + "level": 5, + "profession": "CASTER", + "subProfession": "funnel", + "position": "RANGED" + }, "梅尔": { "level": 5, "profession": "SUPPORT", @@ -969,12 +983,24 @@ "subProfession": "slower", "position": "RANGED" }, + "掠风": { + "level": 5, + "profession": "SUPPORT", + "subProfession": "craftsman", + "position": "MELEE" + }, "空": { "level": 5, "profession": "SUPPORT", "subProfession": "bard", "position": "RANGED" }, + "海蒂": { + "level": 5, + "profession": "SUPPORT", + "subProfession": "bard", + "position": "RANGED" + }, "月禾": { "level": 5, "profession": "SUPPORT", @@ -1251,6 +1277,12 @@ "subProfession": "stalker", "position": "MELEE" }, + "归溟幽灵鲨": { + "level": 6, + "profession": "SPECIAL", + "subProfession": "dollkeeper", + "position": "MELEE" + }, "闪灵": { "level": 6, "profession": "MEDIC", @@ -1269,6 +1301,12 @@ "subProfession": "physician", "position": "RANGED" }, + "流明": { + "level": 6, + "profession": "MEDIC", + "subProfession": "healer", + "position": "RANGED" + }, "星熊": { "level": 6, "profession": "TANK", @@ -1305,6 +1343,12 @@ "subProfession": "duelist", "position": "MELEE" }, + "号角": { + "level": 6, + "profession": "TANK", + "subProfession": "fortress", + "position": "MELEE" + }, "山": { "level": 6, "profession": "WARRIOR", @@ -1329,6 +1373,12 @@ "subProfession": "sword", "position": "MELEE" }, + "艾丽妮": { + "level": 6, + "profession": "WARRIOR", + "subProfession": "sword", + "position": "MELEE" + }, "煌": { "level": 6, "profession": "WARRIOR", @@ -1407,10 +1457,8 @@ "subProfession": "fearless", "position": "MELEE" }, - "断罪者": { - "level": 4, - "profession": "WARRIOR", - "subProfession": "fearless", - "position": "MELEE" + "预备干员": { + "Doc": "事实上没有叫这个名字的干员,但为了避免肉鸽中,requires设置了但找不到的问题,增设这个干员。", + "level": 3 } } \ No newline at end of file diff --git a/resource/config.json b/resource/config.json index 79d48f64c1..41b0862d77 100644 --- a/resource/config.json +++ b/resource/config.json @@ -24,7 +24,7 @@ "devices": "[Adb] devices", "addressRegex": "(.+)\tdevice", "connect": "[Adb] connect [Address]", - "uuid": "[Adb] -s [Address] shell settings get secure android_id", + "uuid": "[Adb] -s [Address] shell \"settings get secure android_id | awk 'NR == 1 {p = $0} NR > 1 {print p; p = $0} END{printf p}' \"", "click": "[Adb] -s [Address] shell input tap [x] [y]", "swipe": "[Adb] -s [Address] shell input swipe [x1] [y1] [x2] [y2] [duration]", "display": "[Adb] -s [Address] shell dumpsys window displays | grep init=", @@ -37,7 +37,7 @@ "devices": "[Adb] devices", "addressRegex": "(.+)\tdevice", "connect": "[Adb] connect [Address]", - "uuid": "[Adb] -s [Address] shell settings get secure android_id", + "uuid": "[Adb] -s [Address] shell \"settings get secure android_id | awk 'NR == 1 {p = $0} NR > 1 {print p; p = $0} END{printf p}' \"", "click": "[Adb] -s [Address] shell input tap [x] [y]", "swipe": "[Adb] -s [Address] shell input swipe [x1] [y1] [x2] [y2] [duration]", "display": "[Adb] -s [Address] shell dumpsys window displays | grep init= | awk ' { print $3 } '", @@ -50,7 +50,7 @@ "devices": "[Adb] devices", "addressRegex": "(.+)\tdevice", "connect": "[Adb] connect [Address]", - "uuid": "[Adb] -s [Address] shell settings get secure android_id", + "uuid": "[Adb] -s [Address] shell \"settings get secure android_id | awk 'NR == 1 {p = $0} NR > 1 {print p; p = $0} END{printf p}' \"", "click": "[Adb] -s [Address] shell input tap [x] [y]", "swipe": "[Adb] -s [Address] shell input swipe [x1] [y1] [x2] [y2] [duration]", "display": "[Adb] -s [Address] shell dumpsys window displays | grep init= | awk ' { print $3 } '", @@ -63,7 +63,7 @@ "devices": "[Adb] devices", "addressRegex": "(.+)\tdevice", "connect": "[Adb] connect [Address]", - "uuid": "[Adb] -s [Address] shell settings get secure android_id", + "uuid": "[Adb] -s [Address] shell \"settings get secure android_id | awk 'NR == 1 {p = $0} NR > 1 {print p; p = $0} END{printf p}' \"", "click": "[Adb] -s [Address] shell input tap [x] [y]", "swipe": "[Adb] -s [Address] shell input swipe [x1] [y1] [x2] [y2] [duration]", "display": "[Adb] -s [Address] shell dumpsys window displays | grep init= | awk ' { print $3 } '", @@ -76,7 +76,7 @@ "devices": "[Adb] devices", "addressRegex": "(.+)\tdevice", "connect": "[Adb] connect [Address]", - "uuid": "[Adb] -s [Address] shell settings get secure android_id", + "uuid": "[Adb] -s [Address] shell \"settings get secure android_id | awk 'NR == 1 {p = $0} NR > 1 {print p; p = $0} END{printf p}' \"", "click": "[Adb] -s [Address] shell input tap [x] [y]", "swipe": "[Adb] -s [Address] shell input swipe [x1] [y1] [x2] [y2] [duration]", "display": "[Adb] -s [Address] shell dumpsys window displays | grep init= | awk ' { print $3 } '", @@ -89,7 +89,7 @@ "devices": "[Adb] devices", "addressRegex": "(.+)\tdevice", "connect": "[Adb] connect [Address]", - "uuid": "[Adb] -s [Address] shell settings get secure android_id", + "uuid": "[Adb] -s [Address] shell \"settings get secure android_id | awk 'NR == 1 {p = $0} NR > 1 {print p; p = $0} END{printf p}' \"", "click": "[Adb] -s [Address] shell input tap [x] [y]", "swipe": "[Adb] -s [Address] shell input swipe [x1] [y1] [x2] [y2] [duration]", "display": "[Adb] -s [Address] shell dumpsys window displays | grep init=", @@ -103,7 +103,7 @@ "addressRegex": "(.+)\tdevice", "connect": "[Adb] connect [Address]", "displayId": "[Adb] -s [Address] shell dumpsys display | grep mUniqueId=virtual:com.microsoft.windows.systemapp:com.hypergryph.arknights", - "uuid": "[Adb] -s [Address] shell settings get secure android_id", + "uuid": "[Adb] -s [Address] shell \"settings get secure android_id | awk 'NR == 1 {p = $0} NR > 1 {print p; p = $0} END{printf p}' \"", "click": "[Adb] -s [Address] shell input -d [DisplayId] tap [x] [y]", "swipe": "[Adb] -s [Address] shell input -d [DisplayId] swipe [x1] [y1] [x2] [y2] [duration]", "display": "[Adb] -s [Address] shell \"wm size -d [DisplayId]\"", diff --git a/resource/tasks.json b/resource/tasks.json index 2c413ed145..74271e08c8 100644 --- a/resource/tasks.json +++ b/resource/tasks.json @@ -44,6 +44,7 @@ "action": "SwipeToTheRight", "next": [ "StageSN-8", + "SNChapter2ToSN-8", "SwipeRightToStageSN-8" ] }, @@ -103,6 +104,7 @@ "action": "SwipeToTheLeft", "next": [ "StageSN-9", + "SNChapter3ToSN-9", "SwipeLeftToStageSN-9" ] }, @@ -162,6 +164,7 @@ "action": "SwipeToTheLeft", "next": [ "StageSN-10", + "SNChapter3ToSN-10", "SwipeLeftToStageSN-10" ] }, @@ -2530,12 +2533,14 @@ 110 ] }, - "CreditShop-NotToBuy": { + "CreditShop-ProductName": { "algorithm": "OcrDetect", - "Doc": "这里的text,是子串搜索,即商品名中只要含有任一text,就不买", - "text": [ - "碳", - "家具" + "text": [], + "ocrReplace": [ + [ + "龙门.+", + "龙门币" + ] ], "roi": [ 0, diff --git a/src/MeoAssistant/AbstractConfiger.cpp b/src/MeoAssistant/AbstractConfiger.cpp index fe0887b484..2e45d06412 100644 --- a/src/MeoAssistant/AbstractConfiger.cpp +++ b/src/MeoAssistant/AbstractConfiger.cpp @@ -9,18 +9,17 @@ bool asst::AbstractConfiger::load(const std::string& filename) { LogTraceFunction; -#ifdef WIN32 - std::string cvt_filename = utils::utf8_to_gbk(filename); +#ifdef _WIN32 + Log.info("Load:", utils::gbk_2_utf8(filename)); #else - std::string cvt_filename = filename; + Log.info("Load:", filename); #endif - Log.info("Load:", cvt_filename); - if (!std::filesystem::exists(cvt_filename)) { + if (!std::filesystem::exists(filename)) { return false; } - std::string content = utils::load_file_without_bom(cvt_filename); + std::string content = utils::load_file_without_bom(filename); auto&& ret = json::parser::parse(content); if (!ret) { diff --git a/src/MeoAssistant/AbstractImageAnalyzer.cpp b/src/MeoAssistant/AbstractImageAnalyzer.cpp index e484dbc6db..2ebc71eeb7 100644 --- a/src/MeoAssistant/AbstractImageAnalyzer.cpp +++ b/src/MeoAssistant/AbstractImageAnalyzer.cpp @@ -44,28 +44,30 @@ void asst::AbstractImageAnalyzer::set_roi(const Rect& roi) noexcept asst::Rect asst::AbstractImageAnalyzer::empty_rect_to_full(const Rect& rect, const cv::Mat image) noexcept { + if (image.empty()) { + return rect; + } if (rect.empty()) { return Rect(0, 0, image.cols, image.rows); } - else { - Rect res = rect; - if (image.cols < res.x) { - Log.error("roi is out of range", image.cols, image.rows, res.to_string()); - res.x = image.cols - res.width; - } - if (image.rows < res.y) { - Log.error("roi is out of range", image.cols, image.rows, res.to_string()); - res.y = image.rows - res.height; - } - if (image.cols < res.x + res.width) { - Log.error("roi is out of range", res.to_string()); - res.width = image.cols - res.x; - } - if (image.rows < res.y + res.height) { - Log.error("roi is out of range", res.to_string()); - res.height = image.rows - res.y; - } - return res; + Rect res = rect; + if (image.cols < res.x) { + Log.error("roi is out of range", image.cols, image.rows, res.to_string()); + res.x = image.cols - res.width; } + if (image.rows < res.y) { + Log.error("roi is out of range", image.cols, image.rows, res.to_string()); + res.y = image.rows - res.height; + } + + if (image.cols < res.x + res.width) { + Log.error("roi is out of range", res.to_string()); + res.width = image.cols - res.x; + } + if (image.rows < res.y + res.height) { + Log.error("roi is out of range", res.to_string()); + res.height = image.rows - res.y; + } + return res; } diff --git a/src/MeoAssistant/AbstractTask.cpp b/src/MeoAssistant/AbstractTask.cpp index 0ab5fc2cba..fb34ecd1c0 100644 --- a/src/MeoAssistant/AbstractTask.cpp +++ b/src/MeoAssistant/AbstractTask.cpp @@ -80,6 +80,12 @@ AbstractTask& asst::AbstractTask::set_enable(bool enable) noexcept return *this; } +AbstractTask& asst::AbstractTask::set_ignore_error(bool ignore) noexcept +{ + m_ignore_error = ignore; + return *this; +} + AbstractTask& asst::AbstractTask::set_task_id(int task_id) noexcept { m_task_id = task_id; diff --git a/src/MeoAssistant/AbstractTask.h b/src/MeoAssistant/AbstractTask.h index aadf82b168..b7466492ad 100644 --- a/src/MeoAssistant/AbstractTask.h +++ b/src/MeoAssistant/AbstractTask.h @@ -36,6 +36,7 @@ namespace asst virtual AbstractTask& set_ctrler(std::shared_ptr ctrler) noexcept; virtual AbstractTask& set_status(std::shared_ptr status) noexcept; virtual AbstractTask& set_enable(bool enable) noexcept; + virtual AbstractTask& set_ignore_error(bool ignore) noexcept; virtual AbstractTask& set_task_id(int task_id) noexcept; template @@ -51,6 +52,7 @@ namespace asst void clear_plugin() noexcept; bool get_enable() const noexcept { return m_enable; } + bool get_ignore_error() const noexcept { return m_ignore_error; } const std::string& get_task_chain() const noexcept { return m_task_chain; } int get_task_id() const noexcept { return m_task_id; } virtual json::value basic_info() const; @@ -68,6 +70,7 @@ namespace asst bool save_image(const cv::Mat image, const std::string& dir); bool m_enable = true; + bool m_ignore_error = true; AsstCallback m_callback; void* m_callback_arg = nullptr; bool* m_exit_flag = nullptr; diff --git a/src/MeoAssistant/Assistant.cpp b/src/MeoAssistant/Assistant.cpp index c16757dff0..c8388cde59 100644 --- a/src/MeoAssistant/Assistant.cpp +++ b/src/MeoAssistant/Assistant.cpp @@ -237,7 +237,11 @@ void Assistant::working_proc() bool ret = task_ptr->run(); - m_tasks_list.pop_front(); + lock.lock(); + if (!m_tasks_list.empty()) { + m_tasks_list.pop_front(); + } + lock.unlock(); auto run_msg = AsstMsg::TaskChainCompleted; if (!ret) { diff --git a/src/MeoAssistant/AsstCaller.cpp b/src/MeoAssistant/AsstCaller.cpp index b8546e87a3..43165632fc 100644 --- a/src/MeoAssistant/AsstCaller.cpp +++ b/src/MeoAssistant/AsstCaller.cpp @@ -39,8 +39,13 @@ static bool inited = false; bool AsstLoadResource(const char* path) { - bool log_inited = asst::Logger::set_dirname(std::string(path) + "/"); - bool resrc_inited = asst::Resrc.load(std::string(path) + "/resource/"); +#ifdef _WIN32 + std::string working_path = asst::utils::utf8_to_gbk(path); +#else + std::string working_path = std::string(path); +#endif + bool log_inited = asst::Logger::set_dirname(working_path + "/"); + bool resrc_inited = asst::Resrc.load(working_path + "/resource/"); if (!resrc_inited) { std::cerr << asst::Resrc.get_last_error() << std::endl; } @@ -80,7 +85,11 @@ bool AsstConnect(AsstHandle handle, const char* adb_path, const char* address, c return false; } +#ifdef _WIN32 + return handle->connect(asst::utils::utf8_to_gbk(adb_path), address, config ? config : std::string()); +#else return handle->connect(adb_path, address, config ? config : std::string()); +#endif } bool AsstStart(AsstHandle handle) @@ -108,15 +117,15 @@ TaskId AsstAppendTask(AsstHandle handle, const char* type, const char* params) } return handle->append_task(type, params); -} - -bool AsstSetTaskParams(AsstHandle handle, TaskId id, const char* params) +} + +bool AsstSetTaskParams(AsstHandle handle, TaskId id, const char* params) { if (!inited || handle == nullptr) { return 0; } - return handle->set_task_params(id, params); + return handle->set_task_params(id, params); } unsigned long long AsstGetImage(AsstHandle handle, void* buff, unsigned long long buff_size) diff --git a/src/MeoAssistant/AsstUtils.hpp b/src/MeoAssistant/AsstUtils.hpp index 475679fdab..2d3ce27916 100644 --- a/src/MeoAssistant/AsstUtils.hpp +++ b/src/MeoAssistant/AsstUtils.hpp @@ -307,5 +307,5 @@ namespace asst // } // return str; //} - } - } + } +} diff --git a/src/MeoAssistant/AutoRecruitTask.cpp b/src/MeoAssistant/AutoRecruitTask.cpp index e1cbf75246..7187911d49 100644 --- a/src/MeoAssistant/AutoRecruitTask.cpp +++ b/src/MeoAssistant/AutoRecruitTask.cpp @@ -185,7 +185,7 @@ bool asst::AutoRecruitTask::recruit_now() bool asst::AutoRecruitTask::confirm() { ProcessTask confirm_task(*this, { "RecruitConfirm" }); - return confirm_task.run(); + return confirm_task.set_retry_times(5).run(); } bool asst::AutoRecruitTask::refresh() diff --git a/src/MeoAssistant/Controller.cpp b/src/MeoAssistant/Controller.cpp index 02f1a77af6..26b6bb0dc5 100644 --- a/src/MeoAssistant/Controller.cpp +++ b/src/MeoAssistant/Controller.cpp @@ -16,7 +16,11 @@ #include #include + +#pragma warning( push ) +#pragma warning( disable : 4068) #include +#pragma warning( pop ) #include "AsstTypes.h" #include "Logger.hpp" @@ -508,7 +512,7 @@ cv::Mat asst::Controller::get_resized_image() const return cv::Mat(dsize, CV_8UC3); } cv::Mat resized_mat; - cv::resize(m_cache_image, resized_mat, dsize); + cv::resize(m_cache_image, resized_mat, dsize, 0.0, 0.0, cv::INTER_AREA); return resized_mat; } diff --git a/src/MeoAssistant/CopilotTask.cpp b/src/MeoAssistant/CopilotTask.cpp index 6c186b0504..55c98f8a28 100644 --- a/src/MeoAssistant/CopilotTask.cpp +++ b/src/MeoAssistant/CopilotTask.cpp @@ -6,37 +6,37 @@ #include "BattleFormationTask.h" asst::CopilotTask::CopilotTask(AsstCallback callback, void* callback_arg) - : PackageTask(callback, callback_arg, TaskType), - m_battle_task_ptr(std::make_shared(callback, callback_arg, TaskType)), - m_formation_task_ptr(std::make_shared(callback, callback_arg, TaskType)) + : PackageTask(callback, callback_arg, TaskType), + m_formation_task_ptr(std::make_shared(callback, callback_arg, TaskType)), + m_battle_task_ptr(std::make_shared(callback, callback_arg, TaskType)) { - m_subtasks.emplace_back(m_formation_task_ptr); + m_subtasks.emplace_back(m_formation_task_ptr)->set_ignore_error(false); - auto start_task_ptr = std::make_shared(callback, callback_arg, TaskType); - start_task_ptr->set_tasks({ "BattleStartNormal", "BattleStartRaid", "BattleStartExercise" }); - m_subtasks.emplace_back(start_task_ptr); + auto start_task_ptr = std::make_shared(callback, callback_arg, TaskType); + start_task_ptr->set_tasks({ "BattleStartNormal", "BattleStartRaid", "BattleStartExercise" }); + m_subtasks.emplace_back(start_task_ptr)->set_ignore_error(false); - m_subtasks.emplace_back(m_battle_task_ptr); + m_subtasks.emplace_back(m_battle_task_ptr); } bool asst::CopilotTask::set_params(const json::value& params) { - if (m_runned) { - return false; - } + if (m_runned) { + return false; + } - if (!params.contains("stage_name") || !params.at("stage_name").is_string()) { - return false; - } - std::string stage_name = params.at("stage_name").as_string(); + if (!params.contains("stage_name") || !params.at("stage_name").is_string()) { + return false; + } + std::string stage_name = params.at("stage_name").as_string(); - m_battle_task_ptr->set_stage_name(stage_name); - m_formation_task_ptr->set_stage_name(stage_name); + m_battle_task_ptr->set_stage_name(stage_name); + m_formation_task_ptr->set_stage_name(stage_name); - bool with_formation = params.get("formation", false); - m_formation_task_ptr->set_enable(with_formation); + bool with_formation = params.get("formation", false); + m_formation_task_ptr->set_enable(with_formation); - std::string filename = params.get("filename", std::string()); - // 文件名为空时,不加载资源,直接返回 true - return filename.empty() || Resrc.copilot().load(filename); -} \ No newline at end of file + std::string filename = params.get("filename", std::string()); + // 文件名为空时,不加载资源,直接返回 true + return filename.empty() || Resrc.copilot().load(filename); +} diff --git a/src/MeoAssistant/CreditShopImageAnalyzer.cpp b/src/MeoAssistant/CreditShopImageAnalyzer.cpp index 4d161d5fbc..9bb93c5d83 100644 --- a/src/MeoAssistant/CreditShopImageAnalyzer.cpp +++ b/src/MeoAssistant/CreditShopImageAnalyzer.cpp @@ -59,16 +59,17 @@ bool asst::CreditShopImageAnalyzer::commoditys_analyze() bool asst::CreditShopImageAnalyzer::whether_to_buy_analyze() { - const auto not_to_buy_task_ptr = std::dynamic_pointer_cast( - Task.get("CreditShop-NotToBuy")); + const auto product_name_task_ptr = std::dynamic_pointer_cast( + Task.get("CreditShop-ProductName")); for (const Rect& commodity : m_commoditys) { // 商品名的区域 - Rect name_roi = not_to_buy_task_ptr->roi; + Rect name_roi = product_name_task_ptr->roi; name_roi.x += commodity.x; name_roi.y += commodity.y; OcrImageAnalyzer ocr_analyzer(m_image, name_roi); + ocr_analyzer.set_replace(product_name_task_ptr->replace_map); ocr_analyzer.set_required(m_shopping_list); if (ocr_analyzer.analyze()) { // 黑名单模式,有识别结果说明这个商品不买,直接跳过 @@ -84,8 +85,17 @@ bool asst::CreditShopImageAnalyzer::whether_to_buy_analyze() #ifdef ASST_DEBUG cv::rectangle(m_image_draw, utils::make_rect(commodity), cv::Scalar(0, 0, 255), 2); #endif - m_need_to_buy.emplace_back(commodity); + m_need_to_buy.emplace_back(commodity, ocr_analyzer.get_result().empty() ? std::string() : ocr_analyzer.get_result().front().text); } + + if (m_is_white_list) { + std::sort(m_need_to_buy.begin(), m_need_to_buy.end(), [&]( + const auto& lhs, const auto& rhs) -> bool { + return std::find(m_shopping_list.cbegin(), m_shopping_list.cend(), lhs.second) + < std::find(m_shopping_list.cbegin(), m_shopping_list.cend(), rhs.second); + }); + } + return !m_need_to_buy.empty(); } @@ -95,7 +105,7 @@ bool asst::CreditShopImageAnalyzer::sold_out_analyze() MatchImageAnalyzer sold_out_analyzer(m_image); sold_out_analyzer.set_task_info("CreditShop-SoldOut"); - for (const Rect& commodity : m_need_to_buy) { + for (const auto& [commodity, _] : m_need_to_buy) { sold_out_analyzer.set_roi(commodity); if (sold_out_analyzer.analyze()) { #ifdef ASST_DEBUG diff --git a/src/MeoAssistant/CreditShopImageAnalyzer.h b/src/MeoAssistant/CreditShopImageAnalyzer.h index 93e6f78f44..c18000bde7 100644 --- a/src/MeoAssistant/CreditShopImageAnalyzer.h +++ b/src/MeoAssistant/CreditShopImageAnalyzer.h @@ -34,7 +34,7 @@ namespace asst bool sold_out_analyze(); std::vector m_commoditys; - std::vector m_need_to_buy; + std::vector> m_need_to_buy; std::vector m_result; std::vector m_shopping_list; diff --git a/src/MeoAssistant/FightTask.cpp b/src/MeoAssistant/FightTask.cpp index b93d5050a3..98b7f3df9d 100644 --- a/src/MeoAssistant/FightTask.cpp +++ b/src/MeoAssistant/FightTask.cpp @@ -16,14 +16,18 @@ asst::FightTask::FightTask(AsstCallback callback, void* callback_arg) .set_times_limit("StartButton2", 0) .set_times_limit("MedicineConfirm", 0) .set_times_limit("StoneConfirm", 0) - .set_enable(false); + .set_times_limit("StageSNReturnFlag", 0) + .set_enable(false) + .set_ignore_error(false); // 进入对应的关卡 m_stage_task_ptr->set_times_limit("StartButton1", 0) .set_times_limit("StartButton2", 0) .set_times_limit("MedicineConfirm", 0) .set_times_limit("StoneConfirm", 0) - .set_enable(false); + .set_times_limit("StageSNReturnFlag", 0) + .set_enable(false) + .set_ignore_error(false); // 开始战斗任务 m_fight_task_ptr->set_tasks({ "FightBegin" }) diff --git a/src/MeoAssistant/GeneralConfiger.cpp b/src/MeoAssistant/GeneralConfiger.cpp index 9af27cee4f..47c372bcb1 100644 --- a/src/MeoAssistant/GeneralConfiger.cpp +++ b/src/MeoAssistant/GeneralConfiger.cpp @@ -5,50 +5,50 @@ bool asst::GeneralConfiger::parse(const json::value& json) { - LogTraceFunction; + LogTraceFunction; - m_version = json.at("version").as_string(); + m_version = json.at("version").as_string(); - { - const json::value& options_json = json.at("options"); - m_options.task_delay = options_json.at("taskDelay").as_integer(); - m_options.control_delay_lower = options_json.at("controlDelayRange")[0].as_integer(); - m_options.control_delay_upper = options_json.at("controlDelayRange")[1].as_integer(); - //m_options.print_window = options_json.at("printWindow").as_boolean(); - m_options.adb_extra_swipe_dist = options_json.get("adbExtraSwipeDist", 100); - m_options.adb_extra_swipe_duration = options_json.get("adbExtraSwipeDuration", -1); + { + const json::value& options_json = json.at("options"); + m_options.task_delay = options_json.at("taskDelay").as_integer(); + m_options.control_delay_lower = options_json.at("controlDelayRange")[0].as_integer(); + m_options.control_delay_upper = options_json.at("controlDelayRange")[1].as_integer(); + //m_options.print_window = options_json.at("printWindow").as_boolean(); + m_options.adb_extra_swipe_dist = options_json.get("adbExtraSwipeDist", 100); + m_options.adb_extra_swipe_duration = options_json.get("adbExtraSwipeDuration", -1); - auto& penguin_report = options_json.at("penguinReport"); - m_options.penguin_report.cmd_format = penguin_report.get("cmdFormat", std::string()); + auto& penguin_report = options_json.at("penguinReport"); + m_options.penguin_report.cmd_format = penguin_report.get("cmdFormat", std::string()); - if (options_json.contains("aipOcr")) { - auto& aip_ocr = options_json.at("aipOcr"); - m_options.aip_ocr.enable = aip_ocr.get("enable", false); - m_options.aip_ocr.accurate = aip_ocr.get("accurate", false); - m_options.aip_ocr.client_id = aip_ocr.get("clientId", std::string()); - m_options.aip_ocr.client_secret = aip_ocr.get("clientSerect", std::string()); - } - } + if (options_json.contains("aipOcr")) { + auto& aip_ocr = options_json.at("aipOcr"); + m_options.aip_ocr.enable = aip_ocr.get("enable", false); + m_options.aip_ocr.accurate = aip_ocr.get("accurate", false); + m_options.aip_ocr.client_id = aip_ocr.get("clientId", std::string()); + m_options.aip_ocr.client_secret = aip_ocr.get("clientSerect", std::string()); + } + } - for (const auto& [name, cfg_json] : json.at("connection").as_object()) { - AdbCfg adb; + for (const auto& [name, cfg_json] : json.at("connection").as_object()) { + AdbCfg adb; - adb.devices = cfg_json.at("devices").as_string(); - adb.address_regex = cfg_json.at("addressRegex").as_string(); - adb.connect = cfg_json.at("connect").as_string(); - adb.display_id = cfg_json.get("displayId", std::string()); - adb.uuid = cfg_json.at("uuid").as_string(); - adb.click = cfg_json.at("click").as_string(); - adb.swipe = cfg_json.at("swipe").as_string(); - adb.display = cfg_json.at("display").as_string(); - adb.display_format = cfg_json.at("displayFormat").as_string(); - adb.screencap_raw_with_gzip = cfg_json.at("screencapRawWithGzip").as_string(); - adb.screencap_encode = cfg_json.at("screencapEncode").as_string(); - adb.release = cfg_json.at("release").as_string(); - //adb.pullscreen = cfg_json.at("pullscreen").as_string(); + adb.devices = cfg_json.at("devices").as_string(); + adb.address_regex = cfg_json.at("addressRegex").as_string(); + adb.connect = cfg_json.at("connect").as_string(); + adb.display_id = cfg_json.get("displayId", std::string()); + adb.uuid = cfg_json.at("uuid").as_string(); + adb.click = cfg_json.at("click").as_string(); + adb.swipe = cfg_json.at("swipe").as_string(); + adb.display = cfg_json.at("display").as_string(); + adb.display_format = cfg_json.at("displayFormat").as_string(); + adb.screencap_raw_with_gzip = cfg_json.at("screencapRawWithGzip").as_string(); + adb.screencap_encode = cfg_json.at("screencapEncode").as_string(); + adb.release = cfg_json.at("release").as_string(); + //adb.pullscreen = cfg_json.at("pullscreen").as_string(); - m_adb_cfg[name] = std::move(adb); - } + m_adb_cfg[name] = std::move(adb); + } - return true; + return true; } diff --git a/src/MeoAssistant/InfrastProductionTask.cpp b/src/MeoAssistant/InfrastProductionTask.cpp index 342f1d18f5..28f8ea8541 100644 --- a/src/MeoAssistant/InfrastProductionTask.cpp +++ b/src/MeoAssistant/InfrastProductionTask.cpp @@ -556,10 +556,7 @@ bool asst::InfrastProductionTask::opers_choose() [&](const infrast::BattleRealTimeOper& lhs) -> bool { int dist = HashImageAnalyzer::hamming(lhs.face_hash, find_iter->face_hash); Log.debug("opers_choose | face hash dist", dist); - if (dist < face_hash_thres) { - return true; - } - return false; + return dist < face_hash_thres; } ); if (avlb_iter != m_all_available_opers.cend()) { @@ -574,13 +571,12 @@ bool asst::InfrastProductionTask::opers_choose() opt_iter = m_optimal_combs.erase(opt_iter); } if (m_optimal_combs.empty()) { - if (count >= cur_max_num_of_opers) { - break; - } - else { // 这种情况可能是萌新,可用干员人数不足以填满当前设施 + Log.trace(__FUNCTION__, "| count", count, "cur_max_num_of_opers", cur_max_num_of_opers); + if (count < cur_max_num_of_opers) { + // 这种情况可能是萌新,可用干员人数不足以填满当前设施 callback(AsstMsg::SubTaskExtraInfo, basic_info_with_what("NotEnoughStaff")); - break; } + break; } // 因为识别完了还要点击,所以这里不能异步滑动 diff --git a/src/MeoAssistant/Logger.hpp b/src/MeoAssistant/Logger.hpp index 850b44911b..b2c2f47de6 100644 --- a/src/MeoAssistant/Logger.hpp +++ b/src/MeoAssistant/Logger.hpp @@ -6,6 +6,7 @@ #include #include #include +#include #include "AsstUtils.hpp" #include "Version.h" @@ -109,7 +110,11 @@ namespace asst trace("MeoAssistant Process Start"); trace("Version", asst::Version); trace("Build DataTime", __DATE__, __TIME__); +#ifdef _WIN32 // 输出到日志的时候统一编码utf8 + trace("Working Path", asst::utils::gbk_2_utf8(m_dirname)); +#else trace("Working Path", m_dirname); +#endif trace("-----------------------------"); } diff --git a/src/MeoAssistant/MallTask.cpp b/src/MeoAssistant/MallTask.cpp index 70b43531c6..19c9614d2d 100644 --- a/src/MeoAssistant/MallTask.cpp +++ b/src/MeoAssistant/MallTask.cpp @@ -6,12 +6,15 @@ asst::MallTask::MallTask(AsstCallback callback, void* callback_arg) : PackageTask(callback, callback_arg, TaskType), m_mall_task_ptr(std::make_shared(callback, callback_arg, TaskType)), + m_shopping_first_task_ptr(std::make_shared(callback, callback_arg, TaskType)), m_shopping_task_ptr(std::make_shared(callback, callback_arg, TaskType)) { m_mall_task_ptr->set_tasks({ "MallBegin" }); - m_shopping_task_ptr->set_enable(false); + m_shopping_first_task_ptr->set_enable(false).set_retry_times(1); + m_shopping_task_ptr->set_enable(false).set_retry_times(1); m_subtasks.emplace_back(m_mall_task_ptr); + m_subtasks.emplace_back(m_shopping_first_task_ptr); m_subtasks.emplace_back(m_shopping_task_ptr); } @@ -20,24 +23,35 @@ bool asst::MallTask::set_params(const json::value& params) bool shopping = params.get("shopping", true); if (shopping) { - if (params.contains("shopping_list") && params.at("shopping_list").is_array()) { - std::vector shopping_list; - for (auto& name : params.at("shopping_list").as_array()) { - shopping_list.emplace_back(name.as_string()); + if (params.contains("buy_first") && params.at("buy_first").is_array()) { + std::vector buy_first; + for (auto& name : params.at("buy_first").as_array()) { + buy_first.emplace_back(name.as_string()); } - if (params.get("is_black_list", false) == true) { - m_shopping_task_ptr->set_black_list(std::move(shopping_list)); + if (!buy_first.empty()) { + m_shopping_first_task_ptr->set_white_list(std::move(buy_first)); + m_shopping_first_task_ptr->set_enable(true); } else { - m_shopping_task_ptr->set_white_list(std::move(shopping_list)); + m_shopping_first_task_ptr->set_enable(false); } } else { - return false; + m_shopping_first_task_ptr->set_enable(false); } + + if (params.contains("blacklist") && params.at("blacklist").is_array()) { + std::vector shopping_list; + for (auto& name : params.at("blacklist").as_array()) { + shopping_list.emplace_back(name.as_string()); + } + m_shopping_task_ptr->set_black_list(std::move(shopping_list)); + } + m_shopping_task_ptr->set_enable(true); } else { + m_shopping_first_task_ptr->set_enable(false); m_shopping_task_ptr->set_enable(false); } return true; diff --git a/src/MeoAssistant/MallTask.h b/src/MeoAssistant/MallTask.h index 71380a716d..1d36f5f333 100644 --- a/src/MeoAssistant/MallTask.h +++ b/src/MeoAssistant/MallTask.h @@ -17,6 +17,7 @@ namespace asst static constexpr const char* TaskType = "Mall"; private: std::shared_ptr m_mall_task_ptr = nullptr; + std::shared_ptr m_shopping_first_task_ptr = nullptr; std::shared_ptr m_shopping_task_ptr = nullptr; }; } diff --git a/src/MeoAssistant/MeoAssistant.vcxproj b/src/MeoAssistant/MeoAssistant.vcxproj index 58f0172a38..57301506fc 100644 --- a/src/MeoAssistant/MeoAssistant.vcxproj +++ b/src/MeoAssistant/MeoAssistant.vcxproj @@ -248,7 +248,8 @@ stdc11 MultiThreaded MaxSpeed - /utf-8 /MP %(AdditionalOptions) + /utf-8 /MP $(ExternalCompilerOptions) %(AdditionalOptions) + true Console @@ -297,6 +298,7 @@ MultiThreaded MaxSpeed /utf-8 /MP %(AdditionalOptions) + true Console @@ -327,6 +329,7 @@ true EnableFastChecks /utf-8 /MP %(AdditionalOptions) + true Console @@ -370,4 +373,4 @@ - + \ No newline at end of file diff --git a/src/MeoAssistant/PackageTask.cpp b/src/MeoAssistant/PackageTask.cpp index 1370cb4fb1..31050e3afb 100644 --- a/src/MeoAssistant/PackageTask.cpp +++ b/src/MeoAssistant/PackageTask.cpp @@ -28,7 +28,7 @@ bool asst::PackageTask::run() .set_status(m_status) .set_task_id(m_task_id); - if (!task_ptr->run()) { + if (!task_ptr->run() && !task_ptr->get_ignore_error()) { return false; } diff --git a/src/MeoAssistant/PenguinPack.cpp b/src/MeoAssistant/PenguinPack.cpp index de15e91626..bb7d3e7612 100644 --- a/src/MeoAssistant/PenguinPack.cpp +++ b/src/MeoAssistant/PenguinPack.cpp @@ -20,7 +20,7 @@ bool asst::PenguinPack::load(const std::string& dir) bool ret = load_json(dir + "/json/stages.json", dir + "/json/hash_index.json"); for (const auto& file : std::filesystem::directory_iterator(dir + "/items")) { - ret &= load_templ(file.path().stem().u8string(), file.path().u8string()); + ret &= load_templ(file.path().stem().string(), file.path().string()); } return ret; } diff --git a/src/MeoAssistant/RecruitTask.cpp b/src/MeoAssistant/RecruitTask.cpp index b47bdb4fb2..142fa22822 100644 --- a/src/MeoAssistant/RecruitTask.cpp +++ b/src/MeoAssistant/RecruitTask.cpp @@ -14,7 +14,7 @@ asst::RecruitTask::RecruitTask(AsstCallback callback, void* callback_arg) m_recruit_only_calc_task_ptr->set_enable(false); m_subtasks.emplace_back(m_recruit_begin_task_ptr); - m_subtasks.emplace_back(m_auto_recruit_task_ptr); + m_subtasks.emplace_back(m_auto_recruit_task_ptr)->set_retry_times(1); m_subtasks.emplace_back(m_recruit_only_calc_task_ptr); } diff --git a/src/MeoAssistant/Resource.cpp b/src/MeoAssistant/Resource.cpp index 7bec4e1df8..0bcc66c1a7 100644 --- a/src/MeoAssistant/Resource.cpp +++ b/src/MeoAssistant/Resource.cpp @@ -83,8 +83,8 @@ bool asst::Resource::load(const std::string& dir) if (entry.path().extension() != ".json") { continue; } - if (!m_copilot_cfg_unique_ins.load(entry.path().u8string())) { - m_last_error = entry.path().u8string() + " Load failed"; + if (!m_copilot_cfg_unique_ins.load(entry.path().string())) { + m_last_error = entry.path().string() + " Load failed"; return false; } } @@ -93,8 +93,8 @@ bool asst::Resource::load(const std::string& dir) if (entry.path().extension() != ".json") { continue; } - if (!m_roguelike_cfg_unique_ins.load(entry.path().u8string())) { - m_last_error = entry.path().u8string() + " Load failed"; + if (!m_roguelike_cfg_unique_ins.load(entry.path().string())) { + m_last_error = entry.path().string() + " Load failed"; return false; } } diff --git a/src/MeoAssistant/StageDropsTaskPlugin.cpp b/src/MeoAssistant/StageDropsTaskPlugin.cpp index 3eb742638b..0ad9fc2ff4 100644 --- a/src/MeoAssistant/StageDropsTaskPlugin.cpp +++ b/src/MeoAssistant/StageDropsTaskPlugin.cpp @@ -110,7 +110,6 @@ bool asst::StageDropsTaskPlugin::recognize_drops() auto last_time = last_time_opt ? last_time_opt.value() : 0; m_status->set_data("LastRecognizeDrops", last_time + RecognizationTimeOffset); - return true; } diff --git a/src/MeoAssistant/TilePack.cpp b/src/MeoAssistant/TilePack.cpp index aeb67e0ee2..2798da9313 100644 --- a/src/MeoAssistant/TilePack.cpp +++ b/src/MeoAssistant/TilePack.cpp @@ -6,7 +6,7 @@ asst::TilePack::~TilePack() = default; -bool asst::TilePack::load(const std::string & dir) +bool asst::TilePack::load(const std::string& dir) { LogTraceFunction; @@ -28,7 +28,7 @@ bool asst::TilePack::load(const std::string & dir) } std::unordered_map asst::TilePack::calc( - const std::string & stage_code, bool side) const + const std::string& stage_code, bool side) const { LogTraceFunction; diff --git a/src/MeoAssistant/Version.h b/src/MeoAssistant/Version.h index de415f9699..c24e3b7c70 100644 --- a/src/MeoAssistant/Version.h +++ b/src/MeoAssistant/Version.h @@ -2,5 +2,10 @@ namespace asst { - constexpr static const char* Version = "DEBUG VERSION"; + constexpr static const char* Version = +#ifdef MAA_VERSION + MAA_VERSION; +#else + "DEBUG VERSION"; +#endif } diff --git a/src/MeoAssistantBuilder/Constants.cs b/src/MeoAssistantBuilder/Constants.cs index 7b67b1daf4..52811043bb 100644 --- a/src/MeoAssistantBuilder/Constants.cs +++ b/src/MeoAssistantBuilder/Constants.cs @@ -14,10 +14,10 @@ public static class Constants public const string MaaWpfProjectFilePath = $"{MaaWpfProjectDirectory}/MeoAsstGui.csproj"; public const string MaaBuildOutputDirectory = $"{MaaProjectRootDirectory}/x64"; - + public const string MaaCoreBuildIntermediatOutputDirectory = $"{MaaCoreProjectDirectory}/x64"; - public static readonly string[] MaaCoreExtraFiles = new [] { "MeoAssistant.pdb", "MeoAssistant.lib", "MeoAssistant.exp" }; + public static readonly string[] MaaCoreExtraFiles = new[] { "MeoAssistant.pdb", "MeoAssistant.lib", "MeoAssistant.exp" }; public static readonly string[] MaaWpfExtraFiles = new[] { "MeoAsstGui.pdb", "MeoAsstGui.exe.config" }; } diff --git a/src/MeoAssistantBuilder/Helper/CleanDirectoryHelper.cs b/src/MeoAssistantBuilder/Helper/CleanDirectoryHelper.cs index 44611e9631..48c5fa8ae9 100644 --- a/src/MeoAssistantBuilder/Helper/CleanDirectoryHelper.cs +++ b/src/MeoAssistantBuilder/Helper/CleanDirectoryHelper.cs @@ -2,6 +2,7 @@ using Cake.Common.Diagnostics; using Cake.Common.IO; namespace MeoAssistantBuilder.Helper; + public static class CleanDirectoryHelper { public static void CleanArtifacts(this MaaBuildContext context) diff --git a/src/MeoAssistantBuilder/MaaBuildContext.cs b/src/MeoAssistantBuilder/MaaBuildContext.cs index 01044eed84..ad393e1914 100644 --- a/src/MeoAssistantBuilder/MaaBuildContext.cs +++ b/src/MeoAssistantBuilder/MaaBuildContext.cs @@ -9,7 +9,7 @@ namespace MeoAssistantBuilder; public class MaaBuildContext : FrostingContext { public string MsBuildExecutable { get; set; } - + public MaaBuildContext(ICakeContext context) : base(context) { MsBuildExecutable = context.Argument("tool", ""); diff --git a/src/MeoAssistantBuilder/Tasks/DevBuildTask.cs b/src/MeoAssistantBuilder/Tasks/DevBuildTask.cs index 6b7ce804c7..1507ba06b2 100644 --- a/src/MeoAssistantBuilder/Tasks/DevBuildTask.cs +++ b/src/MeoAssistantBuilder/Tasks/DevBuildTask.cs @@ -1,4 +1,3 @@ -using Cake.Common.Build; using Cake.Common.Diagnostics; using Cake.Frosting; using MeoAssistantBuilder.Helper; diff --git a/src/MeoAssistantBuilder/Tasks/ReleaseBundleTask.cs b/src/MeoAssistantBuilder/Tasks/ReleaseBundleTask.cs index 1a75549b30..a1a056d509 100644 --- a/src/MeoAssistantBuilder/Tasks/ReleaseBundleTask.cs +++ b/src/MeoAssistantBuilder/Tasks/ReleaseBundleTask.cs @@ -45,7 +45,7 @@ public sealed class ReleaseBundleTask : FrostingTask { version += $"-{ghActions.Environment.Workflow.RunId}"; } - else + else { var tag = ghActions.Environment.Workflow.Ref.Replace("refs/tags/", ""); if (tag != version) diff --git a/src/MeoAssistantBuilder/Tasks/ReleaseCoreTask.cs b/src/MeoAssistantBuilder/Tasks/ReleaseCoreTask.cs index 8a2131b5e4..ad4fe1d1e3 100644 --- a/src/MeoAssistantBuilder/Tasks/ReleaseCoreTask.cs +++ b/src/MeoAssistantBuilder/Tasks/ReleaseCoreTask.cs @@ -45,7 +45,7 @@ public sealed class ReleaseCoreTask : FrostingTask { version += $"-{ghActions.Environment.Workflow.RunId}"; } - else + else { var tag = ghActions.Environment.Workflow.Ref.Replace("refs/tags/", ""); if (tag != version) @@ -78,7 +78,7 @@ public sealed class ReleaseCoreTask : FrostingTask context.Information("--------------------------------------------------"); var thirdPartyDlls = Directory.GetFiles(Path.Combine(Constants.MaaProjectThirdPartyDirectory, "bin")); - foreach(var f in thirdPartyDlls) + foreach (var f in thirdPartyDlls) { var fileName = new FileInfo(f).Name; File.Copy(f, Path.Combine(buildOutput, fileName)); diff --git a/src/MeoAssistantBuilder/Tasks/ReleaseResourceTask.cs b/src/MeoAssistantBuilder/Tasks/ReleaseResourceTask.cs index de89df2d60..744ff6247e 100644 --- a/src/MeoAssistantBuilder/Tasks/ReleaseResourceTask.cs +++ b/src/MeoAssistantBuilder/Tasks/ReleaseResourceTask.cs @@ -1,4 +1,3 @@ -using Cake.Common.Build; using Cake.Common.Diagnostics; using Cake.Frosting; using MeoAssistantBuilder.Helper; diff --git a/src/MeoAssistantBuilder/Tasks/ReleaseWpfTask.cs b/src/MeoAssistantBuilder/Tasks/ReleaseWpfTask.cs index 43b7ceb0b9..c12ccf6789 100644 --- a/src/MeoAssistantBuilder/Tasks/ReleaseWpfTask.cs +++ b/src/MeoAssistantBuilder/Tasks/ReleaseWpfTask.cs @@ -1,4 +1,3 @@ -using Cake.Common.Build; using Cake.Common.Diagnostics; using Cake.Frosting; using MeoAssistantBuilder.Helper; diff --git a/src/MeoAsstGui/Helper/AsstProxy.cs b/src/MeoAsstGui/Helper/AsstProxy.cs index 37ff952274..46e37ff562 100644 --- a/src/MeoAsstGui/Helper/AsstProxy.cs +++ b/src/MeoAsstGui/Helper/AsstProxy.cs @@ -1,653 +1,697 @@ -// MeoAsstGui - A part of the MeoAssistantArknights project -// Copyright (C) 2021 MistEO and Contributors -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY - -using System; -using System.Runtime.InteropServices; -using System.Windows; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using Stylet; -using StyletIoC; - -namespace MeoAsstGui -{ - using AsstHandle = IntPtr; - using TaskId = Int32; - - public class AsstProxy - { - private delegate void CallbackDelegate(int msg, IntPtr json_buffer, IntPtr custom_arg); - - private delegate void ProcCallbckMsg(AsstMsg msg, JObject details); - - [DllImport("MeoAssistant.dll")] private static extern bool AsstLoadResource(string dirname); - - [DllImport("MeoAssistant.dll")] private static extern AsstHandle AsstCreate(); - - [DllImport("MeoAssistant.dll")] private static extern AsstHandle AsstCreateEx(CallbackDelegate callback, IntPtr custom_arg); - - [DllImport("MeoAssistant.dll")] private static extern void AsstDestroy(AsstHandle handle); - - [DllImport("MeoAssistant.dll")] private static extern bool AsstConnect(AsstHandle handle, string adb_path, string address, string config); - - [DllImport("MeoAssistant.dll")] private static extern TaskId AsstAppendTask(AsstHandle handle, string type, string task_params); - - [DllImport("MeoAssistant.dll")] private static extern bool AsstSetTaskParams(AsstHandle handle, TaskId id, string task_params); - - [DllImport("MeoAssistant.dll")] private static extern bool AsstStart(AsstHandle handle); - - [DllImport("MeoAssistant.dll")] private static extern bool AsstStop(AsstHandle handle); - - [DllImport("MeoAssistant.dll")] private static extern void AsstLog(string level, string message); - - private readonly CallbackDelegate _callback; - - public AsstProxy(IContainer container, IWindowManager windowManager) - { - _container = container; - _windowManager = windowManager; - _callback = CallbackFunction; - } - - public void Init() - { - bool loaded = AsstLoadResource(System.IO.Directory.GetCurrentDirectory()); - _handle = AsstCreateEx(_callback, IntPtr.Zero); - - if (loaded == false || _handle == IntPtr.Zero) - { - Execute.OnUIThread(() => - { - _windowManager.ShowMessageBox("出现未知异常", "错误", icon: MessageBoxImage.Error); - Environment.Exit(0); - }); - } - var tvm = _container.Get(); - tvm.Idle = true; - } - - [DllImport("kernel32.dll", CharSet = CharSet.Ansi, ExactSpelling = true)] - internal static extern int lstrlenA(IntPtr ptr); - - private static string PtrToStringCustom(IntPtr ptr, System.Text.Encoding enc) - { - if (IntPtr.Zero == ptr) - { - return null; - } - if (lstrlenA(ptr) == 0) - { - return string.Empty; - } - int len = lstrlenA(ptr); - Byte[] bytes = new Byte[len + 1]; - Marshal.Copy(ptr, bytes, 0, len + 1); - return enc.GetString(bytes); - } - - private void CallbackFunction(int msg, IntPtr json_buffer, IntPtr custom_arg) - { - string json_str = PtrToStringCustom(json_buffer, System.Text.Encoding.UTF8); - //Console.WriteLine(json_str); - JObject json = (JObject)JsonConvert.DeserializeObject(json_str); - ProcCallbckMsg dlg = new ProcCallbckMsg(procMsg); - Execute.OnUIThread(() => - { - dlg((AsstMsg)msg, json); - }); - } - - private readonly IWindowManager _windowManager; - private readonly IContainer _container; - private IntPtr _handle; - - private void procMsg(AsstMsg msg, JObject details) - { - switch (msg) - { - case AsstMsg.InternalError: - break; - - case AsstMsg.InitFailed: - _windowManager.ShowMessageBox("初始化错误!请检查是否使用了中文路径", "错误", icon: MessageBoxImage.Error); - Environment.Exit(0); - break; - - case AsstMsg.ConnectionError: - break; - - case AsstMsg.AllTasksCompleted: - case AsstMsg.TaskChainError: - case AsstMsg.TaskChainStart: - case AsstMsg.TaskChainCompleted: - case AsstMsg.TaskChainExtraInfo: - procTaskChainMsg(msg, details); - break; - - case AsstMsg.SubTaskError: - case AsstMsg.SubTaskStart: - case AsstMsg.SubTaskCompleted: - case AsstMsg.SubTaskExtraInfo: - procSubTaskMsg(msg, details); - break; - } - } - - private void procTaskChainMsg(AsstMsg msg, JObject details) - { - string taskChain = details["taskchain"].ToString(); - - if (taskChain == "RecruitCalc") - { - if (msg == AsstMsg.TaskChainError) - { - var recruitModel = _container.Get(); - recruitModel.RecruitInfo = "识别错误!"; - } - return; - } - var mainModel = _container.Get(); - - switch (msg) - { - case AsstMsg.TaskChainError: - mainModel.AddLog("任务出错:" + taskChain, "darkred"); - break; - - case AsstMsg.TaskChainStart: - mainModel.AddLog("开始任务:" + taskChain); - break; - - case AsstMsg.TaskChainCompleted: - mainModel.AddLog("完成任务:" + taskChain); - break; - - case AsstMsg.TaskChainExtraInfo: - break; - - case AsstMsg.AllTasksCompleted: - mainModel.Idle = true; - mainModel.AddLog("任务已全部完成"); - mainModel.UseStone = false; - using (var toast = new ToastNotification("任务已全部完成!")) - { - toast.Show(); - } - mainModel.CheckAndShutdown(); - break; - } - } - - private void procSubTaskMsg(AsstMsg msg, JObject details) - { - // 下面几行注释暂时没用到,先注释起来... - //string taskChain = details["taskchain"].ToString(); - //string classType = details["class"].ToString(); - - //var mainModel = _container.Get(); - switch (msg) - { - case AsstMsg.SubTaskError: - procSubTaskError(details); - break; - - case AsstMsg.SubTaskStart: - procSubTaskStart(details); - break; - - case AsstMsg.SubTaskCompleted: - procSubTaskCompleted(details); - break; - - case AsstMsg.SubTaskExtraInfo: - procSubTaskExtraInfo(details); - break; - } - } - - private void procSubTaskError(JObject details) - { - string subTask = details["subtask"].ToString(); - - var mainModel = _container.Get(); - - switch (subTask) - { - case "AutoRecruitTask": - mainModel.AddLog("公招识别错误,已返回", "darkred"); - break; - - //case "StageDropsTask": - // mainModel.AddLog("关卡识别错误", "darkred"); - // break; - - case "ReportToPenguinStats": - mainModel.AddLog("上传企鹅数据错误", "darkred"); - break; - - case "CheckStageValid": - mainModel.AddLog("EX 关卡,已停止", "darkred"); - break; - } - } - - private void procSubTaskStart(JObject details) - { - string subTask = details["subtask"].ToString(); - - var mainModel = _container.Get(); - if (subTask == "ProcessTask") - { - string taskName = details["details"]["task"].ToString(); - int execTimes = (int)details["details"]["exec_times"]; - - switch (taskName) - { - case "StartButton2": - mainModel.AddLog("已开始行动 " + execTimes + " 次", "darkcyan"); - break; - - case "MedicineConfirm": - mainModel.AddLog("已吃药 " + execTimes + " 个", "darkcyan"); - break; - - case "StoneConfirm": - mainModel.AddLog("已碎石 " + execTimes + " 颗", "darkcyan"); - break; - - case "AbandonAction": - mainModel.AddLog("代理指挥失误", "darkred"); - break; - - case "RecruitRefreshConfirm": - mainModel.AddLog("已刷新标签", "darkcyan"); - break; - - case "RecruitConfirm": - mainModel.AddLog("已确认招募", "darkcyan"); - break; - - case "InfrastDormDoubleConfirmButton": - mainModel.AddLog("干员冲突", "darkred"); - break; - - /* 肉鸽相关 */ - case "Roguelike1Start": - mainModel.AddLog("已开始探索 " + execTimes + " 次", "darkcyan"); - break; - - case "Roguelike1StageTraderInvestConfirm": - mainModel.AddLog("已投资 " + execTimes + " 个源石锭", "darkcyan"); - break; - - case "Roguelike1ExitThenAbandon": - mainModel.AddLog("已放弃本次探索"); - break; - - //case "Roguelike1StartAction": - // mainModel.AddLog("开始战斗"); - // break; - - case "Roguelike1MissionCompletedFlag": - mainModel.AddLog("战斗完成"); - break; - - case "Roguelike1MissionFailedFlag": - mainModel.AddLog("战斗失败"); - break; - - case "Roguelike1StageTraderEnter": - mainModel.AddLog("关卡:诡异行商"); - break; - - case "Roguelike1StageSafeHouseEnter": - mainModel.AddLog("关卡:安全的角落"); - break; - - case "Roguelike1StageEncounterEnter": - mainModel.AddLog("关卡:不期而遇/古堡馈赠"); - break; - - //case "Roguelike1StageBoonsEnter": - // mainModel.AddLog("古堡馈赠"); - // break; - - case "Roguelike1StageCambatDpsEnter": - mainModel.AddLog("关卡:普通作战"); - break; - - case "Roguelike1StageEmergencyDps": - mainModel.AddLog("关卡:紧急作战"); - break; - - case "Roguelike1StageDreadfulFoe": - mainModel.AddLog("关卡:险路恶敌"); - break; - - case "Roguelike1StageTraderInvestSystemFull": - mainModel.AddLog("投资达到上限", "darkcyan"); - break; - } - } - } - - private void procSubTaskCompleted(JObject details) - { - } - - private void procSubTaskExtraInfo(JObject details) - { - string taskChain = details["taskchain"].ToString(); - - if (taskChain == "RecruitCalc") - { - procRecruitCalcMsg(details); - return; - } - - string what = details["what"].ToString(); - var subTaskDetails = details["details"]; - - var mainModel = _container.Get(); - switch (what) - { - case "StageDrops": - { - string cur_drops = string.Empty; - JArray drops = (JArray)subTaskDetails["drops"]; - foreach (var item in drops) - { - string itemName = item["itemName"].ToString(); - int count = (int)item["quantity"]; - cur_drops += $"{itemName} : {count}\n"; - } - cur_drops = cur_drops.EndsWith("\n") ? cur_drops.TrimEnd('\n') : "无"; - mainModel.AddLog("当次掉落:\n" + cur_drops); - - string all_drops = string.Empty; - JArray statistics = (JArray)subTaskDetails["stats"]; - foreach (var item in statistics) - { - string itemName = item["itemName"].ToString(); - int count = (int)item["quantity"]; - all_drops += $"{itemName} : {count}\n"; - } - all_drops = all_drops.EndsWith("\n") ? all_drops.TrimEnd('\n') : "无"; - mainModel.AddLog("掉落统计:\n" + all_drops); - } - break; - - case "EnterFacility": - mainModel.AddLog("当前设施:" + subTaskDetails["facility"] + " " + (int)subTaskDetails["index"]); - break; - - case "RecruitTagsDetected": - { - JArray tags = (JArray)subTaskDetails["tags"]; - string log_content = string.Empty; - foreach (var tag_name in tags) - { - string tag_str = tag_name.ToString(); - log_content += tag_str + "\n"; - } - log_content = log_content.EndsWith("\n") ? log_content.TrimEnd('\n') : "错误"; - mainModel.AddLog("公招识别结果:\n" + log_content); - } - break; - - case "RecruitSpecialTag": - { - string special = subTaskDetails["tag"].ToString(); - using (var toast = new ToastNotification("公招提示")) - { - toast.AppendContentText(special).ShowRecruit(); - } - } - break; - - case "RecruitResult": - { - int level = (int)subTaskDetails["level"]; - if (level >= 5) - { - using (var toast = new ToastNotification($"公招出 {level} 星了哦!")) - { - toast.AppendContentText(new string('★', level)).ShowRecruit(row: 2); - } - mainModel.AddLog(level + " 星 Tags", "darkorange", "Bold"); - } - else - { - mainModel.AddLog(level + " 星 Tags", "darkcyan"); - } - } - break; - - case "RecruitTagsSelected": - { - JArray selected = (JArray)subTaskDetails["tags"]; - string selected_log = string.Empty; - foreach (var tag in selected) - { - selected_log += tag.ToString() + "\n"; - } - selected_log = selected_log.EndsWith("\n") ? selected_log.TrimEnd('\n') : "无"; - - mainModel.AddLog("选择 Tags:\n" + selected_log); - } - break; - - case "NotEnoughStaff": - { - mainModel.AddLog("可用干员不足", "darkred"); - } - break; - - /* Roguelike */ - case "StageInfo": - { - mainModel.AddLog("开始战斗:" + subTaskDetails["name"]); - } - break; - - case "StageInfoError": - { - mainModel.AddLog("关卡识别错误", "darkred"); - } - break; - - case "PenguinId": - { - var settings = _container.Get(); - if (settings.PenguinId == String.Empty) - { - string id = subTaskDetails["id"].ToString(); - settings.PenguinId = id; - AsstSetPenguinId(id); - } - } - break; - } - } - - private void procRecruitCalcMsg(JObject details) - { - string what = details["what"].ToString(); - var subTaskDetails = details["details"]; - - var recruitModel = _container.Get(); - - switch (what) - { - case "RecruitTagsDetected": - { - JArray tags = (JArray)subTaskDetails["tags"]; - string info_content = "识别结果: "; - foreach (var tag_name in tags) - { - string tag_str = tag_name.ToString(); - info_content += tag_str + " "; - } - recruitModel.RecruitInfo = info_content; - } - break; - - case "RecruitSpecialTag": - { - string special = subTaskDetails["tag"].ToString(); - using (var toast = new ToastNotification("公招提示")) - { - toast.AppendContentText(special).ShowRecruit(); - } - } - break; - - case "RecruitResult": - { - string resultContent = string.Empty; - JArray result_array = (JArray)subTaskDetails["result"]; - int level = (int)subTaskDetails["level"]; - foreach (var combs in result_array) - { - int tag_level = (int)combs["level"]; - resultContent += tag_level + "星Tags: "; - foreach (var tag in (JArray)combs["tags"]) - { - resultContent += tag.ToString() + " "; - } - resultContent += "\n\t"; - foreach (var oper in (JArray)combs["opers"]) - { - resultContent += oper["level"].ToString() + " - " + oper["name"].ToString() + " "; - } - resultContent += "\n\n"; - } - recruitModel.RecruitResult = resultContent; - if (level >= 5) - { - using (var toast = new ToastNotification($"公招出 {level} 星了哦!")) - { - toast.AppendContentText(new string('★', level)).ShowRecruit(row: 2); - } - } - } - break; - } - } - - public bool AsstConnect() - { - var settings = _container.Get(); - if (settings.AdbPath == String.Empty || - settings.ConnectAddress == String.Empty) - { - return false; - } - else - { - return AsstConnect(_handle, settings.AdbPath, settings.ConnectAddress, settings.ConnectConfig); - } - } - - public bool AsstAppendFight(string stage, int max_medicine, int max_stone, int max_times) - { - return true; - } - - public bool AsstAppendAward() - { - return false; - //return AsstAppendAward(_handle); - } - - public bool AsstAppendStartUp() - { - AsstAppendTask(_handle, "StartUp", "{}"); - return true; - //return AsstAppendStartUp(_handle); - } - - public bool AsstAppendVisit() - { - return false; - //return AsstAppendVisit(_handle); - } - - public bool AsstAppendMall(bool with_shopping) - { - return false; - //return AsstAppendMall(_handle, with_shopping); - } - - public bool AsstAppendRecruit(int max_times, int[] select_level, int required_len, int[] confirm_level, int confirm_len, bool need_refresh, bool use_expedited) - { - return false; - //return AsstAppendRecruit(_handle, max_times, select_level, required_len, confirm_level, confirm_len, need_refresh, use_expedited); - } - - public bool AsstAppendInfrast(int work_mode, string[] order, int order_len, string uses_of_drones, double dorm_threshold) - { - return false; - //return AsstAppendInfrast(_handle, work_mode, order, order_len, uses_of_drones, dorm_threshold); - } - - public bool AsstAppendRoguelike(int mode) - { - return false; - //return AsstAppendRoguelike(_handle, mode); - } - - public bool AsstStart() - { - return AsstStart(_handle); - } - - public bool AsstStartRecruitCalc(int[] select_level, int required_len, bool set_time) - { - return false; - //return AsstStartRecruitCalc(_handle, select_level, required_len, set_time); - } - - public bool AsstStop() - { - return AsstStop(_handle); - } - - public void AsstSetPenguinId(string id) - { - //AsstSetPenguinId(_handle, id); - } - - //public void AsstSetParam(string type, string param, string value) - //{ - // AsstSetParam(_ptr, type, param, value); - //} - } - - public enum AsstMsg - { - /* Global Info */ - InternalError = 0, // 内部错误 - InitFailed, // 初始化失败 - ConnectionError, // 连接相关错误 - AllTasksCompleted, // 全部任务完成 - /* TaskChain Info */ - TaskChainError = 10000, // 任务链执行/识别错误 - TaskChainStart, // 任务链开始 - TaskChainCompleted, // 任务链完成 - TaskChainExtraInfo, // 任务链额外信息 - /* SubTask Info */ - SubTaskError = 20000, // 原子任务执行/识别错误 - SubTaskStart, // 原子任务开始 - SubTaskCompleted, // 原子任务完成 - SubTaskExtraInfo // 原子任务额外信息 - }; -} +// MeoAsstGui - A part of the MeoAssistantArknights project +// Copyright (C) 2021 MistEO and Contributors +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY + +using System; +using System.Runtime.InteropServices; +using System.Text; +using System.Windows; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using Stylet; +using StyletIoC; + +namespace MeoAsstGui +{ + using AsstHandle = IntPtr; + using TaskId = Int32; + + public class AsstProxy + { + private delegate void CallbackDelegate(int msg, IntPtr json_buffer, IntPtr custom_arg); + + private delegate void ProcCallbckMsg(AsstMsg msg, JObject details); + + [DllImport("MeoAssistant.dll")] private static extern bool AsstLoadResource(byte[] dirname); + + private static bool AsstLoadResource(string dirname) + { + return AsstLoadResource(Encoding.UTF8.GetBytes(dirname)); + } + + [DllImport("MeoAssistant.dll")] private static extern AsstHandle AsstCreate(); + + [DllImport("MeoAssistant.dll")] private static extern AsstHandle AsstCreateEx(CallbackDelegate callback, IntPtr custom_arg); + + [DllImport("MeoAssistant.dll")] private static extern void AsstDestroy(AsstHandle handle); + + [DllImport("MeoAssistant.dll")] private static extern bool AsstConnect(AsstHandle handle, byte[] adb_path, byte[] address, byte[] config); + + private static bool AsstConnect(AsstHandle handle, string adb_path, string address, string config) + { + return AsstConnect(handle, Encoding.UTF8.GetBytes(adb_path), Encoding.UTF8.GetBytes(address), Encoding.UTF8.GetBytes(config)); + } + + [DllImport("MeoAssistant.dll")] private static extern TaskId AsstAppendTask(AsstHandle handle, byte[] type, byte[] task_params); + + private static TaskId AsstAppendTask(AsstHandle handle, string type, string task_params) + { + return AsstAppendTask(handle, Encoding.UTF8.GetBytes(type), Encoding.UTF8.GetBytes(task_params)); + } + + [DllImport("MeoAssistant.dll")] private static extern bool AsstSetTaskParams(AsstHandle handle, TaskId id, byte[] task_params); + + [DllImport("MeoAssistant.dll")] private static extern bool AsstStart(AsstHandle handle); + + [DllImport("MeoAssistant.dll")] private static extern bool AsstStop(AsstHandle handle); + + [DllImport("MeoAssistant.dll")] private static extern void AsstLog(byte[] level, byte[] message); + + private readonly CallbackDelegate _callback; + + public AsstProxy(IContainer container, IWindowManager windowManager) + { + _container = container; + _windowManager = windowManager; + _callback = CallbackFunction; + } + + public void Init() + { + bool loaded = AsstLoadResource(System.IO.Directory.GetCurrentDirectory()); + _handle = AsstCreateEx(_callback, IntPtr.Zero); + + if (loaded == false || _handle == IntPtr.Zero) + { + Execute.OnUIThread(() => + { + _windowManager.ShowMessageBox("出现未知异常", "错误", icon: MessageBoxImage.Error); + Environment.Exit(0); + }); + } + var tvm = _container.Get(); + tvm.Idle = true; + } + + [DllImport("kernel32.dll", CharSet = CharSet.Ansi, ExactSpelling = true)] + internal static extern int lstrlenA(IntPtr ptr); + + private static string PtrToStringCustom(IntPtr ptr, System.Text.Encoding enc) + { + if (IntPtr.Zero == ptr) + { + return null; + } + if (lstrlenA(ptr) == 0) + { + return string.Empty; + } + int len = lstrlenA(ptr); + Byte[] bytes = new Byte[len + 1]; + Marshal.Copy(ptr, bytes, 0, len + 1); + return enc.GetString(bytes); + } + + private void CallbackFunction(int msg, IntPtr json_buffer, IntPtr custom_arg) + { + string json_str = PtrToStringCustom(json_buffer, System.Text.Encoding.UTF8); + //Console.WriteLine(json_str); + JObject json = (JObject)JsonConvert.DeserializeObject(json_str); + ProcCallbckMsg dlg = new ProcCallbckMsg(procMsg); + Execute.OnUIThread(() => + { + dlg((AsstMsg)msg, json); + }); + } + + private readonly IWindowManager _windowManager; + private readonly IContainer _container; + private IntPtr _handle; + + private void procMsg(AsstMsg msg, JObject details) + { + switch (msg) + { + case AsstMsg.InternalError: + break; + + case AsstMsg.InitFailed: + _windowManager.ShowMessageBox("初始化错误!请检查是否使用了中文路径", "错误", icon: MessageBoxImage.Error); + Environment.Exit(0); + break; + + case AsstMsg.ConnectionError: + break; + + case AsstMsg.AllTasksCompleted: + case AsstMsg.TaskChainError: + case AsstMsg.TaskChainStart: + case AsstMsg.TaskChainCompleted: + case AsstMsg.TaskChainExtraInfo: + procTaskChainMsg(msg, details); + break; + + case AsstMsg.SubTaskError: + case AsstMsg.SubTaskStart: + case AsstMsg.SubTaskCompleted: + case AsstMsg.SubTaskExtraInfo: + procSubTaskMsg(msg, details); + break; + } + } + + private void procTaskChainMsg(AsstMsg msg, JObject details) + { + string taskChain = details["taskchain"].ToString(); + + if (taskChain == "Recruit") + { + if (msg == AsstMsg.TaskChainError) + { + var recruitModel = _container.Get(); + recruitModel.RecruitInfo = "识别错误!"; + } + } + var mainModel = _container.Get(); + + switch (msg) + { + case AsstMsg.TaskChainError: + mainModel.AddLog("任务出错:" + taskChain, "darkred"); + break; + + case AsstMsg.TaskChainStart: + mainModel.AddLog("开始任务:" + taskChain); + break; + + case AsstMsg.TaskChainCompleted: + mainModel.AddLog("完成任务:" + taskChain); + break; + + case AsstMsg.TaskChainExtraInfo: + break; + + case AsstMsg.AllTasksCompleted: + mainModel.Idle = true; + mainModel.AddLog("任务已全部完成"); + mainModel.UseStone = false; + using (var toast = new ToastNotification("任务已全部完成!")) + { + toast.Show(); + } + mainModel.CheckAndShutdown(); + break; + } + } + + private void procSubTaskMsg(AsstMsg msg, JObject details) + { + // 下面几行注释暂时没用到,先注释起来... + //string taskChain = details["taskchain"].ToString(); + //string classType = details["class"].ToString(); + + //var mainModel = _container.Get(); + switch (msg) + { + case AsstMsg.SubTaskError: + procSubTaskError(details); + break; + + case AsstMsg.SubTaskStart: + procSubTaskStart(details); + break; + + case AsstMsg.SubTaskCompleted: + procSubTaskCompleted(details); + break; + + case AsstMsg.SubTaskExtraInfo: + procSubTaskExtraInfo(details); + break; + } + } + + private void procSubTaskError(JObject details) + { + string subTask = details["subtask"].ToString(); + + var mainModel = _container.Get(); + + switch (subTask) + { + case "AutoRecruitTask": + mainModel.AddLog("公招识别错误,已返回", "darkred"); + break; + + //case "StageDropsTask": + // mainModel.AddLog("关卡识别错误", "darkred"); + // break; + + case "ReportToPenguinStats": + mainModel.AddLog("上传企鹅数据错误", "darkred"); + break; + + case "CheckStageValid": + mainModel.AddLog("EX 关卡,已停止", "darkred"); + break; + } + } + + private void procSubTaskStart(JObject details) + { + string subTask = details["subtask"].ToString(); + + var mainModel = _container.Get(); + if (subTask == "ProcessTask") + { + string taskName = details["details"]["task"].ToString(); + int execTimes = (int)details["details"]["exec_times"]; + + switch (taskName) + { + case "StartButton2": + mainModel.AddLog("已开始行动 " + execTimes + " 次", "darkcyan"); + break; + + case "MedicineConfirm": + mainModel.AddLog("已吃药 " + execTimes + " 个", "darkcyan"); + break; + + case "StoneConfirm": + mainModel.AddLog("已碎石 " + execTimes + " 颗", "darkcyan"); + break; + + case "AbandonAction": + mainModel.AddLog("代理指挥失误", "darkred"); + break; + + case "RecruitRefreshConfirm": + mainModel.AddLog("已刷新标签", "darkcyan"); + break; + + case "RecruitConfirm": + mainModel.AddLog("已确认招募", "darkcyan"); + break; + + case "InfrastDormDoubleConfirmButton": + mainModel.AddLog("干员冲突", "darkred"); + break; + + /* 肉鸽相关 */ + case "Roguelike1Start": + mainModel.AddLog("已开始探索 " + execTimes + " 次", "darkcyan"); + break; + + case "Roguelike1StageTraderInvestConfirm": + mainModel.AddLog("已投资 " + execTimes + " 个源石锭", "darkcyan"); + break; + + case "Roguelike1ExitThenAbandon": + mainModel.AddLog("已放弃本次探索"); + break; + + //case "Roguelike1StartAction": + // mainModel.AddLog("开始战斗"); + // break; + + case "Roguelike1MissionCompletedFlag": + mainModel.AddLog("战斗完成"); + break; + + case "Roguelike1MissionFailedFlag": + mainModel.AddLog("战斗失败"); + break; + + case "Roguelike1StageTraderEnter": + mainModel.AddLog("关卡:诡异行商"); + break; + + case "Roguelike1StageSafeHouseEnter": + mainModel.AddLog("关卡:安全的角落"); + break; + + case "Roguelike1StageEncounterEnter": + mainModel.AddLog("关卡:不期而遇/古堡馈赠"); + break; + + //case "Roguelike1StageBoonsEnter": + // mainModel.AddLog("古堡馈赠"); + // break; + + case "Roguelike1StageCambatDpsEnter": + mainModel.AddLog("关卡:普通作战"); + break; + + case "Roguelike1StageEmergencyDps": + mainModel.AddLog("关卡:紧急作战"); + break; + + case "Roguelike1StageDreadfulFoe": + mainModel.AddLog("关卡:险路恶敌"); + break; + + case "Roguelike1StageTraderInvestSystemFull": + mainModel.AddLog("投资达到上限", "darkcyan"); + break; + } + } + } + + private void procSubTaskCompleted(JObject details) + { + } + + private void procSubTaskExtraInfo(JObject details) + { + string taskChain = details["taskchain"].ToString(); + + if (taskChain == "Recruit") + { + procRecruitCalcMsg(details); + } + + string what = details["what"].ToString(); + var subTaskDetails = details["details"]; + + var mainModel = _container.Get(); + switch (what) + { + case "StageDrops": + { + string cur_drops = string.Empty; + JArray drops = (JArray)subTaskDetails["drops"]; + foreach (var item in drops) + { + string itemName = item["itemName"].ToString(); + int count = (int)item["quantity"]; + cur_drops += $"{itemName} : {count}\n"; + } + cur_drops = cur_drops.EndsWith("\n") ? cur_drops.TrimEnd('\n') : "无"; + mainModel.AddLog("当次掉落:\n" + cur_drops); + + string all_drops = string.Empty; + JArray statistics = (JArray)subTaskDetails["stats"]; + foreach (var item in statistics) + { + string itemName = item["itemName"].ToString(); + int count = (int)item["quantity"]; + all_drops += $"{itemName} : {count}\n"; + } + all_drops = all_drops.EndsWith("\n") ? all_drops.TrimEnd('\n') : "无"; + mainModel.AddLog("掉落统计:\n" + all_drops); + } + break; + + case "EnterFacility": + mainModel.AddLog("当前设施:" + subTaskDetails["facility"] + " " + (int)subTaskDetails["index"]); + break; + + case "RecruitTagsDetected": + { + JArray tags = (JArray)subTaskDetails["tags"]; + string log_content = string.Empty; + foreach (var tag_name in tags) + { + string tag_str = tag_name.ToString(); + log_content += tag_str + "\n"; + } + log_content = log_content.EndsWith("\n") ? log_content.TrimEnd('\n') : "错误"; + mainModel.AddLog("公招识别结果:\n" + log_content); + } + break; + + case "RecruitSpecialTag": + { + string special = subTaskDetails["tag"].ToString(); + using (var toast = new ToastNotification("公招提示")) + { + toast.AppendContentText(special).ShowRecruit(); + } + } + break; + + case "RecruitResult": + { + int level = (int)subTaskDetails["level"]; + if (level >= 5) + { + using (var toast = new ToastNotification($"公招出 {level} 星了哦!")) + { + toast.AppendContentText(new string('★', level)).ShowRecruit(row: 2); + } + mainModel.AddLog(level + " 星 Tags", "darkorange", "Bold"); + } + else + { + mainModel.AddLog(level + " 星 Tags", "darkcyan"); + } + } + break; + + case "RecruitTagsSelected": + { + JArray selected = (JArray)subTaskDetails["tags"]; + string selected_log = string.Empty; + foreach (var tag in selected) + { + selected_log += tag.ToString() + "\n"; + } + selected_log = selected_log.EndsWith("\n") ? selected_log.TrimEnd('\n') : "无"; + + mainModel.AddLog("选择 Tags:\n" + selected_log); + } + break; + + case "NotEnoughStaff": + { + mainModel.AddLog("可用干员不足", "darkred"); + } + break; + + /* Roguelike */ + case "StageInfo": + { + mainModel.AddLog("开始战斗:" + subTaskDetails["name"]); + } + break; + + case "StageInfoError": + { + mainModel.AddLog("关卡识别错误", "darkred"); + } + break; + + case "PenguinId": + { + var settings = _container.Get(); + if (settings.PenguinId == String.Empty) + { + string id = subTaskDetails["id"].ToString(); + settings.PenguinId = id; + //AsstSetPenguinId(id); + } + } + break; + } + } + + private void procRecruitCalcMsg(JObject details) + { + string what = details["what"].ToString(); + var subTaskDetails = details["details"]; + + var recruitModel = _container.Get(); + + switch (what) + { + case "RecruitTagsDetected": + { + JArray tags = (JArray)subTaskDetails["tags"]; + string info_content = "识别结果: "; + foreach (var tag_name in tags) + { + string tag_str = tag_name.ToString(); + info_content += tag_str + " "; + } + recruitModel.RecruitInfo = info_content; + } + break; + + case "RecruitSpecialTag": + { + string special = subTaskDetails["tag"].ToString(); + using (var toast = new ToastNotification("公招提示")) + { + toast.AppendContentText(special).ShowRecruit(); + } + } + break; + + case "RecruitResult": + { + string resultContent = string.Empty; + JArray result_array = (JArray)subTaskDetails["result"]; + int level = (int)subTaskDetails["level"]; + foreach (var combs in result_array) + { + int tag_level = (int)combs["level"]; + resultContent += tag_level + "星Tags: "; + foreach (var tag in (JArray)combs["tags"]) + { + resultContent += tag.ToString() + " "; + } + resultContent += "\n\t"; + foreach (var oper in (JArray)combs["opers"]) + { + resultContent += oper["level"].ToString() + " - " + oper["name"].ToString() + " "; + } + resultContent += "\n\n"; + } + recruitModel.RecruitResult = resultContent; + if (level >= 5) + { + using (var toast = new ToastNotification($"公招出 {level} 星了哦!")) + { + toast.AppendContentText(new string('★', level)).ShowRecruit(row: 2); + } + } + } + break; + } + } + + public bool AsstConnect() + { + var settings = _container.Get(); + if (settings.AdbPath == String.Empty || + settings.ConnectAddress == String.Empty) + { + return false; + } + else + { + return AsstConnect(_handle, settings.AdbPath, settings.ConnectAddress, settings.ConnectConfig); + } + } + + private bool AsstAppendTaskWithEncoding(string type, JObject task_params = null) + { + task_params = task_params ?? new JObject(); + return AsstAppendTask(_handle, type, JsonConvert.SerializeObject(task_params)) != 0; + } + + public bool AsstAppendFight(string stage, int max_medicine, int max_stone, int max_times) + { + var task_params = new JObject(); + task_params["stage"] = stage; + task_params["medicine"] = max_medicine; + task_params["stone"] = max_stone; + task_params["times"] = max_times; + task_params["report_to_penguin"] = true; + var settings = _container.Get(); + task_params["penguin_id"] = settings.PenguinId; + task_params["server"] = "CN"; + return AsstAppendTaskWithEncoding("Fight", task_params); + } + + public bool AsstAppendAward() + { + return AsstAppendTaskWithEncoding("Award"); + } + + public bool AsstAppendStartUp() + { + return AsstAppendTaskWithEncoding("StartUp"); + } + + public bool AsstAppendVisit() + { + return AsstAppendTaskWithEncoding("Visit"); + } + + public bool AsstAppendMall(bool with_shopping, string[] firstlist, string[] blacklist) + { + var task_params = new JObject(); + task_params["shopping"] = with_shopping; + task_params["buy_first"] = new JArray { firstlist }; + task_params["blacklist"] = new JArray { blacklist }; + return AsstAppendTaskWithEncoding("Mall", task_params); + } + + public bool AsstAppendRecruit(int max_times, int[] select_level, int required_len, int[] confirm_level, int confirm_len, bool need_refresh, bool use_expedited) + { + var task_params = new JObject(); + task_params["refresh"] = need_refresh; + task_params["select"] = new JArray(select_level); + task_params["confirm"] = new JArray(confirm_level); + task_params["times"] = max_times; + task_params["set_time"] = true; + task_params["expedite"] = use_expedited; + task_params["expedite_times"] = max_times; + return AsstAppendTaskWithEncoding("Recruit", task_params); + } + + public bool AsstAppendInfrast(int work_mode, string[] order, int order_len, string uses_of_drones, double dorm_threshold) + { + var task_params = new JObject(); + //task_params["mode"] = 0; + task_params["facility"] = new JArray(order); + task_params["drones"] = uses_of_drones; + task_params["threshold"] = dorm_threshold; + task_params["replenish"] = true; + return AsstAppendTaskWithEncoding("Infrast", task_params); + } + + public bool AsstAppendRoguelike(int mode) + { + var task_params = new JObject(); + task_params["mode"] = mode; + task_params["opers"] = new JArray { + new JObject { { "name", "山" }, { "skill", 2 }, { "skill_usage", 2 } }, + new JObject { { "name", "棘刺" }, { "skill", 3 }, { "skill_usage", 1 } }, + new JObject { { "name", "芙蓉" }, { "skill", 1 }, { "skill_usage", 1 } }, + new JObject { { "name", "梓兰" }, { "skill", 1 }, { "skill_usage", 1 } }, + }; + return AsstAppendTaskWithEncoding("Roguelike", task_params); + } + + public bool AsstStartRecruitCalc(int[] select_level, int required_len, bool set_time) + { + var task_params = new JObject(); + task_params["refresh"] = false; + task_params["select"] = new JArray(select_level); + task_params["confirm"] = new JArray(); + task_params["times"] = 0; + task_params["set_time"] = true; + task_params["expedite"] = false; + task_params["expedite_times"] = 0; + return AsstAppendTaskWithEncoding("Recruit", task_params); + } + + public bool AsstStart() + { + return AsstStart(_handle); + } + + public bool AsstStop() + { + return AsstStop(_handle); + } + } + + public enum AsstMsg + { + /* Global Info */ + InternalError = 0, // 内部错误 + InitFailed, // 初始化失败 + ConnectionError, // 连接相关错误 + AllTasksCompleted, // 全部任务完成 + /* TaskChain Info */ + TaskChainError = 10000, // 任务链执行/识别错误 + TaskChainStart, // 任务链开始 + TaskChainCompleted, // 任务链完成 + TaskChainExtraInfo, // 任务链额外信息 + /* SubTask Info */ + SubTaskError = 20000, // 原子任务执行/识别错误 + SubTaskStart, // 原子任务开始 + SubTaskCompleted, // 原子任务完成 + SubTaskExtraInfo // 原子任务额外信息 + }; +} diff --git a/src/MeoAsstGui/Helper/ScrollViewerBinding.cs b/src/MeoAsstGui/Helper/ScrollViewerBinding.cs index fe2913ed6b..ef67fdf86e 100644 --- a/src/MeoAsstGui/Helper/ScrollViewerBinding.cs +++ b/src/MeoAsstGui/Helper/ScrollViewerBinding.cs @@ -224,7 +224,6 @@ namespace MeoAsstGui private static void BindRectangleVerticalOffsetList(ScrollViewer scrollViewer) { - if (scrollViewer.GetValue(RectangleVerticalOffsetListBindingProperty) != null) return; @@ -257,6 +256,5 @@ namespace MeoAsstGui } #endregion RectangleVerticalOffsetList attached property - } } diff --git a/src/MeoAsstGui/Helper/ToastNotification.cs b/src/MeoAsstGui/Helper/ToastNotification.cs index 86a4a8d80c..944bdf7964 100644 --- a/src/MeoAsstGui/Helper/ToastNotification.cs +++ b/src/MeoAsstGui/Helper/ToastNotification.cs @@ -88,7 +88,7 @@ namespace MeoAsstGui // 最大显示宽度 NotificationConstants.MaxWidth = 460d; - #endregion + #endregion 初始化 Notification.Wpf 默认静态配置 } /// @@ -130,7 +130,7 @@ namespace MeoAsstGui None } - #endregion + #endregion 通知提示音列表枚举 /// /// 播放通知提示音 @@ -180,19 +180,23 @@ namespace MeoAsstGui } } - #endregion + #endregion 通知提示音 #region 通知按钮设置 #region 通知按钮变量 + // 左边按钮 protected string _buttonLeftText = null; + protected Action _buttonLeftAction = null; // 右边按钮 protected string _buttonRightText = null; + protected Action _buttonRightAction = null; - #endregion + + #endregion 通知按钮变量 /// /// 给通知添加一个在左边的按钮,比如确定按钮,多次设置只会按最后一次设置生效 @@ -220,7 +224,7 @@ namespace MeoAsstGui return this; } - #endregion + #endregion 通知按钮设置 #region 通知显示 @@ -279,7 +283,7 @@ namespace MeoAsstGui return content; } - #endregion + #endregion 通知基本字体样式和内容模板 #region 显示通知方法 @@ -373,9 +377,9 @@ namespace MeoAsstGui notificationContent: content); } - #endregion + #endregion 显示通知方法 - #endregion + #endregion 通知显示 #region 任务栏闪烁 @@ -457,7 +461,7 @@ namespace MeoAsstGui return FlashWindowEx(ref fInfo); } - #endregion + #endregion 任务栏闪烁 /// /// 通知使用完后释放已使用的数据 @@ -472,6 +476,5 @@ namespace MeoAsstGui _buttonLeftText = _buttonRightText = null; _buttonLeftAction = _buttonRightAction = null; } - } } diff --git a/src/MeoAsstGui/Helper/ViewStatusStorage.cs b/src/MeoAsstGui/Helper/ViewStatusStorage.cs index f6749dc442..37afa53517 100644 --- a/src/MeoAsstGui/Helper/ViewStatusStorage.cs +++ b/src/MeoAsstGui/Helper/ViewStatusStorage.cs @@ -1,87 +1,84 @@ -// MeoAsstGui - A part of the MeoAssistantArknights project -// Copyright (C) 2021 MistEO and Contributors -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY - -using System; -using System.IO; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; - -namespace MeoAsstGui -{ - // 界面设置存储(读写json文件) - public class ViewStatusStorage - { - private static readonly string _configFilename = System.Environment.CurrentDirectory + "\\gui.json"; - private static JObject _viewStatus = new JObject(); - - public static string Get(string key, string defalut_value) - { - if (_viewStatus.ContainsKey(key)) - { - return _viewStatus[key].ToString(); - } - else - { - return defalut_value; - } - } - - public static void Set(string key, string value) - { - _viewStatus[key] = value; - Save(); - } - - public static bool Load() - { - if (File.Exists(_configFilename)) - { - try - { - using (StreamReader sr = new StreamReader(_configFilename)) - { - string jsonStr = sr.ReadToEnd(); - - // 文件存在但为空,会读出来一个null,感觉c#这库有bug,如果是null 就赋值一个空JObject - _viewStatus = (JObject)JsonConvert.DeserializeObject(jsonStr) ?? new JObject(); - } - } - catch (Exception) - { - _viewStatus = new JObject(); - return false; - } - } - else - { - _viewStatus = new JObject(); - return false; - } - return true; - } - - public static bool Save() - { - try - { - using (StreamWriter sw = new StreamWriter(_configFilename)) - { - sw.Write(_viewStatus.ToString()); - } - } - catch (Exception) - { - return false; - } - return true; - } - } -} +// MeoAsstGui - A part of the MeoAssistantArknights project +// Copyright (C) 2021 MistEO and Contributors +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY + +using System; +using System.IO; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace MeoAsstGui +{ + // 界面设置存储(读写json文件) + public class ViewStatusStorage + { + private static readonly string _configFilename = System.Environment.CurrentDirectory + "\\gui.json"; + private static JObject _viewStatus = new JObject(); + + public static string Get(string key, string defalut_value) + { + if (_viewStatus.ContainsKey(key)) + { + return _viewStatus[key].ToString(); + } + else + { + return defalut_value; + } + } + + public static void Set(string key, string value) + { + _viewStatus[key] = value; + Save(); + } + + public static bool Load() + { + if (File.Exists(_configFilename)) + { + try + { + string jsonStr = File.ReadAllText(_configFilename); + + // 文件存在但为空,会读出来一个null,感觉c#这库有bug,如果是null 就赋值一个空JObject + _viewStatus = (JObject)JsonConvert.DeserializeObject(jsonStr) ?? new JObject(); + } + catch (Exception) + { + _viewStatus = new JObject(); + return false; + } + } + else + { + _viewStatus = new JObject(); + return false; + } + return true; + } + + public static bool Save() + { + try + { + using (StreamWriter sw = new StreamWriter(_configFilename)) + { + sw.Write(_viewStatus.ToString()); + } + } + catch (Exception) + { + return false; + } + return true; + } + } +} diff --git a/src/MeoAsstGui/UserControl/FightSettingsUserControl.xaml b/src/MeoAsstGui/UserControl/FightSettingsUserControl.xaml index b639be1276..0d39d07b11 100644 --- a/src/MeoAsstGui/UserControl/FightSettingsUserControl.xaml +++ b/src/MeoAsstGui/UserControl/FightSettingsUserControl.xaml @@ -24,7 +24,7 @@ - + diff --git a/src/MeoAsstGui/UserControl/MallSettingsUserControl.xaml b/src/MeoAsstGui/UserControl/MallSettingsUserControl.xaml index 001119dad0..d52648ce08 100644 --- a/src/MeoAsstGui/UserControl/MallSettingsUserControl.xaml +++ b/src/MeoAsstGui/UserControl/MallSettingsUserControl.xaml @@ -8,9 +8,23 @@ mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="550"> - - + + + + + + Content=" 信用购物 " /> + + + + + + + + \ No newline at end of file diff --git a/src/MeoAsstGui/UserControl/ToastSettingsUserControl.xaml b/src/MeoAsstGui/UserControl/ToastSettingsUserControl.xaml index b4bff8d5cc..d01a5d5c0b 100644 --- a/src/MeoAsstGui/UserControl/ToastSettingsUserControl.xaml +++ b/src/MeoAsstGui/UserControl/ToastSettingsUserControl.xaml @@ -86,7 +86,6 @@ VerticalAlignment="Bottom" Content="↘ 右下" IsChecked="{Binding ToastPositionBottomRight}" /> -