From fcf5bb696ceace6f78373d3d9560e12f786b1e7e Mon Sep 17 00:00:00 2001 From: Horror Proton <107091537+horror-proton@users.noreply.github.com> Date: Sun, 25 Aug 2024 21:31:34 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E4=BD=BF=E7=94=A8=E5=8F=98=E6=8D=A2?= =?UTF-8?q?=E5=90=8E=E7=9A=84=E5=9B=BE=E5=83=8F=E8=BF=9B=E8=A1=8C=E6=8A=80?= =?UTF-8?q?=E8=83=BD=E6=8C=89=E9=92=AE=E8=AF=86=E5=88=AB=20(#10293)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: use `cv::warpPerspective` in `use_skill` * chore: remove unused reclamation task info * chore: Auto update by pre-commit hooks --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .../include/Arknights-Tile-Pos/TileCalc2.hpp | 24 +-- resource/tasks.json | 27 +-- .../BattleSkillReadyOnClick-SquareMap.png | Bin 386 -> 0 bytes .../BattleSkillReadyOnClick-TopView.png | Bin 0 -> 3389 bytes resource/template/BattleSkillReadyOnClick.png | Bin 493 -> 0 bytes .../BattleSkillStopOnClick-MiddleMap.png | Bin 563 -> 0 bytes .../BattleSkillStopOnClick-SquareMap.png | Bin 458 -> 0 bytes .../BattleSkillStopOnClick-TopView.png | Bin 0 -> 895 bytes resource/template/BattleSkillStopOnClick.png | Bin 761 -> 0 bytes src/MaaCore/Task/BattleHelper.cpp | 175 +++++++++--------- src/MaaCore/Task/BattleHelper.h | 2 + 11 files changed, 105 insertions(+), 123 deletions(-) delete mode 100644 resource/template/BattleSkillReadyOnClick-SquareMap.png create mode 100644 resource/template/BattleSkillReadyOnClick-TopView.png delete mode 100644 resource/template/BattleSkillReadyOnClick.png delete mode 100644 resource/template/BattleSkillStopOnClick-MiddleMap.png delete mode 100644 resource/template/BattleSkillStopOnClick-SquareMap.png create mode 100644 resource/template/BattleSkillStopOnClick-TopView.png delete mode 100644 resource/template/BattleSkillStopOnClick.png diff --git a/3rdparty/include/Arknights-Tile-Pos/TileCalc2.hpp b/3rdparty/include/Arknights-Tile-Pos/TileCalc2.hpp index 3be61f8fe5..4bda0b8cfa 100644 --- a/3rdparty/include/Arknights-Tile-Pos/TileCalc2.hpp +++ b/3rdparty/include/Arknights-Tile-Pos/TileCalc2.hpp @@ -39,8 +39,8 @@ inline matrix4x4 camera_matrix_from_trans( const vec3d& euler, double ratio, double fov_2_y = 20 * degree, - double far = 1000, - double near = 0.3) + double far_c = 1000, + double near_c = 0.3) { const double cos_y = std::cos(euler[0]); const double sin_y = std::sin(euler[0]); @@ -66,11 +66,11 @@ inline matrix4x4 camera_matrix_from_trans( 0, -sin_x, -cos_x, 0, // 0, 0, 0, 1, }; - const matrix4x4 proj = { + const matrix4x4 proj = matrix4x4 { // clang-format off ratio / tan_f, 0, 0, 0, 0, 1 / tan_f, 0, 0, - 0, 0, -(far + near) / (far - near), -(far * near * 2) / (far - near), + 0, 0, -(far_c + near_c) / (far_c - near_c), -(far_c * near_c * 2) / (far_c - near_c), 0, 0, -1, 0, // clang-format on }; @@ -78,14 +78,13 @@ inline matrix4x4 camera_matrix_from_trans( return proj * matrixX * matrixY * translate; } -inline cv::Point - world_to_screen(const Level& level, const vec3d& world_pos, bool side, const vec3d& offset = {}) +inline cv::Point world_to_screen(const Level& level, const vec3d& world_pos, bool side, const vec3d& offset = {}) { - static constexpr double width = 1280; - static constexpr double height = 720; + static constexpr int width = 1280; + static constexpr int height = 720; const vec3d pos_cam = camera_pos(level, side, width, height) + offset; const vec3d euler = camera_euler_angles_yxz(level, side); - const matrix4x4 matrix = camera_matrix_from_trans(pos_cam, euler, height / width); + const matrix4x4 matrix = camera_matrix_from_trans(pos_cam, euler, static_cast(height) / width); auto result = matrix * cv::Point3d(world_pos); result = result / result(3); result = (result + cv::Vec4d::ones()) / 2.; @@ -107,12 +106,7 @@ inline vec3d get_tile_world_pos(const Level& level, int tile_y, int tile_x) }; } -inline auto get_tile_screen_pos( - const Level& level, - int tile_y, - int tile_x, - bool side = false, - const vec3d& offset = {}) +inline auto get_tile_screen_pos(const Level& level, int tile_y, int tile_x, bool side = false, const vec3d& offset = {}) { return world_to_screen(level, get_tile_world_pos(level, tile_y, tile_x), side, offset); } diff --git a/resource/tasks.json b/resource/tasks.json index 218968b07f..0ed47e894c 100644 --- a/resource/tasks.json +++ b/resource/tasks.json @@ -4634,25 +4634,9 @@ "BattleSkillReady": { "rectMove": [-28, -140, 64, 64] }, - "BattleSkillReadyOnClick": { - "roi": [748, 414, 210, 118], - "templThreshold": 0.7, - "action": "ClickSelf", - "rectMove": [0, -110, 90, 90], - "postDelay": 300, - "next": ["#self", "Stop"] - }, - "BattleSkillReadyOnClick-SquareMap": { - "baseTask": "BattleSkillReadyOnClick" - }, - "BattleSkillStopOnClick": { - "baseTask": "BattleSkillReadyOnClick" - }, - "BattleSkillStopOnClick-MiddleMap": { - "baseTask": "BattleSkillReadyOnClick" - }, - "BattleSkillStopOnClick-SquareMap": { - "baseTask": "BattleSkillReadyOnClick" + "BattleSkillReadyOnClick-TopView": { + "template": ["BattleSkillReadyOnClick-TopView.png", "BattleSkillStopOnClick-TopView.png"], + "templThreshold": [0.8, 0.8] }, "BattleUseOper": { "algorithm": "JustReturn", @@ -10718,11 +10702,6 @@ "template": "Fire@Reclamation@ClickExitLevel.png", "roi": [100, 0, 164, 166] }, - "Fire@Reclamation@BattleSkillReadyOnClick": { - "baseTask": "BattleSkillReadyOnClick", - "template": "BattleSkillReadyOnClick.png", - "roi": [439, 76, 841, 644] - }, "Fire@Reclamation@BattleStart": { "baseTask": "Fire@Reclamation@BattlePackIconTemplate", "template": "Fire@Reclamation@ClickExitLevel.png", diff --git a/resource/template/BattleSkillReadyOnClick-SquareMap.png b/resource/template/BattleSkillReadyOnClick-SquareMap.png deleted file mode 100644 index 05ad1fa9c400f2faa7367037b1fed32326d2a860..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 386 zcmV-|0e$|7P)cI6V#x?wR23Zt*J$RVI5L1i36+c>{!Rvl6>lqM zFNC!3uV?rx^g@DrF~Vhrenc}2|8Uh?=71Guj@9Nhf8G`@+0zblD1~jv2<&o}i zX>+%e0w)YJPZt1!mH+?%07*qoM6N<$f?pk|LI3~& diff --git a/resource/template/BattleSkillReadyOnClick-TopView.png b/resource/template/BattleSkillReadyOnClick-TopView.png new file mode 100644 index 0000000000000000000000000000000000000000..4df32a40193ba90aca0a526d16291ab5aee2c60d GIT binary patch literal 3389 zcmV-D4Z`w?P)iEAisH-!QkGx@7(`A+dTYm=@;QH*f_8y@s*VEa}{x| z;QdEAIu9V=X9*5>pbFF;Yon4-5pbbN;o2w?kOtJC0d&g-)LH?k)@rCVf<|mEg9;JX&Ak&s zjI~>PvgRR9?Ep;aIzXtk_;EFnQfUyYm+y(?g>Y)zn;NT>3qC|#H)xo{DkWJdMPV2< zCr6PeEl2rV!PJE7*CYs|DTG#}1e8{S(u%)2M}vZm>Qu|&=%wPtQ}s(9_#dCCO z9RDc2Q5~qe;rIV5|J|1>ue?#zZ@n@8^0%&EJr_vD05I@{9hdc*s7DJzm!zzRUJ%q|y(EPv zMHp#}pn(8=?R;!0uhFcHj~8aA%Awx~)fQo>&Ytupu6PTTg|aBj7O$SZ^xQ&llf&XMXZ3Nl9z26JgyInlasq1%v#KR<6q|# zmw*ZYeBU3vT=px@j^W&vK^rN$GbbI(l}%y{q3(&*@X@5gO} z!^wEk-nKovbzo`k*3zr5mVe`GBLFZnQ=Xj;I{Vs29*igA(AX?(@Er|Y>0F#2iShdp zcysegdu~u5B7-G3%P>lDN)j>+QiFm|g%P5*0A$RLA+QEWmgw$ki&@#?B6wvE3K10& zAd^8P?U+GCtO*gB61i;VI~hS?roND`WHa$y`<-0h^3*7m3yCOXx+P#`MJtpPm$gbn zTym3A8RyZ*`*-i-1o2y!jfESWq}|!?96Zt|wai~twUQHt?8M3G(gGjZAM5HjiJFCS zqwgT7UgwF7xu0S3wp6EV)`uJcSBWE73D#~?xL7;45?%u?;O=lvoJ^n~lTLub<~=mZ z$OpH|Y;I+o1Smk#p-&1Vpi+vp(z;rOF--)`+8p{KKUI{Tx%*&0u=-~XbzMHSG&5D$ zv8N+#HBVQUSCm4@f~6@vzDm86hMv+~WC3sRAcNGaqTkA2a} zw9#6{b-l&KYBHT19BxCXZW-)EzC1BndhDqV&}%#L>WUk{$qxJK!%iHmiZQ;!u`FGwKkEPkphlV=ZV@MhRLl3p2 z%7S_RLbvXL;wpRSJx#^Y3>&i|gQ`=^UWqDi<48`)3+AX=M4vV!?j~ydI zTZkXI01>*vMY9(AU4Gz40xb(OUC_UiE?(f*ez;l$JL1XY(2)gzG-w3epbnUn$ytwd zIA0))!97rQadRa&73w980zMTY^n5|Y7W1|5y>&%{4E)vCOf12kc&6u(rv~B)Q!{}` zwF-d3wp?a-hhsR^FbX0O5EtnjwOTkiHdddT!M%r^?mkm%O&kWcXY!NPYggubb`C-V zJBFsoL}-EDaJ+TTvmJrj@PaCFyCIw&9%;+9EnGaApT8CEJ(}9HFUFY<8{vqQFo*h_ zUm~>O)6iOnfhsI}?+1EOK>(Y;^Fq=_M^9|qh-o@{`etSHVxqT$fBwk>W?B>Zh)6_% z3uuUKBk`w>cXbbB0d=$O7fd#`$ADR-nf9>i=f~mQ??kCg4K%tn3?uK{+34sq8VLX) zks$(7N}HBIpmoE`E1_S7n4>J)Gpw$r;K{7>z@hfpn_<0L9UMuwWs}YS8yoVD#ghqZ z7vh$CRcIyjaxpkn3NJLI*%U%~N~Lx^#EyKyN~Nt6Z|mtBwv5z`(S_ZeosEiZFvc}# zW`$<5DlI$YylLRZCfF<7Qj#jgO;>OI-eSH9sX(JJkR3edX z)g9DI>cyF$IL$lzqGZa)wY;K;LtD4Q8HH-uNoEL*JNr4x@dHUVQkK^$;z~8VSPssX zgOla(w9?+j?#}h)L^=8}g!1M)<}h+WlOF^?%1Q9yk)B--^p`5Z#q)W;DnRi@7sq08 zAY=#(Y5jJfThfRqnjK%5o2kdz=l370ANx}M^S@gEmEVcJ{MF?B_jN57>!(kZP@__i z&XQM$C=4Bov|?J*>Q#6B)pSn8`}&hZJGP@1#|H^UIXU)M)#sg-oA;n>--TQ~PS#-I7hL#sX*g;EMtt*)+99KBR^ z3yI1yOLa(MAcca4NZiAXWkw^`~JMq2EF&YEYYFY76&E4=8j)4f~IsTjtF3p7UafNTWsujO%z>XWLA71!k^6Jjo9~I+RF$l9IVWs~2&* zqut0R1Fxj#rt6t*!>wxog(4_SS9!t8Ppiw9CML$_ipAjA)7$nv-1W(#*s@EU#4l=EXVNvPi{Ux1Q<@4JWxy}oyOrP0Hw6Q_i#pw zEv15=vXWYI#=Je_B~6X!2H%)J~8?C39jlztwk?b@A0?_SCH{X!}0a}lr zG$5>3yjHJ&HxPhYmWX?*!?eb3`^&w~vqapN*B8Rq7W~spDfkJY0dVd8r-1(jtg!g* T5FXI#00000NkvXXu0mjfKGL7X literal 0 HcmV?d00001 diff --git a/resource/template/BattleSkillReadyOnClick.png b/resource/template/BattleSkillReadyOnClick.png deleted file mode 100644 index 0aab185168086e7fced1ad72ca6c4448b0b52e05..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 493 zcmVa|R0005BNkl0U2;t1heHdT-C44nA+Ga%C>^PkhY<1a}6qPd$p9DO7LmSoa zewkdApvzOznvA?Tr|d4MhdQ-gvGU^2lZ)!G$H_`+Kf`Z$uISR(Tjq4=eAE<^mY}v! zO#V7iUiWF@TLx6O2a7qP-xi?w6CP~8-&=k9`TAz2K#v%1KdK|^UOFjlu47e`bctfW z23$;q04#^6bMlTbZ)>y9`7|-VsN4i}Kvc7wSIs|N4?z2oIhb~;FiX6wwC@~k9T&Ag6Z j?W*xES>6~``RaBbKbD^a@;++E00000NkvXXu0mjfx^C>& diff --git a/resource/template/BattleSkillStopOnClick-MiddleMap.png b/resource/template/BattleSkillStopOnClick-MiddleMap.png deleted file mode 100644 index e88755b44a80129395c040083082d66505bf77c8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 563 zcmV-30?hr1P) zr2^ZtdI2DA60V>PlT;=tRT8P?Ed&HjIAVqqn=-oTh^m>>OdV;>to7#a-2ri-#sZrZ zMnn_IvuEx+1#Kn-`5%NlLOqY{te{B@6yVJ!N-7E0Mu%vYQv$mP@$-Zo5=>Jv$%H1SI|t(Jbxb|?Ep6Iz%=ID3jiUDC-`0d%H{lrU)D3v}OyR{<-- zD@$L$5Oq-$KxTSiizZ0Utc?%3S1&7RL(XbS%8zJ2mK2+~oqu=~dW`3AKm3>@R;1prV07#;iqVLm+_95|hi2Sps%&`-k1S+TLU z_afyPz<2=sUtmT2rSR&$Cw=+~-lG%BZF-WOK?H-COq8lt{tkPk5={$*#H^qX& zWWjITSx&xKXf31KiP9xkCJn}0kbMi<|BWhvCQIn<77+p+;Wd%YM8Mjt16Yktdq7?& zWup}@5|~Iz1InE0n01^#Y&Id#HYJQ-`wkm zp?XBka*necTbus&hwkPFOb#xvgt^6X8tykcKU)2_ks+(47RLHDw(kH;2IpA>^K*-O z$*EmZOs6bTkI9MDP`zqV7SLl$A5ogh6&?T#G0|jhJg%ZCIWl~D-YgD$|0+PP=N1#q zS`u2S9`W_?MNxFf`6Q8mEwNZey`@HoT)!P}ysPW4iNS29vl$P*5+5*QHbIq~&bD}R zYHDk0(d4eat=o5W`<8?NX7$AF{-R#Nz$iOZ!)1wVT918-s@aOZwl*Ye0Dv{j1=i_5}V}~NRuN`J+=&=KF^ZP ziuNjCNz9Ul7N-`MQavyQ5k~tdTXilc>9@P=mKEppb*x}i3KHNjV@`aryoOIfn zL^C@4>@K0Dt9{p7bA{#cG;}YK6V(M4bMr*v+}6$ZN1y0qoa@SR1WYVkx#2Fq30%-= z#llIawZBo`dS6XYhjX|B0l*A|$+`DSX~{qQmiwQ|gU|KXuleIU9{Ti1vVbhSYGMe;=^jDmJmlps{0Ebw Vne$FfnacnG002ovPDHLkV1k*Esto`D literal 0 HcmV?d00001 diff --git a/resource/template/BattleSkillStopOnClick.png b/resource/template/BattleSkillStopOnClick.png deleted file mode 100644 index 5d6645b98f221ca273411afca6278507a92fd6a7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 761 zcmVDc$-4mY^70{j}g zWC5&%b>OlM9IkMOzsqRTnYKv|$-LVB>hg=72YUj5fo4-(&TB+D!D=jihFwA{ZWPyw zcS@I~r7V8vRWX=ib`OpTjxKs<)B=+`?77b`fAn^y&Y^A4*8beojWwdUF}(2^FArvY zIf60O5`Zw*)5|{6UwSwu$A}@%5?GldRjeS|RyQ7@s zV}e1m#aZHliH_ua(wAcxqx?6@Mu0|Lb>wJBL{_cf7)&986S*HUhUV?MBL^wM;7HD= zuJew(581iHkP&NJE<3VJf}-%UX_1bc-;o1weeJLPT}E-pswanX46YS)10p|iuN))U zn$@Mf>_cYD4U7gcYy;Dv-3V#5T6j6mkxx$KZpfsQNBX-@$^OHvS(mOuyRGzv-!Zz! zC)6>ztt0P4wm2NNxaE=RuZ{WZip+*0{~slH21OR${gN2pgmeJM4fl0q2dTLWnMjK8 z$v2A!-;h#51P~I^pZ)G3I3~CEW!JL{S(FqM9mwbaXR!vZcy;L$S}QEh_2ofZ(iiU{ rjIq9q%@zN5Q~F=)Gv~GfGxq!kl@nT|Uc?DH00000NkvXXu0mjf&G2V( diff --git a/src/MaaCore/Task/BattleHelper.cpp b/src/MaaCore/Task/BattleHelper.cpp index c5a62cf07e..9c4407f450 100644 --- a/src/MaaCore/Task/BattleHelper.cpp +++ b/src/MaaCore/Task/BattleHelper.cpp @@ -3,6 +3,7 @@ #include #include +#include "Config/GeneralConfig.h" #include "Config/Miscellaneous/AvatarCacheManager.h" #include "Config/Miscellaneous/BattleDataConfig.h" #include "Config/TaskData.h" @@ -11,16 +12,19 @@ #include "Utils/ImageIo.hpp" #include "Utils/Logger.hpp" #include "Utils/NoWarningCV.h" +#include "Utils/Time.hpp" #include "Vision/Battle/BattlefieldClassifier.h" #include "Vision/Battle/BattlefieldMatcher.h" #include "Vision/BestMatcher.h" #include "Vision/Matcher.h" #include "Vision/RegionOCRer.h" +#include "Arknights-Tile-Pos/TileCalc2.hpp" + using namespace asst::battle; -asst::BattleHelper::BattleHelper(Assistant* inst) - : m_inst_helper(inst) +asst::BattleHelper::BattleHelper(Assistant* inst) : + m_inst_helper(inst) { } @@ -54,10 +58,7 @@ void asst::BattleHelper::clear() m_used_tiles.clear(); } -bool asst::BattleHelper::calc_tiles_info( - const std::string& stage_name, - double shift_x, - double shift_y) +bool asst::BattleHelper::calc_tiles_info(const std::string& stage_name, double shift_x, double shift_y) { LogTraceFunction; @@ -99,7 +100,7 @@ bool asst::BattleHelper::update_deployment(bool init, const cv::Mat& reusable, b LogTraceFunction; if (init) { - AvatarCache.remove_avatars(Role::Drone);// 移除小龙等不同技能很像的召唤物,防止错误识别 + AvatarCache.remove_avatars(Role::Drone); // 移除小龙等不同技能很像的召唤物,防止错误识别 wait_until_start(false); } @@ -157,14 +158,12 @@ bool asst::BattleHelper::update_deployment(bool init, const cv::Mat& reusable, b Log.trace("start matching cooling", oper.index); static const auto cooling_threshold = Task.get("BattleAvatarCoolingData")->templ_thresholds.front(); - static const auto cooling_mask_range = - Task.get("BattleAvatarCoolingData")->mask_ranges; + static const auto cooling_mask_range = Task.get("BattleAvatarCoolingData")->mask_ranges; avatar_analyzer.set_threshold(cooling_threshold); avatar_analyzer.set_mask_ranges(cooling_mask_range, true, true); } else { - static const auto threshold = - Task.get("BattleAvatarData")->templ_thresholds.front(); + static const auto threshold = Task.get("BattleAvatarData")->templ_thresholds.front(); static const auto drone_threshold = Task.get("BattleDroneAvatarData")->templ_thresholds.front(); avatar_analyzer.set_threshold(oper.role == Role::Drone ? drone_threshold : threshold); @@ -208,8 +207,7 @@ bool asst::BattleHelper::update_deployment(bool init, const cv::Mat& reusable, b } } - if (ranges::count_if(unknown_opers, [](const DeploymentOper& it) { return !it.cooling; }) > 0 - || init) { + if (ranges::count_if(unknown_opers, [](const DeploymentOper& it) { return !it.cooling; }) > 0 || init) { // 一个都没匹配上的,挨个点开来看一下 LogTraceScope("rec unknown opers"); @@ -285,6 +283,38 @@ bool asst::BattleHelper::update_deployment(bool init, const cv::Mat& reusable, b return check_in_battle(image); } +// if side = true, get top view of the selected operator, tile size is 5x5 +cv::Mat asst::BattleHelper::get_top_view(const cv::Mat& cam_img, bool side) +{ + if (!side) { + return cv::Mat {}; // TODO + } + + const std::vector world_points { + { -2.5, -2.5 }, + { 2.5, -2.5 }, + { -2.5, 2.5 }, + { 2.5, 2.5 }, + }; + const std::vector dst_points { + { 0, 0 }, + { 500, 0 }, + { 0, 500 }, + { 500, 500 }, + }; + std::vector screen_points; + for (const auto& point : world_points) { + cv::Vec3d temp { point.x, -point.y, -0.3967874050140381 }; + auto screen_pt = Map::TileCalc2::world_to_screen(m_map_data, temp, true); + screen_points.push_back(screen_pt); + } + + const auto xform = cv::getPerspectiveTransform(screen_points, dst_points); + cv::Mat result; + cv::warpPerspective(cam_img, result, xform, cv::Size(500, 500)); + return result; +} + bool asst::BattleHelper::update_kills(const cv::Mat& reusable) { cv::Mat image = reusable.empty() ? m_inst_helper.ctrler()->get_image() : reusable; @@ -314,10 +344,7 @@ bool asst::BattleHelper::update_cost(const cv::Mat& reusable) return true; } -bool asst::BattleHelper::deploy_oper( - const std::string& name, - const Point& loc, - DeployDirection direction) +bool asst::BattleHelper::deploy_oper(const std::string& name, const Point& loc, DeployDirection direction) { LogTraceFunction; @@ -337,9 +364,8 @@ bool asst::BattleHelper::deploy_oper( } Point target_point = target_iter->second.pos; - int dist = static_cast(Point::distance( - target_point, - { oper_rect.x + oper_rect.width / 2, oper_rect.y + oper_rect.height / 2 })); + int dist = static_cast( + Point::distance(target_point, { oper_rect.x + oper_rect.width / 2, oper_rect.y + oper_rect.height / 2 })); // 1000 是随便取的一个系数,把整数的 pre_delay 转成小数用的 int duration = static_cast(dist / 1000.0 * swipe_oper_task_ptr->pre_delay); @@ -347,9 +373,8 @@ bool asst::BattleHelper::deploy_oper( if (int min_duration = swipe_oper_task_ptr->special_params.at(4); duration < min_duration) { duration = min_duration; } - bool deploy_with_pause = ControlFeat::support( - m_inst_helper.ctrler()->support_features(), - ControlFeat::SWIPE_WITH_PAUSE); + bool deploy_with_pause = + ControlFeat::support(m_inst_helper.ctrler()->support_features(), ControlFeat::SWIPE_WITH_PAUSE); Point oper_point(oper_rect.x + oper_rect.width / 2, oper_rect.y + oper_rect.height / 2); m_inst_helper.ctrler()->swipe( oper_point, @@ -447,9 +472,7 @@ bool asst::BattleHelper::retreat_oper(const Point& loc, bool manually) m_used_tiles.erase(loc); if (manually) { - std::erase_if(m_battlefield_opers, [&loc](const auto& pair) -> bool { - return pair.second == loc; - }); + std::erase_if(m_battlefield_opers, [&loc](const auto& pair) -> bool { return pair.second == loc; }); } return true; } @@ -611,10 +634,7 @@ bool asst::BattleHelper::use_all_ready_skill(const cv::Mat& reusable) return used; } -bool asst::BattleHelper::check_and_use_skill( - const std::string& name, - bool& has_error, - const cv::Mat& reusable) +bool asst::BattleHelper::check_and_use_skill(const std::string& name, bool& has_error, const cv::Mat& reusable) { auto oper_iter = m_battlefield_opers.find(name); if (oper_iter == m_battlefield_opers.cend()) { @@ -624,10 +644,7 @@ bool asst::BattleHelper::check_and_use_skill( return check_and_use_skill(oper_iter->second, has_error, reusable); } -bool asst::BattleHelper::check_and_use_skill( - const Point& loc, - bool& has_error, - const cv::Mat& reusable) +bool asst::BattleHelper::check_and_use_skill(const Point& loc, bool& has_error, const cv::Mat& reusable) { cv::Mat image = reusable.empty() ? m_inst_helper.ctrler()->get_image() : reusable; BattlefieldClassifier skill_analyzer(image); @@ -658,14 +675,7 @@ void asst::BattleHelper::save_map(const cv::Mat& image) auto draw = image.clone(); for (const auto& [loc, info] : m_normal_tile_info) { cv::circle(draw, cv::Point(info.pos.x, info.pos.y), 5, cv::Scalar(0, 255, 0), -1); - cv::putText( - draw, - loc.to_string(), - cv::Point(info.pos.x - 30, info.pos.y), - 1, - 1.2, - cv::Scalar(0, 0, 255), - 2); + cv::putText(draw, loc.to_string(), cv::Point(info.pos.x - 30, info.pos.y), 1, 1.2, cv::Scalar(0, 0, 255), 2); } std::string suffix; @@ -732,9 +742,8 @@ bool asst::BattleHelper::click_oper_on_battlefield(const Point& loc) bool asst::BattleHelper::click_retreat() { LogTraceFunction; - bool deploy_with_pause = ControlFeat::support( - m_inst_helper.ctrler()->support_features(), - ControlFeat::SWIPE_WITH_PAUSE); + bool deploy_with_pause = + ControlFeat::support(m_inst_helper.ctrler()->support_features(), ControlFeat::SWIPE_WITH_PAUSE); if (deploy_with_pause) { ProcessTask(this_task(), { "BattlePause" }).run(); @@ -748,39 +757,48 @@ bool asst::BattleHelper::click_retreat() return ret; } -// TODO: use m_skill_button_pos bool asst::BattleHelper::click_skill(bool keep_waiting) { LogTraceFunction; - bool deploy_with_pause = ControlFeat::support( - m_inst_helper.ctrler()->support_features(), - ControlFeat::SWIPE_WITH_PAUSE); + bool deploy_with_pause = + ControlFeat::support(m_inst_helper.ctrler()->support_features(), ControlFeat::SWIPE_WITH_PAUSE); + bool pausing = false; if (!keep_waiting && deploy_with_pause) { - ProcessTask(this_task(), { "BattlePause" }).run(); + pausing = ProcessTask(this_task(), { "BattlePause" }).run(); } - ProcessTask skill_task( - this_task(), - { "BattleSkillReadyOnClick", - "BattleSkillReadyOnClick-SquareMap", - "BattleSkillStopOnClick", - "BattleSkillStopOnClick-MiddleMap", - "BattleSkillStopOnClick-SquareMap" }); - skill_task.set_task_delay(0); - if (keep_waiting) { - return skill_task.set_retry_times(1000).run(); - } - else { - bool ret = skill_task.set_retry_times(5).run(); - if (!ret) { - cancel_oper_selection(); + cv::Mat top_view; + for (int retry = 0; retry < (keep_waiting ? 1000 : 5); ++retry) { + top_view = get_top_view(m_inst_helper.ctrler()->get_image(), true); + Matcher skill_analyzer { top_view }; + skill_analyzer.set_task_info("BattleSkillReadyOnClick-TopView"); + skill_analyzer.set_roi({ 250, 250, 250, 250 }); + if (skill_analyzer.analyze()) { + m_inst_helper.ctrler()->click(m_skill_button_pos); + if (pausing) { + ProcessTask(this_task(), { "BattlePauseCancel" }).run(); + } + return true; } - if (deploy_with_pause) { - ProcessTask(this_task(), { "BattlePauseCancel" }).run(); - } - return ret; + m_inst_helper.sleep(Config.get_options().task_delay); } + + // this means false positive in skill ready detection + +#ifdef ASST_DEBUG + if (!top_view.empty()) { + using namespace asst::utils::path_literals; + asst::imwrite( + "debug"_p / "skill"_p / asst::utils::path(m_stage_name + '_' + utils::get_time_filestem() + ".png"), + top_view); + } +#endif + cancel_oper_selection(); + if (pausing) { + ProcessTask(this_task(), { "BattlePauseCancel" }).run(); + } + return false; } bool asst::BattleHelper::cancel_oper_selection() @@ -828,8 +846,7 @@ void asst::BattleHelper::fix_swipe_out_of_limit( }; // 旋转后偏移值会不够,计算补偿比例 - double adjust_more = - std::get<0>(adjust_scale) * direct.x + std::get<1>(adjust_scale) * direct.y; + double adjust_more = std::get<0>(adjust_scale) * direct.x + std::get<1>(adjust_scale) * direct.y; Point adjust = { static_cast(std::get<0>(adjust_scale) / adjust_more * distance), @@ -843,14 +860,7 @@ void asst::BattleHelper::fix_swipe_out_of_limit( }; } - Log.info( - __FUNCTION__, - "swipe end_point out of limit, start:", - p1, - ", end:", - p2, - ", adjust:", - adjust); + Log.info(__FUNCTION__, "swipe end_point out of limit, start:", p1, ", end:", p2, ", adjust:", adjust); p1 += adjust; p2 += adjust; } @@ -905,14 +915,11 @@ std::string asst::BattleHelper::analyze_detail_page_oper_name(const cv::Mat& ima return BattleData.is_name_invalid(det_name) ? std::string() : det_name; } -std::optional - asst::BattleHelper::get_oper_rect_on_deployment(const std::string& name) const +std::optional asst::BattleHelper::get_oper_rect_on_deployment(const std::string& name) const { LogTraceFunction; - auto oper_iter = ranges::find_if(m_cur_deployment_opers, [&](const auto& oper) { - return oper.name == name; - }); + auto oper_iter = ranges::find_if(m_cur_deployment_opers, [&](const auto& oper) { return oper.name == name; }); if (oper_iter == m_cur_deployment_opers.end()) { Log.error("No oper", name); return std::nullopt; diff --git a/src/MaaCore/Task/BattleHelper.h b/src/MaaCore/Task/BattleHelper.h index f597e30245..b39e17125f 100644 --- a/src/MaaCore/Task/BattleHelper.h +++ b/src/MaaCore/Task/BattleHelper.h @@ -39,6 +39,8 @@ namespace asst bool update_kills(const cv::Mat& reusable = cv::Mat()); bool update_cost(const cv::Mat& reusable = cv::Mat()); + cv::Mat get_top_view(const cv::Mat& cam_img, bool side = true); + bool deploy_oper(const std::string& name, const Point& loc, battle::DeployDirection direction); bool retreat_oper(const std::string& name); bool retreat_oper(const Point& loc, bool manually = true);