diff --git a/include/AsstCaller.h b/include/AsstCaller.h index 4ecc59743a..51216a1f3e 100644 --- a/include/AsstCaller.h +++ b/include/AsstCaller.h @@ -19,9 +19,9 @@ extern "C" { bool MEOAPI AsstStartSanity(void* p_asst); bool MEOAPI AsstStartVisit(void* p_asst, bool with_shopping); bool MEOAPI AsstStartProcessTask(void* p_asst, const char* task); - bool MEOAPI AsstStartOpenRecruit(void* p_asst, const int required_level[], int required_len, bool set_time); - bool MEOAPI AsstStartIndertifyOpers(void* p_asst); - bool MEOAPI AsstStartInfrast(void* p_asst); + bool MEOAPI AsstStartRecruiting(void* p_asst, const int required_level[], int required_len, bool set_time); + //bool MEOAPI AsstStartIndertifyOpers(void* p_asst); + //bool MEOAPI AsstStartInfrast(void* p_asst); bool MEOAPI AsstStartDebugTask(void* p_asst); void MEOAPI AsstStop(void* p_asst); diff --git a/resource/config.json b/resource/config.json index 145a440a0a..911ceaf2d8 100644 --- a/resource/config.json +++ b/resource/config.json @@ -21,10 +21,6 @@ "ocrThreadNumber": 4, "ocrThreadNumber_Doc": "文字识别库OcrLite的线程数量,理论上开的高点识别会快点,但是会更卡。默认4" }, - "infrastOptions": { - "dormThreshold": 0.3, - "dormThreshold_Doc": "宿舍心情百分比阈值,心情百分比小于该值的干员会被放进宿舍。取值范围(0, 1.0),默认0.3" - }, "emulator_Doc": "下面的和模拟器窗口捕获逻辑有关,不需要修改", "emulator": { "BlueStacks": { @@ -150,74 +146,5 @@ "screencap": "[Adb] exec-out screencap -p" } } - }, - "ocrReplace_Doc": "下面为常见的文字识别错误纠正,不需要修改", - "recruitOcrReplace": [ - [ - "沮击", - "狙击" - ], - [ - "犯击", - "狙击" - ], - [ - "泪击", - "狙击" - ], - [ - "都出", - "输出" - ], - [ - "都乐", - "输出" - ], - [ - "抓出", - "输出" - ], - [ - "都任", - "输出" - ], - [ - "新于", - "新手" - ], - [ - "防拍", - "防护" - ] - ], - "infrastOcrReplace": [ - [ - "蛇居箱", - "蛇屠箱" - ], - [ - "叫米", - "古米" - ], - [ - "节草", - "苇草" - ], - [ - "粹兰", - "梓兰" - ], - [ - "艾丝菜尔", - "艾丝黛尔" - ], - [ - "艾丝莱尔", - "艾丝黛尔" - ], - [ - ",斑点", - "斑点" - ] - ] + } } \ No newline at end of file diff --git a/resource/infrast.json b/resource/infrast.json deleted file mode 100644 index e423d1b324..0000000000 --- a/resource/infrast.json +++ /dev/null @@ -1,1043 +0,0 @@ -{ - "infrast": [ - { - "facility": "DogFood", - "Doc": "制造站-狗粮", - "combs": [ - { - "opers": [ - { - "name": "刻俄柏", - "elite": 2 - }, - { - "name": "稀音", - "elite": 2 - }, - { - "name": "红云", - "elite": 1 - } - ], - "efficiency": 105 - }, - { - "opers": [ - { - "name": "贝娜", - "elite": 0 - }, - { - "name": "泡泡", - "elite": 1 - }, - { - "name": "火神", - "elite": 2 - } - ], - "efficiency": 93 - }, - { - "opers": [ - { - "name": "温蒂", - "elite": 2 - }, - { - "name": "异客", - "elite": 2 - }, - { - "name": "森蚺", - "elite": 2 - } - ], - "efficiency": 90 - }, - { - "opers": [ - { - "name": "槐琥", - "elite": 2 - } - ], - "efficiency": 40 - }, - { - "opers": [ - { - "name": "食铁兽", - "elite": 2 - } - ], - "efficiency": 35 - }, - { - "opers": [ - { - "name": "断罪者", - "elite": 2 - } - ], - "efficiency": 35 - }, - { - "opers": [ - { - "name": "白雪", - "elite": 1 - } - ], - "efficiency": 30 - }, - { - "opers": [ - { - "name": "霜叶", - "elite": 1 - } - ], - "efficiency": 30 - }, - { - "opers": [ - { - "name": "红豆", - "elite": 0 - } - ], - "efficiency": 30 - }, - { - "opers": [ - { - "name": "Castle-3", - "elite": 0 - } - ], - "efficiency": 30 - }, - { - "opers": [ - { - "name": "梅尔", - "elite": 2 - } - ], - "efficiency": 30 - }, - { - "opers": [ - { - "name": "帕拉斯", - "elite": 2 - } - ], - "efficiency": 25 - }, - { - "opers": [ - { - "name": "水月", - "elite": 2 - } - ], - "efficiency": 25 - }, - { - "opers": [ - { - "name": "白面鸮", - "elite": 2 - } - ], - "efficiency": 25 - }, - { - "opers": [ - { - "name": "赫默", - "elite": 2 - } - ], - "efficiency": 25 - }, - { - "opers": [ - { - "name": "杰西卡", - "elite": 0 - } - ], - "efficiency": 25 - }, - { - "opers": [ - { - "name": "史都华德", - "elite": 1 - } - ], - "efficiency": 25 - }, - { - "opers": [ - { - "name": "香草", - "elite": 0 - } - ], - "efficiency": 25 - }, - { - "opers": [ - { - "name": "调香师", - "elite": 1 - } - ], - "efficiency": 25 - }, - { - "opers": [ - { - "name": "石棉", - "elite": 0 - } - ], - "efficiency": 25 - }, - { - "opers": [ - { - "name": "泡普卡", - "elite": 0 - } - ], - "efficiency": 25 - }, - { - "opers": [ - { - "name": "芬", - "elite": 0 - } - ], - "efficiency": 23 - }, - { - "opers": [ - { - "name": "克洛斯", - "elite": 0 - } - ], - "efficiency": 20 - }, - { - "opers": [ - { - "name": "豆苗", - "elite": 0 - } - ], - "efficiency": 15 - }, - { - "opers": [ - { - "name": "流星", - "elite": 0 - } - ], - "efficiency": 15 - }, - { - "opers": [ - { - "name": "夜刀", - "elite": 0 - } - ], - "efficiency": 15 - }, - { - "opers": [ - { - "name": "蛇屠箱", - "elite": 0 - } - ], - "efficiency": 10 - }, - { - "opers": [ - { - "name": "黑角", - "elite": 0 - } - ], - "efficiency": 10 - }, - { - "opers": [ - { - "name": "卡缇", - "elite": 0 - } - ], - "efficiency": 10 - }, - { - "opers": [ - { - "name": "米格鲁", - "elite": 0 - } - ], - "efficiency": 10 - } - ], - "endFlag": [ - "安洁莉娜", - "嵯峨", - "风笛", - "赫拉格", - "棘刺", - "假日威龙陈", - "卡涅利安", - "傀影", - "铃兰", - "塞雷娅", - "闪灵", - "史尔特尔", - "斯卡蒂", - "夜莺", - "推进之王", - "星熊", - "银灰", - "浊心斯卡蒂", - "歌蕾蒂娅", - "莫斯提马", - "早露", - "瑕光", - "阿米娅" - ], - "endFlag_Doc": "识别到这里面的名字,就不继续往后识别了,一般用列表里的最后一个人名" - }, - { - "facility": "PureGold", - "Doc": "制造站-赤金", - "combs": [ - { - "opers": [ - { - "name": "贝娜", - "elite": 0 - }, - { - "name": "泡泡", - "elite": 1 - }, - { - "name": "火神", - "elite": 2 - } - ], - "efficiency": 93 - }, - { - "opers": [ - { - "name": "温蒂", - "elite": 2 - }, - { - "name": "异客", - "elite": 2 - }, - { - "name": "森蚺", - "elite": 2 - } - ], - "efficiency": 90 - }, - { - "opers": [ - { - "name": "砾", - "elite": 2 - } - ], - "efficiency": 35 - }, - { - "opers": [ - { - "name": "斑点", - "elite": 0 - } - ], - "efficiency": 30 - }, - { - "opers": [ - { - "name": "夜烟", - "elite": 0 - } - ], - "efficiency": 30 - }, - { - "opers": [ - { - "name": "槐琥", - "elite": 2 - } - ], - "efficiency": 40 - }, - { - "opers": [ - { - "name": "梅尔", - "elite": 2 - } - ], - "efficiency": 30 - }, - { - "opers": [ - { - "name": "水月", - "elite": 2 - } - ], - "efficiency": 25 - }, - { - "opers": [ - { - "name": "白面鸮", - "elite": 2 - } - ], - "efficiency": 25 - }, - { - "opers": [ - { - "name": "赫默", - "elite": 2 - } - ], - "efficiency": 25 - }, - { - "opers": [ - { - "name": "杰西卡", - "elite": 0 - } - ], - "efficiency": 25 - }, - { - "opers": [ - { - "name": "史都华德", - "elite": 1 - } - ], - "efficiency": 25 - }, - { - "opers": [ - { - "name": "香草", - "elite": 0 - } - ], - "efficiency": 25 - }, - { - "opers": [ - { - "name": "调香师", - "elite": 1 - } - ], - "efficiency": 25 - }, - { - "opers": [ - { - "name": "石棉", - "elite": 0 - } - ], - "efficiency": 25 - }, - { - "opers": [ - { - "name": "泡普卡", - "elite": 0 - } - ], - "efficiency": 25 - }, - { - "opers": [ - { - "name": "芬", - "elite": 0 - } - ], - "efficiency": 23 - }, - { - "opers": [ - { - "name": "克洛斯", - "elite": 0 - } - ], - "efficiency": 20 - }, - { - "opers": [ - { - "name": "豆苗", - "elite": 0 - } - ], - "efficiency": 15 - }, - { - "opers": [ - { - "name": "流星", - "elite": 0 - } - ], - "efficiency": 15 - }, - { - "opers": [ - { - "name": "夜刀", - "elite": 0 - } - ], - "efficiency": 15 - }, - { - "opers": [ - { - "name": "蛇屠箱", - "elite": 0 - } - ], - "efficiency": 10 - }, - { - "opers": [ - { - "name": "黑角", - "elite": 0 - } - ], - "efficiency": 10 - }, - { - "opers": [ - { - "name": "卡缇", - "elite": 0 - } - ], - "efficiency": 10 - }, - { - "opers": [ - { - "name": "米格鲁", - "elite": 0 - } - ], - "efficiency": 10 - } - ], - "endFlag": [ - "安洁莉娜", - "嵯峨", - "风笛", - "赫拉格", - "棘刺", - "假日威龙陈", - "卡涅利安", - "傀影", - "铃兰", - "塞雷娅", - "闪灵", - "史尔特尔", - "斯卡蒂", - "夜莺", - "推进之王", - "星熊", - "银灰", - "浊心斯卡蒂", - "歌蕾蒂娅", - "莫斯提马", - "早露", - "瑕光", - "阿米娅" - ], - "endFlag_Doc": "识别到这里面的名字,就不继续往后识别了,一般用列表里的最后一个人名" - }, - { - "facility": "TradeMoney", - "Doc": "贸易站-龙门币", - "combs": [ - { - "opers": [ - { - "name": "巫恋", - "elite": 2 - }, - { - "name": "龙舌兰", - "elite": 2 - }, - { - "name": "卡夫卡", - "elite": 2 - } - ], - "efficiency": 150, - "Doc": "这三个有效率加成,不知道怎么算的,反正很高,先按150写" - }, - { - "opers": [ - { - "name": "巫恋", - "elite": 2 - }, - { - "name": "龙舌兰", - "elite": 2 - }, - { - "name": "柏喙", - "elite": 2 - } - ], - "efficiency": 150, - "Doc": "这三个有效率加成,不知道怎么算的,反正很高,先按150写" - }, - { - "opers": [ - { - "name": "能天使", - "elite": 2 - }, - { - "name": "拉普兰德", - "elite": 2 - }, - { - "name": "德克萨斯", - "elite": 2 - } - ], - "efficiency": 100 - }, - { - "opers": [ - { - "name": "空弦", - "elite": 2 - } - ], - "efficiency": 40 - }, - { - "opers": [ - { - "name": "能天使", - "elite": 2 - } - ], - "efficiency": 35 - }, - { - "opers": [ - { - "name": "雪雉", - "elite": 2 - } - ], - "efficiency": 35 - }, - { - "opers": [ - { - "name": "古米", - "elite": 0 - } - ], - "efficiency": 30 - }, - { - "opers": [ - { - "name": "空爆", - "elite": 0 - } - ], - "efficiency": 30 - }, - { - "opers": [ - { - "name": "月见夜", - "elite": 0 - } - ], - "efficiency": 30 - }, - { - "opers": [ - { - "name": "空", - "elite": 2 - } - ], - "efficiency": 30 - }, - { - "opers": [ - { - "name": "安比尔", - "elite": 1 - } - ], - "efficiency": 30 - }, - { - "opers": [ - { - "name": "缠丸", - "elite": 1 - } - ], - "efficiency": 30 - }, - { - "opers": [ - { - "name": "芬", - "elite": 1 - } - ], - "efficiency": 30 - }, - { - "opers": [ - { - "name": "芬", - "elite": 1 - } - ], - "efficiency": 30 - }, - { - "opers": [ - { - "name": "慕斯", - "elite": 0 - } - ], - "efficiency": 30 - }, - { - "opers": [ - { - "name": "夜刀", - "elite": 0 - } - ], - "efficiency": 30 - }, - { - "opers": [ - { - "name": "夜烟", - "elite": 1 - } - ], - "efficiency": 30 - }, - { - "opers": [ - { - "name": "玫兰莎", - "elite": 0 - } - ], - "efficiency": 25 - }, - { - "opers": [ - { - "name": "梓兰", - "elite": 0 - } - ], - "efficiency": 25 - }, - { - "opers": [ - { - "name": "远山", - "elite": 0 - } - ], - "efficiency": 25 - } - ], - "endFlag": [ - "安洁莉娜", - "嵯峨", - "风笛", - "赫拉格", - "棘刺", - "假日威龙陈", - "卡涅利安", - "傀影", - "铃兰", - "塞雷娅", - "闪灵", - "史尔特尔", - "斯卡蒂", - "夜莺", - "推进之王", - "星熊", - "浊心斯卡蒂", - "歌蕾蒂娅", - "莫斯提马", - "早露", - "瑕光", - "阿米娅" - ], - "endFlag_Doc": "识别到这里面的名字,就不继续往后识别了,一般用列表里的最后一个人名" - } - ], - "allNames": [ - "桃金娘", - "食铁兽", - "断罪者", - "白雪", - "Castle-3", - "霜叶", - "红豆", - "帕拉斯", - "砾", - "夜烟", - "斑点", - "清流", - "迷迭香", - "槐琥", - "梅尔", - "赫默", - "白面鸮", - "水月", - "调香师", - "杰西卡", - "史都华德", - "香草", - "石棉", - "泡普卡", - "芬", - "克洛丝", - "豆苗", - "流星", - "夜刀", - "温蒂", - "森蚺", - "异客", - "蛇屠箱", - "黑角", - "卡缇", - "米格鲁", - "火神", - "贝娜", - "卡达", - "稀音", - "泡泡", - "刻俄柏", - "红云", - "艾雅法拉", - "炎熔", - "月见夜", - "安洁莉娜", - "夜莺", - "嵯峨", - "风笛", - "赫拉格", - "黑", - "煌", - "棘刺", - "卡涅利安", - "傀影", - "铃兰", - "泥岩", - "塞雷娅", - "山", - "史尔特尔", - "闪灵", - "斯卡蒂", - "推进之王", - "星熊", - "银灰", - "浊心斯卡蒂", - "W", - "歌蕾蒂娅", - "假日威龙陈", - "空弦", - "麦哲伦", - "莫斯提马", - "年", - "早露", - "阿", - "夕", - "瑕光", - "阿米娅", - "幽灵鲨", - "白金", - "柏喙", - "鞭刃", - "华法琳", - "极境", - "贾维", - "空", - "临光", - "狮蝎", - "星极", - "陨星", - "真理", - "初雪", - "格劳克斯", - "凛冬", - "送葬人", - "苇草", - "爱丽丝", - "蓝毒", - "天火", - "锡兰", - "罗宾", - "特米米", - "图耶", - "雪雉", - "炎狱炎熔", - "羽毛笔", - "嘉维尔", - "末药", - "安比尔", - "暗索", - "缠丸", - "古米", - "坚雷", - "孑", - "刻刀", - "猎蜂", - "梅", - "苏苏洛", - "讯使", - "宴", - "远山", - "玫兰莎", - "空爆", - "安德切尔", - "安赛尔", - "芙蓉", - "翎羽", - "梓兰", - "安哲拉", - "奥斯塔", - "拜松", - "暴行", - "暴雨", - "薄绿", - "布洛卡", - "赤冬", - "断崖", - "芙兰卡", - "格拉尼", - "吽", - "灰喉", - "惊蛰", - "可颂", - "苦艾", - "莱恩哈特", - "蜜蜡", - "普罗旺斯", - "绮良", - "熔泉", - "慑砂", - "诗怀雅", - "守林人", - "四月", - "燧石", - "微风", - "乌有", - "絮雨", - "崖心", - "亚叶", - "炎客", - "夜魔", - "月禾", - "铸铁", - "艾丝黛尔", - "波登可", - "地灵", - "杜宾", - "芳汀", - "角峰", - "杰克", - "慕斯", - "清道夫", - "深靛", - "深海色", - "松果", - "酸糖", - "12F", - "杜林", - "巡林者", - "Lancet-2", - "闪击", - "战车", - "红", - "卡夫卡", - "龙舌兰", - "巫恋", - "阿消", - "雷蛇", - "伊桑", - "陈", - "灰烬", - "凯尔希", - "霜华", - "拉普兰德", - "格雷伊", - "能天使", - "德克萨斯", - "因陀罗", - "伊芙利特", - "THRM-EX" - ] -} \ No newline at end of file diff --git a/resource/tasks.json b/resource/tasks.json index a61a059ad3..f2c53f4bec 100644 --- a/resource/tasks.json +++ b/resource/tasks.json @@ -20,7 +20,6 @@ ] }, "UsePrts": { - "template": "UsePrts.png", "templThreshold": 0.8, "action": "clickSelf", "next": [ @@ -28,8 +27,16 @@ ] }, "StartButton1": { - "template": "StartButton1.png", - "templThreshold": 0.75, + "algorithm": "OcrDetect", + "text": [ + "开始行动" + ], + "roi": [ + 800, + 400, + 480, + 320 + ], "action": "clickSelf", "next": [ "StartButton2", @@ -38,7 +45,6 @@ ] }, "StartButton2": { - "template": "StartButton2.png", "action": "clickSelf", "rearDelay": 20000, "templThreshold": 0.95, @@ -54,7 +60,7 @@ "剩余可放置角色", "接管作战" ], - "identifyArea": [ + "roi": [ 0, 530, 1279, @@ -84,7 +90,7 @@ "ClickCorner_Doc": "点击屏幕右边,不会点到掉落物品,且不会关掉关卡选择的一块区域", "algorithm": "justreturn", "action": "clickRect", - "specificArea": [ + "specificRect": [ 1000, 1, 270, @@ -92,7 +98,6 @@ ], "next": [ "EndOfAction", - "Loading", "StartButton1", "StartButton2", "UseMedicine", @@ -117,14 +122,13 @@ "algorithm": "justreturn", "action": "clickRect", "rearDelay": 2000, - "specificArea": [ + "specificRect": [ 1000, 1, 270, 340 ], "next": [ - "Loading", "StartButton1", "StartButton2", "UseMedicine", @@ -132,23 +136,13 @@ "EndOfAction" ] }, - "Loading": { - "template": "Loading.png", - "templThreshold": 0.8, - "action": "doNothing", - "next": [ - "StartButton1" - ] - }, "UseMedicine": { - "template": "UseMedicine.png", "action": "doNothing", "next": [ "MedicineConfirm" ] }, "MedicineConfirm": { - "template": "MedicineConfirm.png", "action": "clickSelf", "maxTimes": 0, "reduceOtherTimes": [ @@ -159,7 +153,6 @@ ] }, "UseStone": { - "template": "UseStone.png", "action": "doNothing", "next": [ "StoneConfirm" @@ -177,7 +170,6 @@ ] }, "PrtsErrorConfirm": { - "template": "PrtsErrorConfirm.png", "templThreshold": 0.8, "cache": false, "action": "doNothing", @@ -187,13 +179,11 @@ ] }, "AbandonAction": { - "template": "AbandonAction.png", "action": "clickSelf", "cache": false, "reduceOtherTimes": [ "StartButton1", - "StartButton2", - "Loading" + "StartButton2" ], "next": [ "EndOfAction", @@ -213,13 +203,11 @@ ] }, "OfflineConfirm": { - "template": "OfflineConfirm.png", "action": "clickSelf", "cache": false, "reduceOtherTimes": [ "StartButton1", - "StartButton2", - "Loading" + "StartButton2" ], "next": [ "CloseAnno", @@ -228,7 +216,6 @@ ] }, "StartToWakeUp": { - "template": "StartToWakeUp.png", "action": "clickSelf", "cache": false, "next": [ @@ -239,7 +226,6 @@ ] }, "CloseAnno": { - "template": "CloseAnno.png", "action": "clickSelf", "cache": false, "next": [ @@ -249,7 +235,6 @@ ] }, "Terminal": { - "template": "Terminal.png", "cache": false, "action": "clickSelf", "next": [ @@ -265,7 +250,7 @@ "今日配给" ], "action": "clickRect", - "specificArea": [ + "specificRect": [ 1000, 1, 270, @@ -312,7 +297,6 @@ ] }, "Friends": { - "template": "Friends.png", "templThreshold": 0.85, "action": "clickSelf", "next": [ @@ -321,7 +305,6 @@ ] }, "FriendsList": { - "template": "FriendsList.png", "action": "clickSelf", "next": [ "StartToVisit", @@ -329,14 +312,12 @@ ] }, "NoFriends": { - "template": "NoFriends.png", "action": "doNothing", "next": [ "ReturnToMall" ] }, "StartToVisit": { - "template": "StartToVisit.png", "templThreshold": 0.8, "action": "clickSelf", "rearDelay": 3000, @@ -347,11 +328,10 @@ ] }, "VisitNext": { - "template": "VisitNext.png", "action": "clickSelf", "cache": false, "rearDelay": 2000, - "identifyArea": [ + "roi": [ 1080, 570, 195, @@ -374,7 +354,7 @@ ], "action": "clickSelf", "rearDelay": 2000, - "identifyArea": [ + "roi": [ 1080, 570, 195, @@ -411,7 +391,6 @@ ] }, "Mall": { - "template": "Mall.png", "action": "clickSelf", "next": [ "CreditStore", @@ -419,7 +398,6 @@ ] }, "CreditStore": { - "template": "CreditStore.png", "templThreshold": 0.85, "rearDelay": 1000, "action": "clickSelf", @@ -433,7 +411,7 @@ "text": [ "信用交易所" ], - "identifyArea": [ + "roi": [ 1000, 0, 280, @@ -447,7 +425,6 @@ ] }, "CollectCredit": { - "template": "CollectCredit.png", "action": "clickSelf", "rearDelay": 2000, "next": [ @@ -457,7 +434,7 @@ "CloseCollectCredit": { "algorithm": "justReturn", "action": "clickRect", - "specificArea": [ + "specificRect": [ 1000, 1, 270, @@ -474,7 +451,7 @@ "已达上限" ], "action": "doNothing", - "identifyArea": [ + "roi": [ 900, 50, 375, @@ -485,9 +462,8 @@ ] }, "VisitNextBlack": { - "template": "VisitNextBlack.png", "action": "doNothing", - "identifyArea": [ + "roi": [ 1080, 570, 195, @@ -497,6 +473,30 @@ "ReturnToMall" ] }, + "CreditShop-CreditPoint": { + "template": "CreditPoint.png" + }, + "CreditShop-SoldOut": { + "template": "SoldOut.png" + }, + "CreditShop-BuyIt": { + "template": "BuyIt.png", + "preDelay": 1000, + "rareDelay": 1000 + }, + "CreditShop-NoMoney": { + "algorithm": "OcrDetect", + "text": [ + "信用不足", + "无法购买" + ], + "roi": [ + 940, + 60, + 339, + 110 + ] + }, "Stop": { "algorithm": "justreturn", "action": "stop", @@ -505,22 +505,60 @@ "RecruitTime": { "template": "RecruitTimeReduce.png", "templThreshold": 0.89, - "action": "clickRect", - "specificArea": [ - 391, - 279, + "action": "clickSelf", + "resultMove": [ + 7, + 94, 129, 44 - ], - "next": [ - "Stop" ] }, - "Listless": { - "template": "Listless.png", - "action": "clickSelf", - "next": [ - "Stop" + "RecruitTags": { + "algorithm": "OcrDetect", + "text": [], + "roi": [ + 200, + 200, + 800, + 500 + ], + "ocrReplace": [ + [ + "沮击", + "狙击" + ], + [ + "犯击", + "狙击" + ], + [ + "泪击", + "狙击" + ], + [ + "都出", + "输出" + ], + [ + "都乐", + "输出" + ], + [ + "抓出", + "输出" + ], + [ + "都任", + "输出" + ], + [ + "新于", + "新手" + ], + [ + "防拍", + "防护" + ] ] }, "OperatorBegin": { @@ -532,7 +570,6 @@ ] }, "EnterOperator": { - "template": "EnterOperator.png", "rareDelay": 1000, "templThreshold": 0.7, "action": "clickSelf", @@ -575,7 +612,6 @@ ] }, "EnterInfrast": { - "template": "EnterInfrast.png", "templThreshold": 0.85, "histThreshold": 0.85, "rareDelay": 3000, @@ -601,7 +637,6 @@ ] }, "Trade": { - "template": "Trade.png", "templThreshold": 0.8, "cache": false, "action": "clickSelf", @@ -611,7 +646,6 @@ ] }, "TradeMini": { - "template": "TradeMini.png", "templThreshold": 0.8, "cache": false, "action": "clickSelf", @@ -621,7 +655,6 @@ ] }, "Manufacturing": { - "template": "Manufacturing.png", "templThreshold": 0.8, "cache": false, "action": "clickSelf", @@ -631,7 +664,6 @@ ] }, "ManufacturingMini": { - "template": "ManufacturingMini.png", "templThreshold": 0.8, "cache": false, "action": "clickSelf", @@ -644,7 +676,7 @@ "Doc": "制造站点进去之后,左下角那个“中级作战记录 制造中”", "algorithm": "justreturn", "action": "clickRect", - "specificArea": [ + "specificRect": [ 1, 535, 525, @@ -658,7 +690,7 @@ "Doc": "设施列表里第一个(第一个制造站或者贸易站)", "algorithm": "justreturn", "action": "clickRect", - "specificArea": [ + "specificRect": [ 1, 183, 220, @@ -669,7 +701,6 @@ ] }, "InfrastNotification": { - "template": "InfrastNotification.png", "templThreshold": 0.8, "action": "clickSelf", "next": [ @@ -686,7 +717,7 @@ ], "rearDelay": 1000, "action": "clickSelf", - "identifyArea": [ + "roi": [ 0, 600, 800, @@ -702,7 +733,7 @@ "Doc": "干员疲劳、线索收集 是不能一键收获的,所以要先退出一键收获的界面,这里点击的是控制中枢左侧那一片空白的区域", "algorithm": "justreturn", "action": "clickRect", - "specificArea": [ + "specificRect": [ 250, 100, 380, @@ -713,7 +744,6 @@ ] }, "UavAssist-MFG": { - "template": "UavAssist-MFG.png", "action": "clickSelf", "cache": false, "maxTimes": 1, @@ -724,7 +754,6 @@ ] }, "UavAssist-Trade": { - "template": "UavAssist-Trade.png", "action": "clickSelf", "cache": false, "next": [ @@ -733,14 +762,12 @@ ] }, "UavMax": { - "template": "UavMax.png", "action": "clickSelf", "next": [ "UavConfirm" ] }, "UavConfirm": { - "template": "UavConfirm.png", "action": "clickSelf", "rearDelay": 2000, "next": [ @@ -750,7 +777,6 @@ ] }, "DeliverableOrder": { - "template": "DeliverableOrder.png", "cache": false, "action": "clickSelf", "next": [ diff --git a/resource/template/special/02.png b/resource/template/02.png similarity index 100% rename from resource/template/special/02.png rename to resource/template/02.png diff --git a/resource/template/special/03.png b/resource/template/03.png similarity index 100% rename from resource/template/special/03.png rename to resource/template/03.png diff --git a/resource/template/special/04.png b/resource/template/04.png similarity index 100% rename from resource/template/special/04.png rename to resource/template/04.png diff --git a/resource/template/special/05.png b/resource/template/05.png similarity index 100% rename from resource/template/special/05.png rename to resource/template/05.png diff --git a/resource/template/special/AddOperator-Trade.png b/resource/template/AddOperator-Trade.png similarity index 100% rename from resource/template/special/AddOperator-Trade.png rename to resource/template/AddOperator-Trade.png diff --git a/resource/template/special/BuyIt.png b/resource/template/BuyIt.png similarity index 100% rename from resource/template/special/BuyIt.png rename to resource/template/BuyIt.png diff --git a/resource/template/special/ContactSuspended.png b/resource/template/ContactSuspended.png similarity index 100% rename from resource/template/special/ContactSuspended.png rename to resource/template/ContactSuspended.png diff --git a/resource/template/special/CreditPoint.png b/resource/template/CreditPoint.png similarity index 100% rename from resource/template/special/CreditPoint.png rename to resource/template/CreditPoint.png diff --git a/resource/template/special/DogFood.png b/resource/template/DogFood.png similarity index 100% rename from resource/template/special/DogFood.png rename to resource/template/DogFood.png diff --git a/resource/template/special/Dorm.png b/resource/template/Dorm.png similarity index 100% rename from resource/template/special/Dorm.png rename to resource/template/Dorm.png diff --git a/resource/template/special/DormConfirm.png b/resource/template/DormConfirm.png similarity index 100% rename from resource/template/special/DormConfirm.png rename to resource/template/DormConfirm.png diff --git a/resource/template/special/DormMini.png b/resource/template/DormMini.png similarity index 100% rename from resource/template/special/DormMini.png rename to resource/template/DormMini.png diff --git a/resource/template/special/Elite1.png b/resource/template/Elite1.png similarity index 100% rename from resource/template/special/Elite1.png rename to resource/template/Elite1.png diff --git a/resource/template/special/Elite2.png b/resource/template/Elite2.png similarity index 100% rename from resource/template/special/Elite2.png rename to resource/template/Elite2.png diff --git a/resource/template/special/GoIn.png b/resource/template/GoIn.png similarity index 100% rename from resource/template/special/GoIn.png rename to resource/template/GoIn.png diff --git a/resource/template/Listless.png b/resource/template/Listless.png index 61ee7aff8b..014335c901 100644 Binary files a/resource/template/Listless.png and b/resource/template/Listless.png differ diff --git a/resource/template/special/Office.png b/resource/template/Office.png similarity index 100% rename from resource/template/special/Office.png rename to resource/template/Office.png diff --git a/resource/template/special/OfficeMini.png b/resource/template/OfficeMini.png similarity index 100% rename from resource/template/special/OfficeMini.png rename to resource/template/OfficeMini.png diff --git a/resource/template/special/OnShift.png b/resource/template/OnShift.png similarity index 100% rename from resource/template/special/OnShift.png rename to resource/template/OnShift.png diff --git a/resource/template/Power.png b/resource/template/Power.png index fa1db56ce7..c04f3d78e1 100644 Binary files a/resource/template/Power.png and b/resource/template/Power.png differ diff --git a/resource/template/special/PowerMini.png b/resource/template/PowerMini.png similarity index 100% rename from resource/template/special/PowerMini.png rename to resource/template/PowerMini.png diff --git a/resource/template/special/PureGold.png b/resource/template/PureGold.png similarity index 100% rename from resource/template/special/PureGold.png rename to resource/template/PureGold.png diff --git a/resource/template/special/Resting.png b/resource/template/Resting.png similarity index 100% rename from resource/template/special/Resting.png rename to resource/template/Resting.png diff --git a/resource/template/special/SmileyAtRest.png b/resource/template/SmileyAtRest.png similarity index 100% rename from resource/template/special/SmileyAtRest.png rename to resource/template/SmileyAtRest.png diff --git a/resource/template/special/SmileyAtWork.png b/resource/template/SmileyAtWork.png similarity index 100% rename from resource/template/special/SmileyAtWork.png rename to resource/template/SmileyAtWork.png diff --git a/resource/template/special/SoldOut.png b/resource/template/SoldOut.png similarity index 100% rename from resource/template/special/SoldOut.png rename to resource/template/SoldOut.png diff --git a/resource/template/special/StationInfoSelected.png b/resource/template/StationInfoSelected.png similarity index 100% rename from resource/template/special/StationInfoSelected.png rename to resource/template/StationInfoSelected.png diff --git a/resource/template/special/TradeMoney.png b/resource/template/TradeMoney.png similarity index 100% rename from resource/template/special/TradeMoney.png rename to resource/template/TradeMoney.png diff --git a/resource/template/special/UnlockClues.png b/resource/template/UnlockClues.png similarity index 100% rename from resource/template/special/UnlockClues.png rename to resource/template/UnlockClues.png diff --git a/resource/template/special/AddOperator.png b/resource/template/special/AddOperator.png deleted file mode 100644 index bebe549b84..0000000000 Binary files a/resource/template/special/AddOperator.png and /dev/null differ diff --git a/resource/template/special/ClearSelection.png b/resource/template/special/ClearSelection.png deleted file mode 100644 index 52220b1a9f..0000000000 Binary files a/resource/template/special/ClearSelection.png and /dev/null differ diff --git a/resource/template/special/Listless.png b/resource/template/special/Listless.png deleted file mode 100644 index 014335c901..0000000000 Binary files a/resource/template/special/Listless.png and /dev/null differ diff --git a/resource/template/special/Power.png b/resource/template/special/Power.png deleted file mode 100644 index c04f3d78e1..0000000000 Binary files a/resource/template/special/Power.png and /dev/null differ diff --git a/src/MeoAssistance/AbstractConfiger.cpp b/src/MeoAssistance/AbstractConfiger.cpp index 9dc8be4d2b..e288ecd568 100644 --- a/src/MeoAssistance/AbstractConfiger.cpp +++ b/src/MeoAssistance/AbstractConfiger.cpp @@ -1,20 +1,15 @@ #include "AbstractConfiger.h" -#include #include #include #include -#include "Logger.hpp" - bool asst::AbstractConfiger::load(const std::string& filename) { - DebugTraceFunction; - DebugTrace("Configer::load | ", filename); - std::ifstream ifs(filename, std::ios::in); if (!ifs.is_open()) { + m_last_error = filename + " can't be opened"; return false; } std::stringstream iss; @@ -24,7 +19,7 @@ bool asst::AbstractConfiger::load(const std::string& filename) auto&& ret = json::parser::parse(content); if (!ret) { - DebugTrace("parse error", content); + m_last_error = "json pasing error " + content; return false; } @@ -34,10 +29,8 @@ bool asst::AbstractConfiger::load(const std::string& filename) parse(root); } catch (json::exception& e) { - DebugTraceError("Load config json error!", e.what()); + m_last_error = std::string("json field error ") + e.what(); return false; } - - DebugTrace("Load config succeed"); return true; } \ No newline at end of file diff --git a/src/MeoAssistance/AbstractConfiger.h b/src/MeoAssistance/AbstractConfiger.h index 9df0f2e8ce..ef8903b241 100644 --- a/src/MeoAssistance/AbstractConfiger.h +++ b/src/MeoAssistance/AbstractConfiger.h @@ -1,30 +1,20 @@ #pragma once -#include -#include -#include +#include "AbstractResource.h" -#include "AsstDef.h" +#include namespace json { class value; } namespace asst { - class AbstractConfiger + class AbstractConfiger : public AbstractResource { public: virtual ~AbstractConfiger() = default; - virtual bool load(const std::string& filename); - + virtual bool load(const std::string& filename) override; protected: - AbstractConfiger() = default; - AbstractConfiger(const AbstractConfiger& rhs) = default; - AbstractConfiger(AbstractConfiger&& rhs) noexcept = default; - - AbstractConfiger& operator=(const AbstractConfiger& rhs) = default; - AbstractConfiger& operator=(AbstractConfiger&& rhs) noexcept = default; - virtual bool parse(const json::value& json) = 0; }; } diff --git a/src/MeoAssistance/AbstractImageAnalyzer.cpp b/src/MeoAssistance/AbstractImageAnalyzer.cpp new file mode 100644 index 0000000000..53fa2c523b --- /dev/null +++ b/src/MeoAssistance/AbstractImageAnalyzer.cpp @@ -0,0 +1,24 @@ +#include "AbstractImageAnalyzer.h" + +asst::AbstractImageAnalyzer::AbstractImageAnalyzer(const cv::Mat& image, const Rect& roi) + : m_image(image), + m_roi(empty_rect_to_full(roi, image)) +{ + ; +} + +void asst::AbstractImageAnalyzer::set_image(const cv::Mat& image, const Rect& roi) +{ + m_image = image; + m_roi = empty_rect_to_full(roi, image); +} + +void asst::AbstractImageAnalyzer::set_roi(const Rect& roi) noexcept +{ + m_roi = empty_rect_to_full(roi, m_image); +} + +asst::Rect asst::AbstractImageAnalyzer::empty_rect_to_full(const Rect& rect, const cv::Mat& image) noexcept +{ + return rect.empty() ? Rect(0, 0, image.cols, image.rows) : rect; +} \ No newline at end of file diff --git a/src/MeoAssistance/AbstractImageAnalyzer.h b/src/MeoAssistance/AbstractImageAnalyzer.h new file mode 100644 index 0000000000..e8c5e25544 --- /dev/null +++ b/src/MeoAssistance/AbstractImageAnalyzer.h @@ -0,0 +1,30 @@ +#pragma once + +#include + +#include "AsstDef.h" + +namespace asst { + class AbstractImageAnalyzer + { + public: + AbstractImageAnalyzer() = default; + AbstractImageAnalyzer(const cv::Mat& image, const Rect& roi = Rect()); + AbstractImageAnalyzer(const AbstractImageAnalyzer&) = delete; + AbstractImageAnalyzer(AbstractImageAnalyzer&&) = delete; + virtual ~AbstractImageAnalyzer() = default; + + virtual void set_image(const cv::Mat& image, const Rect& roi = Rect()); + virtual void set_roi(const Rect& roi) noexcept; + virtual bool analyze() = 0; + + AbstractImageAnalyzer& operator=(const AbstractImageAnalyzer&) = delete; + AbstractImageAnalyzer& operator=(AbstractImageAnalyzer&&) = delete; + + protected: + static Rect empty_rect_to_full(const Rect& rect, const cv::Mat& image) noexcept; + + cv::Mat m_image; + Rect m_roi; + }; +} \ No newline at end of file diff --git a/src/MeoAssistance/AbstractResource.cpp b/src/MeoAssistance/AbstractResource.cpp new file mode 100644 index 0000000000..e9b6196692 --- /dev/null +++ b/src/MeoAssistance/AbstractResource.cpp @@ -0,0 +1 @@ +#include "AbstractResource.h" \ No newline at end of file diff --git a/src/MeoAssistance/AbstractResource.h b/src/MeoAssistance/AbstractResource.h new file mode 100644 index 0000000000..04e67bf3a0 --- /dev/null +++ b/src/MeoAssistance/AbstractResource.h @@ -0,0 +1,27 @@ +#pragma once + +#include + +namespace asst { + class AbstractResource + { + public: + AbstractResource() = default; + AbstractResource(const AbstractResource& rhs) = delete; + AbstractResource(AbstractResource&& rhs) noexcept = delete; + + virtual ~AbstractResource() = default; + + virtual bool load(const std::string& filename) = 0; + virtual const std::string& get_last_error() const noexcept + { + return m_last_error; + } + + AbstractResource& operator=(const AbstractResource& rhs) = delete; + AbstractResource& operator=(AbstractResource&& rhs) noexcept = delete; + + protected: + std::string m_last_error; + }; +} diff --git a/src/MeoAssistance/AbstractTask.cpp b/src/MeoAssistance/AbstractTask.cpp index 22a28c8400..7feeb1f23c 100644 --- a/src/MeoAssistance/AbstractTask.cpp +++ b/src/MeoAssistance/AbstractTask.cpp @@ -6,9 +6,7 @@ #include -#include "WinMacro.h" -#include "Identify.h" -#include "Configer.h" +#include "Controller.h" #include "AsstAux.h" #include "Logger.hpp" @@ -21,14 +19,6 @@ AbstractTask::AbstractTask(AsstCallback callback, void* callback_arg) ; } -void AbstractTask::set_ptr( - std::shared_ptr controller_ptr, - std::shared_ptr identify_ptr) -{ - m_controller_ptr = controller_ptr; - m_identify_ptr = identify_ptr; -} - void AbstractTask::set_exit_flag(bool* exit_flag) { m_exit_flag = exit_flag; @@ -81,20 +71,10 @@ bool asst::AbstractTask::need_exit() const noexcept return m_exit_flag != NULL && *m_exit_flag == true; } -bool asst::AbstractTask::is_ptr_inited() const noexcept -{ - if (m_controller_ptr == NULL - || m_identify_ptr == NULL) - { - return false; - } - return true; -} - bool asst::AbstractTask::click_return_button() { - DebugTraceFunction; + LogTraceFunction; const static Rect ConfirmButtonRect(20, 20, 135, 35); - return m_controller_ptr->click(ConfirmButtonRect); + return ctrler.click(ConfirmButtonRect); } \ No newline at end of file diff --git a/src/MeoAssistance/AbstractTask.h b/src/MeoAssistance/AbstractTask.h index 31a8ec4694..bdff8d1acb 100644 --- a/src/MeoAssistance/AbstractTask.h +++ b/src/MeoAssistance/AbstractTask.h @@ -10,9 +10,6 @@ namespace cv } namespace asst { - class WinMacro; - class Identify; - class AbstractTask { public: @@ -21,7 +18,6 @@ namespace asst { AbstractTask(const AbstractTask&) = default; AbstractTask(AbstractTask&&) = default; - virtual void set_ptr(std::shared_ptr controller_ptr, std::shared_ptr identify_ptr); virtual bool run() = 0; virtual void set_exit_flag(bool* exit_flag); @@ -34,13 +30,9 @@ namespace asst { virtual bool sleep(unsigned millisecond); virtual bool save_image(const cv::Mat& iamge, const std::string& dir); virtual bool need_exit() const noexcept; - virtual bool is_ptr_inited() const noexcept; virtual bool click_return_button(); - std::shared_ptr m_controller_ptr = nullptr; - std::shared_ptr m_identify_ptr = nullptr; - AsstCallback m_callback; void* m_callback_arg = NULL; bool* m_exit_flag = NULL; diff --git a/src/MeoAssistance/Assistance.cpp b/src/MeoAssistance/Assistance.cpp index b16cb5aa15..9de9b3f74c 100644 --- a/src/MeoAssistance/Assistance.cpp +++ b/src/MeoAssistance/Assistance.cpp @@ -6,113 +6,30 @@ #include #include -#include "WinMacro.h" -#include "Configer.h" -#include "Identify.h" +#include "Controller.h" #include "Logger.hpp" #include "AsstAux.h" -#include "Task.h" -#include "TaskConfiger.h" -#include "ItemConfiger.h" -#include "RecruitConfiger.h" -#include "InfrastConfiger.h" -#include "UserConfiger.h" +#include "Resource.h" using namespace asst; Assistance::Assistance(AsstCallback callback, void* callback_arg) : m_callback(callback), m_callback_arg(callback_arg) { - DebugTraceFunction; + LogTraceFunction; - // 检查返回值,若为false则回调错误 - auto callback_error = [&](const std::string& filename = std::string()) { - DebugTraceError("resource broken", filename); + bool resource_ret = resource.load(GetResourceDir()); + if (!resource_ret) { + const std::string& error = resource.get_last_error(); + log.error("resource broken", error); if (m_callback == nullptr) { return; } json::value callback_json; - callback_json["filename"] = filename; - callback_json["what"] = "resource broken"; + callback_json["type"] = "resource broken"; + callback_json["what"] = error; m_callback(AsstMsg::InitFaild, callback_json, m_callback_arg); - }; - - /* 项目本身的Configer */ - bool ret = Configer::get_instance().load(GetResourceDir() + "config.json"); - if (!ret) { - callback_error("config.json"); - throw "resource broken"; } - ret = TaskConfiger::get_instance().load(GetResourceDir() + "tasks.json"); - if (!ret) { - callback_error("tasks.json"); - throw "resource broken"; - } - ret = RecruitConfiger::get_instance().load(GetResourceDir() + "recruit.json"); - if (!ret) { - callback_error("recruit.json"); - throw "resource broken"; - } - ret = InfrastConfiger::get_instance().load(GetResourceDir() + "infrast.json"); - if (!ret) { - callback_error("infrast.json"); - throw "resource broken"; - } - ret = ItemConfiger::get_instance().load(GetResourceDir() + "item_index.json"); - if (!ret) { - callback_error("item_index.json"); - throw "resource broken"; - } - - /* 项目使用的图片模板 */ - m_identify_ptr = std::make_shared(); - for (const auto& [name, info] : TaskConfiger::get_instance().m_all_tasks_info) { - if (info->algorithm != AlgorithmType::MatchTemplate) { - continue; - } - std::string filename = std::dynamic_pointer_cast(info)->template_filename; - ret = m_identify_ptr->add_image(name, GetResourceDir() + "template\\" + filename); - if (!ret) { - callback_error(filename); - throw "resource broken"; - } - } - for (auto& p : std::filesystem::directory_iterator(GetResourceDir() + "template\\special\\")) { - if (p.path().extension() == ".png") { - std::string filename = p.path().filename().u8string(); - std::string without_extension = filename.substr(0, filename.size() - 4); - ret = m_identify_ptr->add_image(without_extension, p.path().u8string()); - } - } - - /* 第三方库`OcrLite`所需资源*/ - m_identify_ptr->set_ocr_param(Configer::get_instance().m_options.ocr_gpu_index, Configer::get_instance().m_options.ocr_thread_number); - ret = m_identify_ptr->ocr_init_models(GetResourceDir() + "OcrLiteOnnx\\models\\"); - if (!ret) { - callback_error("OcrLiteOnnx\\models\\"); - throw "resource broken"; - } - - /* 第三方库`penguin-stats-recognize`(企鹅物流掉落识别)所需资源*/ - m_identify_ptr->penguin_load_server(Configer::get_instance().m_options.penguin_server); - m_identify_ptr->penguin_load_json(GetResourceDir() + "penguin-stats-recognize\\json\\stages.json", GetResourceDir() + "penguin-stats-recognize\\json\\hash_index.json"); - - for (const auto& file : std::filesystem::directory_iterator(GetResourceDir() + "penguin-stats-recognize\\items")) { - ret = m_identify_ptr->penguin_load_templ(file.path().stem().u8string(), file.path().u8string()); - if (!ret) { - callback_error(file.path().stem().u8string()); - throw "resource broken"; - } - } - - /* 用户配置 */ - ret = UserConfiger::get_instance().load(GetCurrentDir() + "user.json"); - if (!ret) { - callback_error("user.json"); - throw "resource broken"; - } - - m_controller_ptr = std::make_shared(); m_working_thread = std::thread(std::bind(&Assistance::working_proc, this)); m_msg_thread = std::thread(std::bind(&Assistance::msg_proc, this)); @@ -120,11 +37,7 @@ Assistance::Assistance(AsstCallback callback, void* callback_arg) Assistance::~Assistance() { - DebugTraceFunction; - - //if (m_controller_ptr != nullptr) { - // m_controller_ptr->show_window(); - //} + LogTraceFunction; m_thread_exit = true; m_thread_idle = true; @@ -141,15 +54,16 @@ Assistance::~Assistance() bool asst::Assistance::catch_default() { - DebugTraceFunction; + LogTraceFunction; - switch (Configer::get_instance().m_options.connect_type) { + auto& opt = resource.cfg().get_options(); + switch (opt.connect_type) { case ConnectType::Emulator: return catch_emulator(); case ConnectType::USB: return catch_usb(); case ConnectType::Remote: - return catch_remote(Configer::get_instance().m_options.connect_remote_address); + return catch_remote(opt.connect_remote_address); default: return false; } @@ -157,19 +71,20 @@ bool asst::Assistance::catch_default() bool Assistance::catch_emulator(const std::string& emulator_name) { - DebugTraceFunction; + LogTraceFunction; stop(); bool ret = false; //std::string cor_name = emulator_name; + auto& cfg = resource.cfg(); std::unique_lock lock(m_mutex); // 自动匹配模拟器,逐个找 if (emulator_name.empty()) { - for (const auto& [name, info] : Configer::get_instance().m_handles) { - ret = m_controller_ptr->try_capture(info); + for (const auto& [name, info] : cfg.get_emulators_info()) { + ret = ctrler.try_capture(info); if (ret) { //cor_name = name; break; @@ -177,7 +92,8 @@ bool Assistance::catch_emulator(const std::string& emulator_name) } } else { // 指定的模拟器 - ret = m_controller_ptr->try_capture(Configer::get_instance().m_handles[emulator_name]); + auto& info = cfg.get_emulators_info().at(emulator_name); + ret = ctrler.try_capture(info); } m_inited = ret; @@ -186,17 +102,18 @@ bool Assistance::catch_emulator(const std::string& emulator_name) bool asst::Assistance::catch_usb() { - DebugTraceFunction; + LogTraceFunction; stop(); bool ret = false; + auto& cfg = resource.cfg(); std::unique_lock lock(m_mutex); - EmulatorInfo remote_info = Configer::get_instance().m_handles["USB"]; + EmulatorInfo remote_info = cfg.get_emulators_info().at("USB"); - ret = m_controller_ptr->try_capture(remote_info, true); + ret = ctrler.try_capture(remote_info, true); m_inited = ret; return ret; @@ -204,22 +121,23 @@ bool asst::Assistance::catch_usb() bool asst::Assistance::catch_remote(const std::string& address) { - DebugTraceFunction; + LogTraceFunction; stop(); bool ret = false; + auto& cfg = resource.cfg(); std::unique_lock lock(m_mutex); - EmulatorInfo remote_info = Configer::get_instance().m_handles["Remote"]; + EmulatorInfo remote_info = cfg.get_emulators_info().at("Remote"); remote_info.adb.connect = StringReplaceAll(remote_info.adb.connect, "[Address]", address); remote_info.adb.click = StringReplaceAll(remote_info.adb.click, "[Address]", address); remote_info.adb.swipe = StringReplaceAll(remote_info.adb.swipe, "[Address]", address); remote_info.adb.display = StringReplaceAll(remote_info.adb.display, "[Address]", address); remote_info.adb.screencap = StringReplaceAll(remote_info.adb.screencap, "[Address]", address); - ret = m_controller_ptr->try_capture(remote_info, true); + ret = ctrler.try_capture(remote_info, true); m_inited = ret; return ret; @@ -232,13 +150,13 @@ bool asst::Assistance::start_sanity() bool asst::Assistance::start_visit(bool with_shopping) { - DebugTraceFunction; + LogTraceFunction; if (!m_thread_idle || !m_inited) { return false; } std::unique_lock lock(m_mutex); - m_identify_ptr->clear_cache(); + resource.templ().clear_hists(); append_match_task("VisitBegin", { "VisitBegin" }, ProcessTaskRetryTimesDefault); @@ -256,8 +174,8 @@ bool asst::Assistance::start_visit(bool with_shopping) bool Assistance::start_process_task(const std::string& task, int retry_times, bool block) { - DebugTraceFunction; - DebugTrace("Start |", task, block ? "block" : "non block"); + LogTraceFunction; + log.trace("Start |", task, block ? "block" : "non block"); if (!m_thread_idle || !m_inited) { return false; } @@ -266,7 +184,7 @@ bool Assistance::start_process_task(const std::string& task, int retry_times, bo if (block) { lock = std::unique_lock(m_mutex); //clear_exec_times(); - m_identify_ptr->clear_cache(); + resource.templ().clear_hists(); } append_match_task(task, { task }, retry_times); @@ -280,7 +198,7 @@ bool Assistance::start_process_task(const std::string& task, int retry_times, bo #ifdef LOG_TRACE bool Assistance::start_debug_task() { - DebugTraceFunction; + LogTraceFunction; if (!m_thread_idle || !m_inited) { return false; } @@ -296,7 +214,7 @@ bool Assistance::start_debug_task() // auto ret = get_opers_idtf_result(); // if (!ret) { - // DebugTraceInfo("Get opers info error"); + // log.info("Get opers info error"); // //return false; // } // else { @@ -307,7 +225,7 @@ bool Assistance::start_debug_task() //} { constexpr static const char* DebugTaskChain = "Debug"; - auto shift_task_ptr = std::make_shared(task_callback, (void*)this); + auto shift_task_ptr = std::make_shared(task_callback, (void*)this); shift_task_ptr->set_task_chain(DebugTaskChain); m_tasks_deque.emplace_back(shift_task_ptr); } @@ -319,16 +237,16 @@ bool Assistance::start_debug_task() } #endif -bool Assistance::start_open_recruit(const std::vector& required_level, bool set_time) +bool Assistance::start_recruiting(const std::vector& required_level, bool set_time) { - DebugTraceFunction; + LogTraceFunction; if (!m_thread_idle || !m_inited) { return false; } std::unique_lock lock(m_mutex); - auto task_ptr = std::make_shared(task_callback, (void*)this); + auto task_ptr = std::make_shared(task_callback, (void*)this); task_ptr->set_param(required_level, set_time); task_ptr->set_retry_times(OpenRecruitTaskRetyrTimesDefault); task_ptr->set_task_chain("OpenRecruit"); @@ -340,130 +258,130 @@ bool Assistance::start_open_recruit(const std::vector& required_level, bool return true; } -bool asst::Assistance::start_to_identify_opers() -{ - DebugTraceFunction; - if (!m_thread_idle || !m_inited) { - return false; - } - - std::unique_lock lock(m_mutex); - - append_match_task("IdentifyOpers", { "OperatorBegin" }); - - auto task_ptr = std::make_shared(task_callback, (void*)this); - task_ptr->set_task_chain("IdentifyOpers"); - m_tasks_deque.emplace_back(task_ptr); - - m_thread_idle = false; - m_condvar.notify_one(); - - return true; -} - -bool asst::Assistance::start_infrast() -{ - DebugTraceFunction; - if (!m_thread_idle || !m_inited) { - return false; - } - - std::unique_lock lock(m_mutex); - auto ret = get_opers_idtf_result(); - if (!ret) { - DebugTraceInfo("Get opers info error"); - return false; - } - constexpr static const char* InfrastTaskCahin = "Infrast"; - // 换班任务,依次遍历基建设施列表里的最多5个设施,识别并选择最优解干员组合 - auto shift_task_ptr = std::make_shared(task_callback, (void*)this); - shift_task_ptr->set_task_chain(InfrastTaskCahin); - shift_task_ptr->set_all_opers_info(std::move(ret.value())); - - /* 基建任务整体流程: - 1. 从任意界面进入基建,使用ProcessTask - 2. 一键收获贸易站、制造站、干员信赖,使用ProcessTask - 1) 如果收获了,使用基建全缩放到最小的模板匹配 - 2) 如果没收获,使用基建默认大小的模板匹配 - 3. 进入宿舍,把心情低于阈值的、心情没满但不在工作的,都换下去,使用InfrastDormTask - 4. 根据用户设置,按顺序进入制造站or贸易站,使用ProcessTask - 5. 对制造站or贸易站进行换班,使用InfrastStationTask - 6. 根据用户设置,使用无人机加速制造or贸易,使用ProcessTask - 7. 会客室线索处理、发电站换班、控制中枢、办公室换班,同样需要根据用户设置决定顺序,TODO - 8. 再次进入宿舍,把基建中可能换下来的干员(心情不低的)加入宿舍 - */ - - // 1. 从任意界面进入基建,使用ProcessTask - // 2. 一键收获贸易站、制造站、干员信赖,使用ProcessTask - // 这个任务结束后,是在进入基建后的主界面 - append_match_task(InfrastTaskCahin, { "InfrastBegin" }); - - // 3. 进入宿舍,把心情低于阈值的、心情没满但不在工作的,都换下去 - auto dorm_task_ptr = std::make_shared(task_callback, (void*)this); - dorm_task_ptr->set_task_chain(InfrastTaskCahin); - m_tasks_deque.emplace_back(dorm_task_ptr); - - // 返回基建的主界面 - append_match_task(InfrastTaskCahin, { "InfrastBegin" }); - - // 5. 对制造站or贸易站进行换班,使用InfrastStationTask - - // TODO,这里需要根据用户设置,是先制造站还是先贸易站,或者是别的设施 - // 从进入制造站,到设施列表的界面 - append_match_task(InfrastTaskCahin, { "ManufacturingMini", "Manufacturing" }); - - // 制造站换班 - m_tasks_deque.emplace_back(shift_task_ptr); - - // 返回基建的主界面 - append_match_task(InfrastTaskCahin, { "InfrastBegin" }); - - // TODO,这里需要根据用户设置,是先制造站还是先贸易站,或者是别的设施 - // 从进入贸易站,到设施列表的界面 - append_match_task(InfrastTaskCahin, { "Trade", "TradeMini" }); - - // 贸易站换班 - m_tasks_deque.emplace_back(shift_task_ptr); - - // 6. 根据用户设置,使用无人机加速制造or贸易,使用ProcessTask - // 对贸易站使用无人机加速 - append_match_task(InfrastTaskCahin, { "UavAssist-Trade" }); - - // 返回基建的主界面 - append_match_task(InfrastTaskCahin, { "InfrastBegin" }); - - // 7. 会客室线索处理、发电站换班、控制中枢、办公室换班,同样需要根据用户设置决定顺序,TODO - // 发电站换班 - auto power_task_ptr = std::make_shared(task_callback, (void*)this); - power_task_ptr->set_task_chain(InfrastTaskCahin); - m_tasks_deque.emplace_back(std::move(power_task_ptr)); - - // 返回基建的主界面 - append_match_task(InfrastTaskCahin, { "InfrastBegin" }); - - auto office_task_ptr = std::make_shared(task_callback, (void*)this); - office_task_ptr->set_task_chain(InfrastTaskCahin); - m_tasks_deque.emplace_back(std::move(office_task_ptr)); - - // 返回基建的主界面 - append_match_task(InfrastTaskCahin, { "InfrastBegin" }); - - // 8. 再次进入宿舍,把基建中可能换下来的干员(心情不低的)加入宿舍 - m_tasks_deque.emplace_back(dorm_task_ptr); - - // 全操作完之后,再返回基建的主界面 - append_match_task(InfrastTaskCahin, { "InfrastBegin" }); - - m_thread_idle = false; - m_condvar.notify_one(); - - return true; -} +//bool asst::Assistance::start_to_identify_opers() +//{ +// LogTraceFunction; +// if (!m_thread_idle || !m_inited) { +// return false; +// } +// +// std::unique_lock lock(m_mutex); +// +// append_match_task("IdentifyOpers", { "OperatorBegin" }); +// +// auto task_ptr = std::make_shared(task_callback, (void*)this); +// task_ptr->set_task_chain("IdentifyOpers"); +// m_tasks_deque.emplace_back(task_ptr); +// +// m_thread_idle = false; +// m_condvar.notify_one(); +// +// return true; +//} +// +//bool asst::Assistance::start_infrast() +//{ +// LogTraceFunction; +// if (!m_thread_idle || !m_inited) { +// return false; +// } +// +// std::unique_lock lock(m_mutex); +// auto ret = get_opers_idtf_result(); +// if (!ret) { +// log.info("Get opers info error"); +// return false; +// } +// constexpr static const char* InfrastTaskCahin = "Infrast"; +// // 换班任务,依次遍历基建设施列表里的最多5个设施,识别并选择最优解干员组合 +// auto shift_task_ptr = std::make_shared(task_callback, (void*)this); +// shift_task_ptr->set_task_chain(InfrastTaskCahin); +// shift_task_ptr->set_all_opers_info(std::move(ret.value())); +// +// /* 基建任务整体流程: +// 1. 从任意界面进入基建,使用ProcessTask +// 2. 一键收获贸易站、制造站、干员信赖,使用ProcessTask +// 1) 如果收获了,使用基建全缩放到最小的模板匹配 +// 2) 如果没收获,使用基建默认大小的模板匹配 +// 3. 进入宿舍,把心情低于阈值的、心情没满但不在工作的,都换下去,使用InfrastDormTask +// 4. 根据用户设置,按顺序进入制造站or贸易站,使用ProcessTask +// 5. 对制造站or贸易站进行换班,使用InfrastStationTask +// 6. 根据用户设置,使用无人机加速制造or贸易,使用ProcessTask +// 7. 会客室线索处理、发电站换班、控制中枢、办公室换班,同样需要根据用户设置决定顺序,TODO +// 8. 再次进入宿舍,把基建中可能换下来的干员(心情不低的)加入宿舍 +// */ +// +// // 1. 从任意界面进入基建,使用ProcessTask +// // 2. 一键收获贸易站、制造站、干员信赖,使用ProcessTask +// // 这个任务结束后,是在进入基建后的主界面 +// append_match_task(InfrastTaskCahin, { "InfrastBegin" }); +// +// // 3. 进入宿舍,把心情低于阈值的、心情没满但不在工作的,都换下去 +// auto dorm_task_ptr = std::make_shared(task_callback, (void*)this); +// dorm_task_ptr->set_task_chain(InfrastTaskCahin); +// m_tasks_deque.emplace_back(dorm_task_ptr); +// +// // 返回基建的主界面 +// append_match_task(InfrastTaskCahin, { "InfrastBegin" }); +// +// // 5. 对制造站or贸易站进行换班,使用InfrastStationTask +// +// // TODO,这里需要根据用户设置,是先制造站还是先贸易站,或者是别的设施 +// // 从进入制造站,到设施列表的界面 +// append_match_task(InfrastTaskCahin, { "ManufacturingMini", "Manufacturing" }); +// +// // 制造站换班 +// m_tasks_deque.emplace_back(shift_task_ptr); +// +// // 返回基建的主界面 +// append_match_task(InfrastTaskCahin, { "InfrastBegin" }); +// +// // TODO,这里需要根据用户设置,是先制造站还是先贸易站,或者是别的设施 +// // 从进入贸易站,到设施列表的界面 +// append_match_task(InfrastTaskCahin, { "Trade", "TradeMini" }); +// +// // 贸易站换班 +// m_tasks_deque.emplace_back(shift_task_ptr); +// +// // 6. 根据用户设置,使用无人机加速制造or贸易,使用ProcessTask +// // 对贸易站使用无人机加速 +// append_match_task(InfrastTaskCahin, { "UavAssist-Trade" }); +// +// // 返回基建的主界面 +// append_match_task(InfrastTaskCahin, { "InfrastBegin" }); +// +// // 7. 会客室线索处理、发电站换班、控制中枢、办公室换班,同样需要根据用户设置决定顺序,TODO +// // 发电站换班 +// auto power_task_ptr = std::make_shared(task_callback, (void*)this); +// power_task_ptr->set_task_chain(InfrastTaskCahin); +// m_tasks_deque.emplace_back(std::move(power_task_ptr)); +// +// // 返回基建的主界面 +// append_match_task(InfrastTaskCahin, { "InfrastBegin" }); +// +// auto office_task_ptr = std::make_shared(task_callback, (void*)this); +// office_task_ptr->set_task_chain(InfrastTaskCahin); +// m_tasks_deque.emplace_back(std::move(office_task_ptr)); +// +// // 返回基建的主界面 +// append_match_task(InfrastTaskCahin, { "InfrastBegin" }); +// +// // 8. 再次进入宿舍,把基建中可能换下来的干员(心情不低的)加入宿舍 +// m_tasks_deque.emplace_back(dorm_task_ptr); +// +// // 全操作完之后,再返回基建的主界面 +// append_match_task(InfrastTaskCahin, { "InfrastBegin" }); +// +// m_thread_idle = false; +// m_condvar.notify_one(); +// +// return true; +//} void Assistance::stop(bool block) { - DebugTraceFunction; - DebugTrace("Stop |", block ? "block" : "non block"); + LogTraceFunction; + log.trace("Stop |", block ? "block" : "non block"); m_thread_idle = true; @@ -474,36 +392,35 @@ void Assistance::stop(bool block) decltype(m_tasks_deque) empty; m_tasks_deque.swap(empty); clear_exec_times(); - m_identify_ptr->clear_cache(); + resource.templ().clear_hists(); } bool Assistance::set_param(const std::string& type, const std::string& param, const std::string& value) { - DebugTraceFunction; - DebugTrace("SetParam |", type, param, value); + LogTraceFunction; + log.trace("SetParam |", type, param, value); - return TaskConfiger::get_instance().set_param(type, param, value); + return resource.task().set_param(type, param, value); } void Assistance::working_proc() { - DebugTraceFunction; + LogTraceFunction; auto p_this = this; int retry_times = 0; while (!m_thread_exit) { - //DebugTraceScope("Assistance::working_proc Loop"); + //LogTraceScope("Assistance::working_proc Loop"); std::unique_lock lock(m_mutex); if (!m_thread_idle && !m_tasks_deque.empty()) { - //m_controller_ptr->set_idle(false); + //controller.set_idle(false); auto start_time = std::chrono::system_clock::now(); std::shared_ptr task_ptr = m_tasks_deque.front(); // 先pop出来,如果执行失败再还原回去 m_tasks_deque.pop_front(); - task_ptr->set_ptr(m_controller_ptr, m_identify_ptr); task_ptr->set_exit_flag(&m_thread_idle); bool ret = task_ptr->run(); if (ret) { @@ -534,13 +451,13 @@ void Assistance::working_proc() } } - int& delay = Configer::get_instance().m_options.task_delay; + auto& delay = resource.cfg().get_options().task_delay; m_condvar.wait_until(lock, start_time + std::chrono::milliseconds(delay), [&]() -> bool { return m_thread_idle; }); } else { m_thread_idle = true; - //m_controller_ptr->set_idle(true); + //controller.set_idle(true); m_condvar.wait(lock); } } @@ -548,10 +465,10 @@ void Assistance::working_proc() void Assistance::msg_proc() { - DebugTraceFunction; + LogTraceFunction; while (!m_thread_exit) { - //DebugTraceScope("Assistance::msg_proc Loop"); + //LogTraceScope("Assistance::msg_proc Loop"); std::unique_lock lock(m_msg_mutex); if (!m_msg_queue.empty()) { // 结构化绑定只能是引用,后续的pop会使引用失效,所以需要重新构造一份,这里采用了move的方式 @@ -573,7 +490,7 @@ void Assistance::msg_proc() void Assistance::task_callback(AsstMsg msg, const json::value& detail, void* custom_arg) { - DebugTrace("Assistance::task_callback |", msg, detail.to_string()); + log.trace("Assistance::task_callback |", msg, detail.to_string()); Assistance* p_this = (Assistance*)custom_arg; json::value more_detail = detail; @@ -583,7 +500,7 @@ void Assistance::task_callback(AsstMsg msg, const json::value& detail, void* cus p_this->stop(false); break; //case AsstMsg::WindowMinimized: - // p_this->m_controller_ptr->show_window(); + // p_this->controller.show_window(); // break; case AsstMsg::AppendProcessTask: more_detail["type"] = "ProcessTask"; @@ -592,9 +509,6 @@ void Assistance::task_callback(AsstMsg msg, const json::value& detail, void* cus p_this->append_task(more_detail, true); return; // 这俩消息Assistance会新增任务,外部不需要处理,直接拦掉 break; - case AsstMsg::OpersIdtfResult: - set_opers_idtf_result(more_detail); // 保存到文件 - break; case AsstMsg::StageDrops: more_detail = p_this->organize_stage_drop(more_detail); break; @@ -653,70 +567,26 @@ void asst::Assistance::append_callback(AsstMsg msg, json::value detail) void Assistance::clear_exec_times() { - for (auto&& pair : TaskConfiger::get_instance().m_all_tasks_info) { - pair.second->exec_times = 0; - } - ItemConfiger::get_instance().clear_drop_count(); -} - -void asst::Assistance::set_opers_idtf_result(const json::value& detail) -{ - constexpr static const char* Filename = "operators.json"; - std::ofstream ofs(GetCurrentDir() + Filename, std::ios::out); - ofs << detail.format() << std::endl; - ofs.close(); -} - -std::optional> Assistance::get_opers_idtf_result() -{ - constexpr static const char* Filename = "operators.json"; - std::ifstream ifs(GetCurrentDir() + Filename, std::ios::in); - if (!ifs.is_open()) { - return std::nullopt; - } - std::stringstream iss; - iss << ifs.rdbuf(); - ifs.close(); - std::string content(iss.str()); - - auto&& parse_ret = json::parse(content); - if (!parse_ret) { - DebugTraceError(__FUNCTION__, "json parsing error!"); - return std::nullopt; - } - json::value root = std::move(parse_ret.value()); - std::unordered_map opers_info; - try { - for (const json::value& info_json : root["all"].as_array()) { - OperInfrastInfo info; - info.name = info_json.at("name").as_string(); - info.elite = info_json.at("elite").as_integer(); - info.level = info_json.get("level", 0); - opers_info.emplace(info.name, std::move(info)); - } - } - catch (json::exception& exp) { - DebugTraceError(__FUNCTION__, "json parsing error!", exp.what()); - return std::nullopt; - } - return opers_info; + resource.task().clear_exec_times(); + resource.item().clear_drop_count(); } json::value asst::Assistance::organize_stage_drop(const json::value& rec) { json::value dst = rec; + auto& item = resource.item(); for (json::value& drop : dst["drops"].as_array()) { std::string id = drop["itemId"].as_string(); int quantity = drop["quantity"].as_integer(); - ItemConfiger::get_instance().m_drop_count[id] += quantity; - const std::string& name = ItemConfiger::get_instance().m_item_name[id]; + item.increase_drop_count(id, quantity); + const std::string& name = item.get_item_name(id); drop["itemName"] = name.empty() ? "未知材料" : name; } std::vector statistics_vec; - for (auto&& [id, count] : ItemConfiger::get_instance().m_drop_count) { + for (auto&& [id, count] : item.get_drop_count()) { json::value info; info["itemId"] = id; - const std::string& name = ItemConfiger::get_instance().m_item_name[id]; + const std::string& name = item.get_item_name(id); info["itemName"] = name.empty() ? "未知材料" : name; info["count"] = count; statistics_vec.emplace_back(std::move(info)); @@ -730,7 +600,7 @@ json::value asst::Assistance::organize_stage_drop(const json::value& rec) dst["statistics"] = json::array(std::move(statistics_vec)); - DebugTrace("organize_stage_drop | ", dst.to_string()); + log.trace("organize_stage_drop | ", dst.to_string()); return dst; } \ No newline at end of file diff --git a/src/MeoAssistance/Assistance.h b/src/MeoAssistance/Assistance.h index 323581e8f3..a69005975f 100644 --- a/src/MeoAssistance/Assistance.h +++ b/src/MeoAssistance/Assistance.h @@ -17,7 +17,7 @@ namespace cv { } namespace asst { - class WinMacro; + class Controller; class Identify; class Assistance @@ -41,7 +41,7 @@ namespace asst { bool start_visit(bool with_shopping = false); // 开始公开招募操作 - bool start_open_recruit(const std::vector& required_level, bool set_time = true); + bool start_recruiting(const std::vector& required_level, bool set_time = true); // 开始干员识别任务 bool start_to_identify_opers(); // 开始全自动基建任务 @@ -70,13 +70,8 @@ namespace asst { void append_task(const json::value& detail, bool front = false); void append_callback(AsstMsg msg, json::value detail); void clear_exec_times(); - static void set_opers_idtf_result(const json::value& detail); // 保存干员识别结果 - static std::optional> - get_opers_idtf_result(); // 读取干员识别结果 json::value organize_stage_drop(const json::value& rec); // 整理关卡掉落的材料信息 - std::shared_ptr m_controller_ptr = nullptr; - std::shared_ptr m_identify_ptr = nullptr; bool m_inited = false; bool m_thread_exit = false; diff --git a/src/MeoAssistance/AsstCaller.cpp b/src/MeoAssistance/AsstCaller.cpp index d42a61960d..51c7b90c56 100644 --- a/src/MeoAssistance/AsstCaller.cpp +++ b/src/MeoAssistance/AsstCaller.cpp @@ -156,31 +156,31 @@ const char* AsstGetVersion() return asst::Version; } -bool AsstStartOpenRecruit(void* p_asst, const int required_level[], int required_len, bool set_time) +bool AsstStartRecruiting(void* p_asst, const int required_level[], int required_len, bool set_time) { if (p_asst == nullptr) { return false; } std::vector level_vector; level_vector.assign(required_level, required_level + required_len); - return ((asst::Assistance*)p_asst)->start_open_recruit(level_vector, set_time); + return ((asst::Assistance*)p_asst)->start_recruiting(level_vector, set_time); } -bool AsstStartIndertifyOpers(void* p_asst) -{ - if (p_asst == nullptr) { - return false; - } - return ((asst::Assistance*)p_asst)->start_to_identify_opers(); -} - -bool AsstStartInfrast(void* p_asst) -{ - if (p_asst == nullptr) { - return false; - } - return ((asst::Assistance*)p_asst)->start_infrast(); -} +//bool AsstStartIndertifyOpers(void* p_asst) +//{ +// if (p_asst == nullptr) { +// return false; +// } +// return ((asst::Assistance*)p_asst)->start_to_identify_opers(); +//} +// +//bool AsstStartInfrast(void* p_asst) +//{ +// if (p_asst == nullptr) { +// return false; +// } +// return ((asst::Assistance*)p_asst)->start_infrast(); +//} bool AsstStartDebugTask(void* p_asst) { diff --git a/src/MeoAssistance/AsstDef.h b/src/MeoAssistance/AsstDef.h index 1b2c0da218..62675151fe 100644 --- a/src/MeoAssistance/AsstDef.h +++ b/src/MeoAssistance/AsstDef.h @@ -13,28 +13,6 @@ namespace json } namespace asst { - enum class ProcessTaskAction { - Invalid = 0, - BasicClick = 0x100, - ClickSelf = BasicClick | 1, // 点击自身位置 - ClickRect = BasicClick | 2, // 点击指定区域 - ClickRand = BasicClick | 4, // 点击随机区域 - DoNothing = 0x200, // 什么都不做 - Stop = 0x400, // 停止当前Task - StageDrops = 0x800, // 截图 - BasicSwipe = 0x1000, - SwipeToTheLeft = BasicSwipe | 1, // 往左划一下 - SwipeToTheRight = BasicSwipe | 2, // 往右划一下 - }; - - enum class AlgorithmType { - Invaild = -1, - JustReturn, - MatchTemplate, - CompareHist, - OcrDetect - }; - struct Point { Point() = default; @@ -72,6 +50,7 @@ namespace asst { } Rect& operator=(const Rect&) noexcept = default; Rect& operator=(Rect&&) noexcept = default; + bool empty() const noexcept { return width == 0 || height == 0; } bool operator==(const Rect& rhs) const noexcept { return x == rhs.x && y == rhs.y && width == rhs.width && height == rhs.height; @@ -90,28 +69,100 @@ namespace asst { int height = 0; }; - struct TextArea { - TextArea() = default; - TextArea(const TextArea&) = default; - TextArea(TextArea&&) noexcept = default; - template - TextArea(std::string text, RectArgs &&... rect_args) - : text(std::move(text)), - rect(std::forward(rect_args)...) { - static_assert(std::is_constructible::value, - "Parameter can't be used to construct a asst::Rect"); - } - operator std::string() const { return text; } - TextArea& operator=(const TextArea&) = default; - TextArea& operator=(TextArea&&) noexcept = default; - bool operator==(const TextArea& rhs) const noexcept - { + struct TextRect { + TextRect() = default; + TextRect(const TextRect&) = default; + TextRect(TextRect&&) noexcept = default; + + explicit operator std::string() const noexcept { return text; } + explicit operator Rect() const noexcept { return rect; } + TextRect& operator=(const TextRect&) = default; + TextRect& operator=(TextRect&&) noexcept = default; + bool operator==(const TextRect& rhs) const noexcept { return text == rhs.text && rect == rhs.rect; } std::string text; Rect rect; }; + using TextRectProc = std::function; + + enum class AlgorithmType { + Invaild = -1, + JustReturn, + MatchTemplate, + CompareHist, + OcrDetect + }; + + struct MatchRect { + MatchRect() = default; + MatchRect(const MatchRect&) = default; + MatchRect(MatchRect&&) noexcept = default; + + explicit operator Rect() const noexcept { return rect; } + MatchRect& operator=(const MatchRect&) = default; + MatchRect& operator=(MatchRect&&) noexcept = default; + + AlgorithmType algorithm; + double score = 0.0; + Rect rect; + }; + + enum class ProcessTaskAction { + Invalid = 0, + BasicClick = 0x100, + ClickSelf = BasicClick | 1, // 点击自身位置 + ClickRect = BasicClick | 2, // 点击指定区域 + ClickRand = BasicClick | 4, // 点击随机区域 + DoNothing = 0x200, // 什么都不做 + Stop = 0x400, // 停止当前Task + StageDrops = 0x800, // 关卡结束,特化动作 + BasicSwipe = 0x1000, + SwipeToTheLeft = BasicSwipe | 1, // 往左划一下 + SwipeToTheRight = BasicSwipe | 2, // 往右划一下 + }; + + // 任务信息 + struct TaskInfo { + virtual ~TaskInfo() = default; + std::string name; // 任务名 + AlgorithmType algorithm = // 图像算法类型 + AlgorithmType::Invaild; + ProcessTaskAction action = // 要进行的操作 + ProcessTaskAction::Invalid; + std::vector next; // 下一个可能的任务(列表) + int exec_times = 0; // 任务已执行了多少次 + int max_times = INT_MAX; // 任务最多执行多少次 + std::vector exceeded_next; // 达到最多次数了之后,下一个可能的任务(列表) + std::vector reduce_other_times; // 执行了该任务后,需要减少别的任务的执行次数。例如执行了吃理智药,则说明上一次点击蓝色开始行动按钮没生效,所以蓝色开始行动要-1 + asst::Rect specific_rect; // 指定区域,目前仅针对ClickRect任务有用,会点这个区域 + int pre_delay = 0; // 执行该任务前的延时 + int rear_delay = 0; // 执行该任务后的延时 + int retry_times = INT_MAX; // 未找到图像时的重试次数 + Rect roi; // 要识别的区域,若为0则全图识别 + Rect result_move; // 识别结果移动:有些结果识别到的,和要点击的不是同一个位置。即识别到了res,点击res + result_move的位置 + }; + + // 文字识别任务的信息 + struct OcrTaskInfo : public TaskInfo { + virtual ~OcrTaskInfo() = default; + std::vector text; // 文字的容器,匹配到这里面任一个,就算匹配上了 + bool need_full_match = false; // 是否需要全匹配,否则搜索到子串就算匹配上了 + std::unordered_map + replace_map; // 部分文字容易识别错,字符串强制replace之后,再进行匹配 + bool cache = false; // 是否使用历史区域 + std::vector region_of_appeared; // 曾经出现过的区域:上次处理该任务时,在一些rect里识别到过text,这次优先在这些rect里识别,省点性能 + }; + + // 图片匹配任务的信息 + struct MatchTaskInfo : public TaskInfo { + virtual ~MatchTaskInfo() = default; + std::string templ_name; // 匹配模板图片文件名 + double templ_threshold = 0; // 模板匹配阈值 + double hist_threshold = 0; // 直方图比较阈值 + bool cache = false; // 是否使用缓存(直方图),false时就一直用模板匹配。默认为true + }; struct HandleInfo { std::string class_name; @@ -138,116 +189,10 @@ namespace asst { std::string path; }; - // 任务信息 - struct TaskInfo { - virtual ~TaskInfo() = default; - std::string name; // 任务名 - AlgorithmType algorithm = // 图像算法类型 - AlgorithmType::Invaild; - ProcessTaskAction action = // 要进行的操作 - ProcessTaskAction::Invalid; - std::vector next; // 下一个可能的任务(列表) - int exec_times = 0; // 任务已执行了多少次 - int max_times = INT_MAX; // 任务最多执行多少次 - std::vector exceeded_next; // 达到最多次数了之后,下一个可能的任务(列表) - std::vector reduce_other_times; // 执行了该任务后,需要减少别的任务的执行次数。例如执行了吃理智药,则说明上一次点击蓝色开始行动按钮没生效,所以蓝色开始行动要-1 - asst::Rect specific_area; // 指定区域,目前仅针对ClickRect任务有用,会点这个区域 - int pre_delay = 0; // 执行该任务前的延时 - int rear_delay = 0; // 执行该任务后的延时 - int retry_times = INT_MAX; // 未找到图像时的重试次数 - Rect identify_area; // 要识别的区域,若为0则全图识别 - }; - - // 文字识别任务的信息 - struct OcrTaskInfo : public TaskInfo { - virtual ~OcrTaskInfo() = default; - std::vector text; // 文字的容器,匹配到这里面任一个,就算匹配上了 - bool need_match = false; // 是否需要全匹配,否则搜索到子串就算匹配上了 - std::unordered_map - replace_map; // 部分文字容易识别错,字符串强制replace之后,再进行匹配 - bool cache = false; // 是否使用历史区域 - std::vector history_area; // 历史区域:上次处理该任务时,在一些rect里识别到过text,这次优先在这些rect里识别,省点性能 - }; - - // 图片匹配任务的信息 - struct MatchTaskInfo : public TaskInfo { - virtual ~MatchTaskInfo() = default; - std::string template_filename; // 匹配模板图片文件名 - double templ_threshold = 0; // 模板匹配阈值 - double hist_threshold = 0; // 直方图比较阈值 - bool cache = false; // 是否使用缓存(直方图),false时就一直用模板匹配。默认为true - }; - - enum class ConnectType { - Emulator, - USB, - Remote - }; - - struct Options { - ConnectType connect_type; // 连接类型 - std::string connect_remote_address; // 连接局域网中的安卓设备的地址,仅在connectType为Remote时生效 - int task_delay = 0; // 任务间延时:越快操作越快,但会增加CPU消耗 - int control_delay_lower = 0; // 点击随机延时下限:每次点击操作会进行随机延时 - int control_delay_upper = 0; // 点击随机延时上限:每次点击操作会进行随机延时 - bool print_window = false; // 截图功能:开启后每次结算界面会截图到screenshot目录下 - bool upload_to_penguin = false; // 上传企鹅物流:每次到结算界面,是否上传企鹅物流数据统计网站 https://penguin-stats.cn/ - std::string penguin_api; // 企鹅物流汇报接口 - std::string penguin_server; // 企鹅物流汇报接口"server"字段,"CN", "US", "JP" and "KR". - int ocr_gpu_index = -1; // OcrLite使用GPU编号,-1(使用CPU)/0(使用GPU0)/1(使用GPU1)/... - int ocr_thread_number = 0; // OcrLite线程数量 - }; - - struct InfrastOptions { // 基建的选项 - double dorm_threshold = 0; // 宿舍心情百分比阈值,心情百分比小于该值的干员会被放进宿舍 - }; - - // 干员信息,公开招募相关 - struct OperRecruitInfo { - std::string name; - std::string type; - int level = 0; - std::string sex; - std::unordered_set tags; - bool hidden = false; - std::string name_en; - }; - - // 公开招募的干员组合 - struct OperRecruitCombs { - std::vector opers; - int max_level = 0; - int min_level = 0; - double avg_level = 0; - }; - - // 干员信息,基建相关 - struct OperInfrastInfo { - std::string name; - int elite = 0; // 精英化等级 - int level = 0; // 等级 - bool operator==(const OperInfrastInfo& rhs) const { - return name == rhs.name; - } - }; - // 基建干员组合 - struct OperInfrastComb { - std::vector comb; - int efficiency = 0; // 组合的效率 - }; - constexpr double DoubleDiff = 1e-12; } namespace std { - template<> - class hash { - public: - size_t operator()(const asst::OperInfrastInfo& info) const - { - return std::hash()(info.name); - } - }; template<> class hash { public: @@ -260,9 +205,9 @@ namespace std { } }; template<> - class hash { + class hash { public: - size_t operator()(const asst::TextArea& textarea) const + size_t operator()(const asst::TextRect& textarea) const { return std::hash()(textarea.text) ^ std::hash()(textarea.rect); diff --git a/src/MeoAssistance/Configer.h b/src/MeoAssistance/Configer.h deleted file mode 100644 index f3cca09ff5..0000000000 --- a/src/MeoAssistance/Configer.h +++ /dev/null @@ -1,45 +0,0 @@ -#pragma once - -#include "AbstractConfiger.h" - -#include -#include -#include - -#include "AsstDef.h" - -namespace asst { - class Configer : public AbstractConfiger - { - public: - virtual ~Configer() = default; - - static Configer& get_instance() { - static Configer unique_instance; - return unique_instance; - } - - constexpr static int WindowWidthDefault = 1280; - constexpr static int WindowHeightDefault = 720; - constexpr static double TemplThresholdDefault = 0.9; - constexpr static double HistThresholdDefault = 0.9; - - std::string m_version; - Options m_options; - std::unordered_map m_handles; - std::unordered_map m_recruit_ocr_replace; - std::unordered_map m_infrast_ocr_replace; - - InfrastOptions m_infrast_options; - - protected: - Configer() = default; - Configer(const Configer& rhs) = default; - Configer(Configer&& rhs) noexcept = default; - - Configer& operator=(const Configer& rhs) = default; - Configer& operator=(Configer&& rhs) noexcept = default; - - virtual bool parse(const json::value& json) override; - }; -} diff --git a/src/MeoAssistance/WinMacro.cpp b/src/MeoAssistance/Controller.cpp similarity index 81% rename from src/MeoAssistance/WinMacro.cpp rename to src/MeoAssistance/Controller.cpp index 8f881babd8..006186960c 100644 --- a/src/MeoAssistance/WinMacro.cpp +++ b/src/MeoAssistance/Controller.cpp @@ -1,4 +1,4 @@ -#include "WinMacro.h" +#include "Controller.h" #include #include @@ -12,15 +12,15 @@ #include "AsstDef.h" #include "Logger.hpp" -#include "Configer.h" +#include "Resource.h" #include "UserConfiger.h" using namespace asst; -WinMacro::WinMacro() +Controller::Controller() : m_rand_engine(std::chrono::system_clock::now().time_since_epoch().count()) { - DebugTraceFunction; + LogTraceFunction; // 安全属性描述符 m_pipe_sec_attr.nLength = sizeof(SECURITY_ATTRIBUTES); @@ -44,13 +44,13 @@ WinMacro::WinMacro() m_child_startup_info.hStdOutput = m_pipe_child_write; m_child_startup_info.hStdError = m_pipe_child_write; - auto bind_pipe_working_proc = std::bind(&WinMacro::pipe_working_proc, this); + auto bind_pipe_working_proc = std::bind(&Controller::pipe_working_proc, this); m_cmd_thread = std::thread(bind_pipe_working_proc); } -asst::WinMacro::~WinMacro() +asst::Controller::~Controller() { - DebugTraceFunction; + LogTraceFunction; m_thread_exit = true; //m_thread_idle = true; @@ -67,27 +67,27 @@ asst::WinMacro::~WinMacro() ::CloseHandle(m_pipe_child_write); } -Rect asst::WinMacro::shaped_correct(const Rect& rect) const +Rect asst::Controller::shaped_correct(const Rect& rect) const { if (rect.width == 0 || rect.height == 0) { return rect; } // 明日方舟在异形屏上,有的地方是按比例缩放的,有的地方又是直接位移。没法整,这里简单粗暴一点截一个长条 Rect dst = rect; - if (m_scale_size.first != Configer::WindowWidthDefault) { // 说明是宽屏 + if (m_scale_size.first != GeneralConfiger::WindowWidthDefault) { // 说明是宽屏 dst.x = 0; dst.width = m_scale_size.first - 1; } - else if (m_scale_size.second != Configer::WindowHeightDefault) { // 说明是偏方形屏 + else if (m_scale_size.second != GeneralConfiger::WindowHeightDefault) { // 说明是偏方形屏 dst.y = 0; dst.height = m_scale_size.second - 1; } return dst; } -void asst::WinMacro::pipe_working_proc() +void asst::Controller::pipe_working_proc() { - DebugTraceFunction; + LogTraceFunction; while (!m_thread_exit) { std::unique_lock cmd_queue_lock(m_cmd_queue_mutex); @@ -119,9 +119,9 @@ void asst::WinMacro::pipe_working_proc() } } -bool WinMacro::try_capture(const EmulatorInfo& info, bool without_handle) +bool Controller::try_capture(const EmulatorInfo& info, bool without_handle) { - DebugTraceFunction; + LogTraceFunction; const HandleInfo& handle_info = info.handle; std::string adb_dir; @@ -177,7 +177,7 @@ bool WinMacro::try_capture(const EmulatorInfo& info, bool without_handle) if (emulator_path.empty()) { return false; } - UserConfiger::get_instance().set_emulator_path(info.name, emulator_path); + resource.cfg().set_emulator_path(info.name, emulator_path); } else { emulator_path = info.path; @@ -186,7 +186,7 @@ bool WinMacro::try_capture(const EmulatorInfo& info, bool without_handle) // 到这一步说明句柄和权限没问题了,接下来就是adb的事情了 m_emulator_info = info; m_handle = window_handle; - DebugTrace("Handle:", m_handle, "Name:", m_emulator_info.name); + log.trace("Handle:", m_handle, "Name:", m_emulator_info.name); adb_dir = emulator_path.substr(0, emulator_path.find_last_of('\\') + 1); adb_dir = '"' + StringReplaceAll(m_emulator_info.adb.path, "[EmulatorPath]", adb_dir) + '"'; @@ -215,21 +215,21 @@ bool WinMacro::try_capture(const EmulatorInfo& info, bool without_handle) m_emulator_info.adb.display_height = (std::min)(size_value1, size_value2); constexpr double DefaultRatio = - static_cast(Configer::WindowWidthDefault) / static_cast(Configer::WindowHeightDefault); + static_cast(GeneralConfiger::WindowWidthDefault) / static_cast(GeneralConfiger::WindowHeightDefault); double cur_ratio = static_cast(m_emulator_info.adb.display_width) / static_cast(m_emulator_info.adb.display_height); if (cur_ratio >= DefaultRatio // 说明是宽屏或默认16:9,按照高度计算缩放 || std::fabs(cur_ratio - DefaultRatio) < DoubleDiff) { - int scale_width = cur_ratio * Configer::WindowHeightDefault; - m_scale_size = std::make_pair(scale_width, Configer::WindowHeightDefault); - m_control_scale = static_cast(m_emulator_info.adb.display_height) / static_cast(Configer::WindowHeightDefault); + int scale_width = cur_ratio * GeneralConfiger::WindowHeightDefault; + m_scale_size = std::make_pair(scale_width, GeneralConfiger::WindowHeightDefault); + m_control_scale = static_cast(m_emulator_info.adb.display_height) / static_cast(GeneralConfiger::WindowHeightDefault); } else { // 否则可能是偏正方形的屏幕,按宽度计算 - int scale_height = Configer::WindowWidthDefault / cur_ratio; - m_scale_size = std::make_pair(Configer::WindowWidthDefault, scale_height); - m_control_scale = static_cast(m_emulator_info.adb.display_width) / static_cast(Configer::WindowWidthDefault); + int scale_height = GeneralConfiger::WindowWidthDefault / cur_ratio; + m_scale_size = std::make_pair(GeneralConfiger::WindowWidthDefault, scale_height); + m_control_scale = static_cast(m_emulator_info.adb.display_width) / static_cast(GeneralConfiger::WindowWidthDefault); } m_emulator_info.adb.click = StringReplaceAll(m_emulator_info.adb.click, "[Adb]", adb_dir); @@ -239,9 +239,9 @@ bool WinMacro::try_capture(const EmulatorInfo& info, bool without_handle) return true; } -//void asst::WinMacro::set_idle(bool flag) +//void asst::Controller::set_idle(bool flag) //{ -// DebugTraceFunction; +// LogTraceFunction; // // m_thread_idle = flag; // if (!flag) { @@ -252,9 +252,9 @@ bool WinMacro::try_capture(const EmulatorInfo& info, bool without_handle) // } //} -std::vector WinMacro::call_command(const std::string& cmd) +std::vector Controller::call_command(const std::string& cmd) { - DebugTraceFunction; + LogTraceFunction; static std::mutex pipe_mutex; std::unique_lock pipe_lock(pipe_mutex); @@ -287,17 +287,17 @@ std::vector WinMacro::call_command(const std::string& cmd) ::CloseHandle(process_info.hProcess); ::CloseHandle(process_info.hThread); - DebugTrace("Call", cmd, "ret", exit_ret, ", output size:", pipe_data.size()); + log.trace("Call", cmd, "ret", exit_ret, ", output size:", pipe_data.size()); if (!pipe_data.empty() && pipe_data.size() < 4096) { - DebugTrace("output:", std::string(pipe_data.cbegin(), pipe_data.cend())); + log.trace("output:", std::string(pipe_data.cbegin(), pipe_data.cend())); } return pipe_data; } -void asst::WinMacro::convert_lf(std::vector& data) +void asst::Controller::convert_lf(std::vector& data) { - DebugTraceFunction; + LogTraceFunction; if (data.empty() || data.size() <= 1) { return; @@ -328,7 +328,7 @@ void asst::WinMacro::convert_lf(std::vector& data) data.erase(next_iter, data.end()); } -Point asst::WinMacro::rand_point_in_rect(const Rect& rect) +Point asst::Controller::rand_point_in_rect(const Rect& rect) { int x = 0, y = 0; if (rect.width == 0) { @@ -351,7 +351,7 @@ Point asst::WinMacro::rand_point_in_rect(const Rect& rect) return Point(x, y); } -int asst::WinMacro::push_cmd(const std::string& cmd) +int asst::Controller::push_cmd(const std::string& cmd) { std::unique_lock lock(m_cmd_queue_mutex); m_cmd_queue.emplace(cmd); @@ -359,16 +359,16 @@ int asst::WinMacro::push_cmd(const std::string& cmd) return ++m_push_id; } -void asst::WinMacro::wait(unsigned id) const noexcept +void asst::Controller::wait(unsigned id) const noexcept { while (id > m_completed_id) { std::this_thread::yield(); } } -bool asst::WinMacro::screencap() +bool asst::Controller::screencap() { - DebugTraceFunction; + LogTraceFunction; auto data = call_command(m_emulator_info.adb.screencap); if (!data.empty()) { @@ -377,12 +377,12 @@ bool asst::WinMacro::screencap() } m_cache_image = cv::imdecode(data, cv::IMREAD_COLOR); if (m_cache_image.empty()) { - DebugTraceInfo("Data is not empty, but image is empty, try to convert lf"); + log.info("Data is not empty, but image is empty, try to convert lf"); convert_lf(data); m_cache_image = cv::imdecode(data, cv::IMREAD_COLOR); if (m_cache_image.empty()) { m_image_convert_lf = false; - DebugTraceError("convert lf and retry decode falied!"); + log.error("convert lf and retry decode falied!"); return false; } m_image_convert_lf = true; @@ -391,7 +391,7 @@ bool asst::WinMacro::screencap() return true; } else { - DebugTraceError("Data is empty!"); + log.error("Data is empty!"); return false; } @@ -400,25 +400,25 @@ bool asst::WinMacro::screencap() //m_cache_image = std::move(temp_image); } -int WinMacro::click(const Point& p, bool block) +int Controller::click(const Point& p, bool block) { int x = p.x * m_control_scale; int y = p.y * m_control_scale; - //DebugTrace("Click, raw:", p.x, p.y, "corr:", x, y); + //log.trace("Click, raw:", p.x, p.y, "corr:", x, y); return click_without_scale(Point(x, y), block); } -int WinMacro::click(const Rect& rect, bool block) +int Controller::click(const Rect& rect, bool block) { return click(rand_point_in_rect(rect), block); } -int asst::WinMacro::click_without_scale(const Point& p, bool block) +int asst::Controller::click_without_scale(const Point& p, bool block) { if (p.x < 0 || p.x >= m_emulator_info.adb.display_width || p.y < 0 || p.y >= m_emulator_info.adb.display_height) { - DebugTraceError("click point out of range"); + log.error("click point out of range"); } std::string cur_cmd = StringReplaceAll(m_emulator_info.adb.click, "[x]", std::to_string(p.x)); cur_cmd = StringReplaceAll(cur_cmd, "[y]", std::to_string(p.y)); @@ -429,34 +429,34 @@ int asst::WinMacro::click_without_scale(const Point& p, bool block) return id; } -int asst::WinMacro::click_without_scale(const Rect& rect, bool block) +int asst::Controller::click_without_scale(const Rect& rect, bool block) { return click_without_scale(rand_point_in_rect(rect), block); } -int asst::WinMacro::swipe(const Point& p1, const Point& p2, int duration, bool block, int extra_delay) +int asst::Controller::swipe(const Point& p1, const Point& p2, int duration, bool block, int extra_delay) { int x1 = p1.x * m_control_scale; int y1 = p1.y * m_control_scale; int x2 = p2.x * m_control_scale; int y2 = p2.y * m_control_scale; - //DebugTrace("Swipe, raw:", p1.x, p1.y, p2.x, p2.y, "corr:", x1, y1, x2, y2); + //log.trace("Swipe, raw:", p1.x, p1.y, p2.x, p2.y, "corr:", x1, y1, x2, y2); return swipe_without_scale(Point(x1, y1), Point(x2, y2), duration, block, extra_delay); } -int asst::WinMacro::swipe(const Rect& r1, const Rect& r2, int duration, bool block, int extra_delay) +int asst::Controller::swipe(const Rect& r1, const Rect& r2, int duration, bool block, int extra_delay) { return swipe(rand_point_in_rect(r1), rand_point_in_rect(r2), duration, block, extra_delay); } -int asst::WinMacro::swipe_without_scale(const Point& p1, const Point& p2, int duration, bool block, int extra_delay) +int asst::Controller::swipe_without_scale(const Point& p1, const Point& p2, int duration, bool block, int extra_delay) { if (p1.x < 0 || p1.x >= m_emulator_info.adb.display_width || p1.y < 0 || p1.y >= m_emulator_info.adb.display_height || p2.x < 0 || p2.x >= m_emulator_info.adb.display_width || p2.y < 0 || p2.y >= m_emulator_info.adb.display_height) { - DebugTraceError("swipe point out of range"); + log.error("swipe point out of range"); } std::string cur_cmd = StringReplaceAll(m_emulator_info.adb.swipe, "[x1]", std::to_string(p1.x)); cur_cmd = StringReplaceAll(cur_cmd, "[y1]", std::to_string(p1.y)); @@ -477,12 +477,12 @@ int asst::WinMacro::swipe_without_scale(const Point& p1, const Point& p2, int du return id; } -int asst::WinMacro::swipe_without_scale(const Rect& r1, const Rect& r2, int duration, bool block, int extra_delay) +int asst::Controller::swipe_without_scale(const Rect& r1, const Rect& r2, int duration, bool block, int extra_delay) { return swipe_without_scale(rand_point_in_rect(r1), rand_point_in_rect(r2), duration, block, extra_delay); } -cv::Mat asst::WinMacro::get_image(bool raw) +cv::Mat asst::Controller::get_image(bool raw) { if (!screencap()) { return cv::Mat(); diff --git a/src/MeoAssistance/WinMacro.h b/src/MeoAssistance/Controller.h similarity index 87% rename from src/MeoAssistance/WinMacro.h rename to src/MeoAssistance/Controller.h index 554d333d33..8619d086c1 100644 --- a/src/MeoAssistance/WinMacro.h +++ b/src/MeoAssistance/Controller.h @@ -18,15 +18,19 @@ #include "AsstDef.h" namespace asst { - class WinMacro + class Controller { public: - WinMacro(); - ~WinMacro(); + Controller(const Controller&) = delete; + Controller(Controller&&) = delete; + ~Controller(); + + static Controller& get_instance() { + static Controller unique_instance; + return unique_instance; + } bool try_capture(const EmulatorInfo& info, bool without_handle = false); - //void set_idle(bool flag); - cv::Mat get_image(bool raw = false); // 点击和滑动都是异步执行,返回该任务的id @@ -43,7 +47,12 @@ namespace asst { // 异形屏矫正 Rect shaped_correct(const Rect& rect) const; + + Controller& operator=(const Controller&) = delete; + Controller& operator=(Controller&&) = delete; private: + Controller(); + void pipe_working_proc(); std::vector call_command(const std::string& cmd); int push_cmd(const std::string& cmd); @@ -81,4 +90,6 @@ namespace asst { std::pair m_scale_size; double m_control_scale = 1.0; }; + + static auto& ctrler = Controller::get_instance(); } diff --git a/src/MeoAssistance/CreditShopImageAnalyzer.cpp b/src/MeoAssistance/CreditShopImageAnalyzer.cpp new file mode 100644 index 0000000000..24bba53063 --- /dev/null +++ b/src/MeoAssistance/CreditShopImageAnalyzer.cpp @@ -0,0 +1,123 @@ +#include "CreditShopImageAnalyzer.h" + +#include "MultiMatchImageAnalyzer.h" +#include "OcrImageAnalyzer.h" +#include "MatchImageAnalyzer.h" +#include "Resource.h" + +#include "AsstAux.h" + +bool asst::CreditShopImageAnalyzer::analyze() +{ + m_credit_points.clear(); + m_need_to_buy.clear(); + m_result.clear(); + + return credit_point_analyze() + && commoditys_analyze() + && sold_out_analyze(); +} + +bool asst::CreditShopImageAnalyzer::credit_point_analyze() +{ + const static auto credit_point_task_ptr = std::dynamic_pointer_cast( + resource.task().task_ptr("CreditShop-CreditPoint")); + + // 识别信用点的图标 + MultiMatchImageAnalyzer mm_annlyzer( + m_image, + credit_point_task_ptr->roi, + credit_point_task_ptr->templ_name, + credit_point_task_ptr->templ_threshold); + + if (!mm_annlyzer.analyze()) { + return false; + } + auto credit_points_result = mm_annlyzer.get_result(); + if (credit_points_result.empty()) { + return false; + } + // 按位置排个序 + std::sort(credit_points_result.begin(), credit_points_result.end(), + [](const MatchRect& lhs, const MatchRect& rhs) -> bool { + if (std::abs(lhs.rect.y - rhs.rect.y) < 5) { // y差距较小则理解为是同一排的,按x排序 + return lhs.rect.x < rhs.rect.x; + } + else { + return lhs.rect.y < rhs.rect.y; + } + } + ); + m_credit_points.reserve(credit_points_result.size()); + for (const MatchRect& mr : credit_points_result) { + m_credit_points.emplace_back(mr.rect); + } + + return true; +} + +bool asst::CreditShopImageAnalyzer::commoditys_analyze() +{ + for (const Rect& credit_point : m_credit_points) { + // 商品名的区域 + Rect name(credit_point.x - 80, credit_point.y - 210, 230, 70); + if (name.x < 0) { + name.x = 0; + } + + // TODO,哪些要买哪些不买,提供个接口出去 + static const std::vector not_to_buy_names = { "碳", "家具" }; + + OcrImageAnalyzer ocr_analyzer(m_image, name); + if (!ocr_analyzer.analyze()) { + continue; + } + const auto& ocr_res = ocr_analyzer.get_result(); + + auto find_iter = std::find_first_of(ocr_res.cbegin(), ocr_res.cend(), not_to_buy_names.cbegin(), not_to_buy_names.cend(), + [](const auto& lhs, const std::string& rhs) -> bool { + return lhs.text.find(rhs) != std::string::npos; + }); + if (find_iter != ocr_res.cend()) { // 找到了不需要买的名字 +#ifdef LOG_TRACE + cv::putText(m_image, "Not to buy", cv::Point(credit_point.x, credit_point.y), 1, 2, cv::Scalar(255, 0, 0)); +#endif // LOG_TRACE + continue; + } + Rect commodity(credit_point.x - 60, credit_point.y - 180, 220, 220); +#ifdef LOG_TRACE + cv::rectangle(m_image, make_rect(commodity), cv::Scalar(0, 0, 255), 2); +#endif + m_need_to_buy.emplace_back(commodity); + } + return !m_need_to_buy.empty(); +} + +bool asst::CreditShopImageAnalyzer::sold_out_analyze() +{ + const static auto sold_out_task_ptr = std::dynamic_pointer_cast( + resource.task().task_ptr("CreditShop-SoldOut")); + + // 识别是否售罄 + MatchImageAnalyzer sold_out_analyzer( + m_image, + sold_out_task_ptr->roi, + sold_out_task_ptr->templ_name, + sold_out_task_ptr->templ_threshold); + + for (const Rect& commodity : m_need_to_buy) { + sold_out_analyzer.set_roi(commodity); + if (sold_out_analyzer.analyze()) { +#ifdef LOG_TRACE + cv::rectangle(m_image, make_rect(commodity), cv::Scalar(0, 0, 255)); + cv::putText(m_image, "Sold Out", cv::Point(commodity.x, commodity.y), 1, 2, cv::Scalar(255, 0, 0)); +#endif // LOG_TRACE + + // 如果识别到了售罄,那这个商品就不用买了,跳过 + continue; + } + m_result.emplace_back(commodity); + } + + return !m_result.empty(); +} \ No newline at end of file diff --git a/src/MeoAssistance/CreditShopImageAnalyzer.h b/src/MeoAssistance/CreditShopImageAnalyzer.h new file mode 100644 index 0000000000..7e4de30a83 --- /dev/null +++ b/src/MeoAssistance/CreditShopImageAnalyzer.h @@ -0,0 +1,25 @@ +#pragma once +#include "AbstractImageAnalyzer.h" + +namespace asst { + class CreditShopImageAnalyzer final : public AbstractImageAnalyzer + { + public: + using AbstractImageAnalyzer::AbstractImageAnalyzer; + virtual ~CreditShopImageAnalyzer() = default; + + virtual bool analyze() override; + + const std::vector& get_result() const noexcept { + return m_result; + } + protected: + bool credit_point_analyze(); + bool commoditys_analyze(); + bool sold_out_analyze(); + + std::vector m_credit_points; + std::vector m_need_to_buy; + std::vector m_result; + }; +} diff --git a/src/MeoAssistance/CreditShoppingTask.cpp b/src/MeoAssistance/CreditShoppingTask.cpp index ba645de6d7..1e60bd91eb 100644 --- a/src/MeoAssistance/CreditShoppingTask.cpp +++ b/src/MeoAssistance/CreditShoppingTask.cpp @@ -5,116 +5,75 @@ #include -#include "Identify.h" -#include "WinMacro.h" -#include "Configer.h" +#include "Controller.h" +#include "CreditShopImageAnalyzer.h" +#include "MatchImageAnalyzer.h" +#include "OcrImageAnalyzer.h" +#include "Resource.h" bool asst::CreditShoppingTask::run() { - if (m_controller_ptr == nullptr - || m_identify_ptr == nullptr) - { - m_callback(AsstMsg::PtrIsNull, json::value(), m_callback_arg); + const cv::Mat& image = ctrler.get_image(); + + CreditShopImageAnalyzer shop_analyzer(image); + if (!shop_analyzer.analyze()) { return false; } + const auto& shopping_list = shop_analyzer.get_result(); - cv::Mat image = m_controller_ptr->get_image(); - - // 识别信用点的图标 - auto find_res_vec = m_identify_ptr->find_all_images(image, "CreditPoint", Configer::TemplThresholdDefault, false); - - // 按位置排个序 - std::sort(find_res_vec.begin(), find_res_vec.end(), []( - const auto& lhs, const auto& rhs) -> bool { - if (std::abs(lhs.rect.y - rhs.rect.y) < 5) { // y差距较小则理解为是同一排的,按x排序 - return lhs.rect.x < rhs.rect.x; - } - else { - return lhs.rect.y < rhs.rect.y; - } - }); - - // 计算哪些商品是需要买的 - std::vector need_to_buy; - for (const auto& res : find_res_vec) { - cv::Rect name_rect; - name_rect.x = res.rect.x - 80; - name_rect.y = res.rect.y - 210; - name_rect.width = 230; - name_rect.height = 70; - if (name_rect.x < 0) { - name_rect.x = 0; - } - // 过滤掉不买的 - // TODO,哪些要买哪些不买,提供个接口出去 - static const std::vector not_to_buy_names = { "碳", "家具" }; - const auto& ocr_res = m_identify_ptr->ocr_detect(image(name_rect)); - auto find_iter = std::find_first_of(ocr_res.cbegin(), ocr_res.cend(), not_to_buy_names.cbegin(), not_to_buy_names.cend(), - [](const auto& lhs, const std::string& rhs) -> bool { - return lhs.text.find(rhs) != std::string::npos; - }); - if (find_iter != ocr_res.cend()) { -#ifdef LOG_TRACE - cv::putText(image, "Not to buy", cv::Point(res.rect.x, res.rect.y), 1, 2, cv::Scalar(255, 0, 0)); -#endif // LOG_TRACE - continue; - } - Rect commodity_rect(res.rect.x - 60, res.rect.y - 180, 220, 220); - // 识别“售罄” - auto sold_out_res = m_identify_ptr->find_image(image(make_rect(commodity_rect)), "SoldOut"); - -#ifdef LOG_TRACE - cv::rectangle(image, make_rect(commodity_rect), cv::Scalar(0, 0, 255)); - if (sold_out_res.score >= Configer::TemplThresholdDefault) { - cv::putText(image, "Sold Out", cv::Point(commodity_rect.x, commodity_rect.y), 1, 2, cv::Scalar(255, 0, 0)); - } -#endif // LOG_TRACE - - if (sold_out_res.score >= Configer::TemplThresholdDefault) { - continue; - } - need_to_buy.emplace_back(commodity_rect.center_zoom(0.8)); - } - - for (const Rect& commodity_rect : need_to_buy) { + for (const Rect& commodity : shopping_list) { if (need_exit()) { return false; } - m_controller_ptr->click(commodity_rect); - sleep(1000); - image = m_controller_ptr->get_image(); + ctrler.click(commodity); + + static int pre_delay = 1000; + static int rare_delay = 1000; + + sleep(pre_delay); // “购买商品”按钮 static Rect buy_it_rect; - if (buy_it_rect.width == 0) { - auto buy_it_res = m_identify_ptr->find_image(image, "BuyIt", Configer::TemplThresholdDefault); - if (buy_it_res.score < Configer::TemplThresholdDefault) { - // 没事别到“购买商品”按钮,不应该出现这种情况,TODO 报错 + if (buy_it_rect.empty()) { + const auto buy_it_task_ptr = std::dynamic_pointer_cast( + resource.task().task_ptr("CreditShop-BuyIt")); + + const cv::Mat& buy_image = ctrler.get_image(); + MatchImageAnalyzer buy_it_analyzer( + buy_image, + buy_it_task_ptr->roi, + buy_it_task_ptr->templ_name, + buy_it_task_ptr->templ_threshold); + if (!buy_it_analyzer.analyze()) { + // 没识别到“购买商品”按钮,不应该出现这种情况,TODO 报错 return false; } - buy_it_rect = buy_it_res.rect; + buy_it_rect = buy_it_analyzer.get_result().rect; + pre_delay = buy_it_task_ptr->pre_delay; + rare_delay = buy_it_task_ptr->rear_delay; } + if (need_exit()) { return false; } - m_controller_ptr->click(buy_it_rect); - sleep(1000); + ctrler.click(buy_it_rect); + sleep(rare_delay); + // 识别是否信用不足无法购买 - image = m_controller_ptr->get_image(); - static const std::vector shopping_finished = { "信用不足", "无法购买" }; - const auto& ocr_res = ocr_detect(image(cv::Rect(940, 60, 339, 110))); - auto find_iter = std::find_first_of(ocr_res.cbegin(), ocr_res.cend(), shopping_finished.cbegin(), shopping_finished.cend(), - [](const auto& lhs, const std::string& rhs) -> bool { - return lhs.text.find(rhs) != std::string::npos; - }); - if (find_iter != ocr_res.cend()) { + const cv::Mat& prompt_image = ctrler.get_image(); + + const static auto no_money_task_ptr = std::dynamic_pointer_cast( + resource.task().task_ptr("CreditShop-NoMoney")); + OcrImageAnalyzer prompt_analyzer(prompt_image, no_money_task_ptr->roi); + prompt_analyzer.set_required(no_money_task_ptr->text); + if (prompt_analyzer.analyze()) { click_return_button(); return true; } // 这里随便点一下都行,把购买完弹出来物品的界面取消掉 - m_controller_ptr->click(buy_it_rect); - sleep(1000); + ctrler.click(buy_it_rect); + sleep(rare_delay); } return true; diff --git a/src/MeoAssistance/CreditShoppingTask.h b/src/MeoAssistance/CreditShoppingTask.h index 2a9331fe1b..0c8b2396a4 100644 --- a/src/MeoAssistance/CreditShoppingTask.h +++ b/src/MeoAssistance/CreditShoppingTask.h @@ -1,15 +1,16 @@ #pragma once -#include "OcrAbstractTask.h" + +#include "AbstractTask.h" #include #include "AsstDef.h" namespace asst { - class CreditShoppingTask : public OcrAbstractTask + class CreditShoppingTask : public AbstractTask { public: - using OcrAbstractTask::OcrAbstractTask; + using AbstractTask::AbstractTask; virtual ~CreditShoppingTask() = default; virtual bool run() override; private: diff --git a/src/MeoAssistance/Configer.cpp b/src/MeoAssistance/GeneralConfiger.cpp similarity index 71% rename from src/MeoAssistance/Configer.cpp rename to src/MeoAssistance/GeneralConfiger.cpp index 1ca5da5602..3b25fd3d6c 100644 --- a/src/MeoAssistance/Configer.cpp +++ b/src/MeoAssistance/GeneralConfiger.cpp @@ -1,16 +1,8 @@ -#include "Configer.h" - -#include -#include -#include +#include "GeneralConfiger.h" #include -#include "Logger.hpp" - -using namespace asst; - -bool asst::Configer::parse(const json::value& json) +bool asst::GeneralConfiger::parse(const json::value& json) { m_version = json.at("version").as_string(); @@ -28,13 +20,6 @@ bool asst::Configer::parse(const json::value& json) m_options.penguin_server = options_json.get("penguinServer", "CN"); m_options.ocr_thread_number = options_json.at("ocrThreadNumber").as_integer(); } - DebugTrace("Options", options_json.to_string()); - - const json::value& infrast_options_json = json.at("infrastOptions"); - { - m_infrast_options.dorm_threshold = infrast_options_json.get("dormThreshold", 0.3); - } - DebugTrace("InfrastOptions", infrast_options_json.to_string()); for (const auto& [name, emulator_json] : json.at("emulator").as_object()) { EmulatorInfo emulator_info; @@ -56,14 +41,7 @@ bool asst::Configer::parse(const json::value& json) emulator_info.path = emulator_json.get("path", std::string()); - m_handles.emplace(name, std::move(emulator_info)); - } - - for (const json::value& rep : json.at("infrastOcrReplace").as_array()) { - m_infrast_ocr_replace.emplace(rep.as_array()[0].as_string(), rep.as_array()[1].as_string()); - } - for (const json::value& rep : json.at("recruitOcrReplace").as_array()) { - m_recruit_ocr_replace.emplace(rep.as_array()[0].as_string(), rep.as_array()[1].as_string()); + m_emulators_info.emplace(name, std::move(emulator_info)); } return true; diff --git a/src/MeoAssistance/GeneralConfiger.h b/src/MeoAssistance/GeneralConfiger.h new file mode 100644 index 0000000000..8bdd44cbb5 --- /dev/null +++ b/src/MeoAssistance/GeneralConfiger.h @@ -0,0 +1,73 @@ +#pragma once + +#include "AbstractConfiger.h" + +#include +#include +#include + +#include "AsstDef.h" + +namespace asst { + enum class ConnectType { + Emulator, + USB, + Remote + }; + + struct Options { + ConnectType connect_type; // 连接类型 + std::string connect_remote_address; // 连接局域网中的安卓设备的地址,仅在connectType为Remote时生效 + int task_delay = 0; // 任务间延时:越快操作越快,但会增加CPU消耗 + int control_delay_lower = 0; // 点击随机延时下限:每次点击操作会进行随机延时 + int control_delay_upper = 0; // 点击随机延时上限:每次点击操作会进行随机延时 + bool print_window = false; // 截图功能:开启后每次结算界面会截图到screenshot目录下 + bool upload_to_penguin = false; // 上传企鹅物流:每次到结算界面,是否上传企鹅物流数据统计网站 https://penguin-stats.cn/ + std::string penguin_api; // 企鹅物流汇报接口 + std::string penguin_server; // 企鹅物流汇报接口"server"字段,"CN", "US", "JP" and "KR". + int ocr_gpu_index = -1; // OcrLite使用GPU编号,-1(使用CPU)/0(使用GPU0)/1(使用GPU1)/... + int ocr_thread_number = 0; // OcrLite线程数量 + }; + + class GeneralConfiger : public AbstractConfiger + { + public: + virtual ~GeneralConfiger() = default; + + constexpr static int WindowWidthDefault = 1280; + constexpr static int WindowHeightDefault = 720; + + const std::string& get_version() const noexcept + { + return m_version; + } + const Options& get_options() const noexcept + { + return m_options; + } + const std::unordered_map& get_emulators_info() const noexcept + { + return m_emulators_info; + } + + void set_options(Options opt) noexcept + { + m_options = std::move(opt); + } + void set_emulator_info(std::string name, EmulatorInfo emu) + { + m_emulators_info.emplace(std::move(name), std::move(emu)); + } + void set_emulator_path(std::string name, std::string path) + { + m_emulators_info[name].path = path; + } + + protected: + virtual bool parse(const json::value& json) override; + + std::string m_version; + Options m_options; + std::unordered_map m_emulators_info; + }; +} diff --git a/src/MeoAssistance/Identify.cpp b/src/MeoAssistance/Identify.cpp deleted file mode 100644 index 1596803cf3..0000000000 --- a/src/MeoAssistance/Identify.cpp +++ /dev/null @@ -1,349 +0,0 @@ -#include "Identify.h" - -#include -#include -#include - -#include -#include - -#include - -namespace penguin { -#include -} - -#include "Logger.hpp" -#include "AsstAux.h" -#include "Configer.h" - -using namespace asst; -using namespace cv; - -bool Identify::add_image(const std::string& name, const std::string& path) -{ - Mat image = imread(path); - if (image.empty()) { - return false; - } - m_mat_map.emplace(name, image); - return true; -} - -Mat Identify::image_2_hist(const cv::Mat& src) -{ - //Mat src_hsv; - //cvtColor(src, src_hsv, COLOR_BGR2HSV); - - int histSize[] = { 50, 60 }; - float h_ranges[] = { 0, 180 }; - float s_ranges[] = { 0, 256 }; - const float* ranges[] = { h_ranges, s_ranges }; - int channels[] = { 0, 1 }; - - MatND src_hist; - - calcHist(&src, 1, channels, Mat(), src_hist, 2, histSize, ranges); - normalize(src_hist, src_hist, 0, 1, NORM_MINMAX); - - return src_hist; -} - -double Identify::image_hist_comp(const cv::Mat& src, const cv::MatND& hist) -{ - // keep the interface return value unchanged - return 1 - compareHist(image_2_hist(src), hist, CV_COMP_BHATTACHARYYA); -} - -std::vector