From 79306724346f262750225455b411ca3969489395 Mon Sep 17 00:00:00 2001 From: LmeSzinc <37934724+LmeSzinc@users.noreply.github.com> Date: Mon, 6 Nov 2023 22:28:11 +0800 Subject: [PATCH 1/5] Fix: Each button frame should have its own `search` attribute --- dev_tools/button_extract.py | 23 +++++++++++++------ .../assignment/assets/assets_assignment_ui.py | 12 +++++----- tasks/base/assets/assets_base_page.py | 2 +- 3 files changed, 23 insertions(+), 14 deletions(-) diff --git a/dev_tools/button_extract.py b/dev_tools/button_extract.py index ee9149b69..0a928e29b 100644 --- a/dev_tools/button_extract.py +++ b/dev_tools/button_extract.py @@ -179,20 +179,29 @@ def iter_assets(): if image.attr != '': row = deep_get(data, keys=[image.module, image.assets, image.server, image.frame]) row.load_image(image) - # Apply `search` of the first frame to all + # Set `search` for path, frames in deep_iter(data, depth=3): print(path, frames) + # If `search` attribute is set in the first frame, apply to all first = frames[1] - search = first.search if first.search else DataAssets.area_to_search(first.area) - for frame in frames.values(): - frame.search = search + if first.search: + for frame in frames.values(): + frame.search = first.search + else: + for frame in frames.values(): + if frame.search: + # Follow frame specific `search` + pass + else: + # Generate `search` from `area` + frame.search = DataAssets.area_to_search(frame.area) return data def generate_code(): - all = iter_assets() - for module, module_data in all.items(): + all_assets = iter_assets() + for module, module_data in all_assets.items(): path = os.path.join(AzurLaneConfig.ASSETS_MODULE, module.split('/', maxsplit=1)[0]) output = os.path.join(path, 'assets.py') if os.path.exists(output): @@ -204,7 +213,7 @@ def generate_code(): continue os.remove(prev) - for module, module_data in all.items(): + for module, module_data in all_assets.items(): path = os.path.join(AzurLaneConfig.ASSETS_MODULE, module.split('/', maxsplit=1)[0]) output = os.path.join(path, 'assets') gen = CodeGenerator() diff --git a/tasks/assignment/assets/assets_assignment_ui.py b/tasks/assignment/assets/assets_assignment_ui.py index 3d50d5981..572411124 100644 --- a/tasks/assignment/assets/assets_assignment_ui.py +++ b/tasks/assignment/assets/assets_assignment_ui.py @@ -23,7 +23,7 @@ CHARACTER_MATERIALS_CHECK = ButtonWrapper( Button( file='./assets/en/assignment/ui/CHARACTER_MATERIALS_CHECK.2.png', area=(142, 98, 234, 119), - search=(319, 68, 449, 146), + search=(122, 78, 254, 139), color=(203, 202, 199), button=(142, 98, 234, 119), ), @@ -49,7 +49,7 @@ CHARACTER_MATERIALS_CLICK = ButtonWrapper( Button( file='./assets/en/assignment/ui/CHARACTER_MATERIALS_CLICK.2.png', area=(143, 98, 234, 120), - search=(319, 68, 449, 147), + search=(123, 78, 254, 140), color=(61, 59, 57), button=(143, 98, 234, 120), ), @@ -102,7 +102,7 @@ EXP_MATERIALS_CREDITS_CHECK = ButtonWrapper( Button( file='./assets/en/assignment/ui/EXP_MATERIALS_CREDITS_CHECK.2.png', area=(373, 98, 458, 119), - search=(509, 68, 619, 146), + search=(353, 78, 478, 139), color=(191, 190, 187), button=(373, 98, 458, 119), ), @@ -128,7 +128,7 @@ EXP_MATERIALS_CREDITS_CLICK = ButtonWrapper( Button( file='./assets/en/assignment/ui/EXP_MATERIALS_CREDITS_CLICK.2.png', area=(374, 98, 459, 119), - search=(508, 68, 619, 147), + search=(354, 78, 479, 139), color=(49, 49, 49), button=(374, 98, 459, 119), ), @@ -245,7 +245,7 @@ SYNTHESIS_MATERIALS_CHECK = ButtonWrapper( Button( file='./assets/en/assignment/ui/SYNTHESIS_MATERIALS_CHECK.2.png', area=(624, 97, 715, 119), - search=(683, 68, 810, 146), + search=(604, 77, 735, 139), color=(197, 196, 193), button=(624, 97, 715, 119), ), @@ -271,7 +271,7 @@ SYNTHESIS_MATERIALS_CLICK = ButtonWrapper( Button( file='./assets/en/assignment/ui/SYNTHESIS_MATERIALS_CLICK.2.png', area=(624, 97, 715, 119), - search=(682, 68, 810, 146), + search=(604, 77, 735, 139), color=(51, 50, 49), button=(624, 97, 715, 119), ), diff --git a/tasks/base/assets/assets_base_page.py b/tasks/base/assets/assets_base_page.py index 5063128a0..4ea863018 100644 --- a/tasks/base/assets/assets_base_page.py +++ b/tasks/base/assets/assets_base_page.py @@ -96,7 +96,7 @@ GACHA_CHECK = ButtonWrapper( Button( file='./assets/share/base/page/GACHA_CHECK.2.png', area=(41, 21, 74, 54), - search=(20, 0, 94, 74), + search=(21, 1, 94, 74), color=(188, 167, 142), button=(41, 21, 74, 54), ), From 4adfa00148d39494f11c2207bdb3200c3571bee3 Mon Sep 17 00:00:00 2001 From: LmeSzinc <37934724+LmeSzinc@users.noreply.github.com> Date: Mon, 6 Nov 2023 22:29:49 +0800 Subject: [PATCH 2/5] Add: Add argument `direct_match` to Button methods --- module/base/button.py | 75 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 66 insertions(+), 9 deletions(-) diff --git a/module/base/button.py b/module/base/button.py index 5694c10ef..0846696c2 100644 --- a/module/base/button.py +++ b/module/base/button.py @@ -74,7 +74,7 @@ class Button(Resource): threshold=threshold ) - def match_template(self, image, similarity=0.85) -> bool: + def match_template(self, image, similarity=0.85, direct_match=False) -> bool: """ Detects assets by template matching. @@ -83,18 +83,45 @@ class Button(Resource): Args: image: Screenshot. similarity (float): 0-1. + direct_match: True to ignore `self.search` Returns: bool. """ - image = crop(image, self.search, copy=False) + if not direct_match: + image = crop(image, self.search, copy=False) res = cv2.matchTemplate(self.image, image, cv2.TM_CCOEFF_NORMED) _, sim, _, point = cv2.minMaxLoc(res) self._button_offset = np.array(point) + self.search[:2] - self.area[:2] return sim > similarity - def match_template_color(self, image, similarity=0.85, threshold=30) -> bool: + def match_multi_template(self, image, similarity=0.85, direct_match=False): + """ + Detects assets by template matching, return multiple reults + + Args: + image: Screenshot. + similarity (float): 0-1. + direct_match: True to ignore `self.search` + + Returns: + list: + """ + if not direct_match: + image = crop(image, self.search, copy=False) + res = cv2.matchTemplate(self.image, image, cv2.TM_CCOEFF_NORMED) + res = cv2.inRange(res, similarity, 1.) + try: + points = np.array(cv2.findNonZero(res))[:, 0, :] + points += self.search[:2] + return points.tolist() + except IndexError: + # Empty result + # IndexError: too many indices for array: array is 0-dimensional, but 3 were indexed + return [] + + def match_template_color(self, image, similarity=0.85, threshold=30, direct_match=False) -> bool: """ Template match first, color match then @@ -102,11 +129,12 @@ class Button(Resource): image: Screenshot. similarity (float): 0-1. threshold (int): Default to 10. + direct_match: True to ignore `self.search` Returns: - + bool. """ - matched = self.match_template(image, similarity=similarity) + matched = self.match_template(image, similarity=similarity, direct_match=direct_match) if not matched: return False @@ -173,16 +201,45 @@ class ButtonWrapper(Resource): return True return False - def match_template(self, image, similarity=0.85) -> bool: + def match_template(self, image, similarity=0.85, direct_match=False) -> bool: for assets in self.buttons: - if assets.match_template(image, similarity=similarity): + if assets.match_template(image, similarity=similarity, direct_match=direct_match): self._matched_button = assets return True return False - def match_template_color(self, image, similarity=0.85, threshold=30) -> bool: + def match_multi_template(self, image, similarity=0.85, threshold=5, direct_match=False): + """ + Detects assets by template matching, return multiple results + + Args: + image: Screenshot. + similarity (float): 0-1. + threshold: + direct_match: True to ignore `self.search` + + Returns: + list[ClickButton]: + """ + ps = [] for assets in self.buttons: - if assets.match_template_color(image, similarity=similarity, threshold=threshold): + ps += assets.match_multi_template(image, similarity=similarity, direct_match=direct_match) + if not ps: + return [] + + from module.base.utils.points import Points + ps = Points(ps).group(threshold=threshold) + area_list = [area_offset(self.area, p - self.area[:2]) for p in ps] + button_list = [area_offset(self.button, p - self.area[:2]) for p in ps] + return [ + ClickButton(area=info[0], button=info[1], name=f'{self.name}_result{i}') + for i, info in enumerate(zip(area_list, button_list)) + ] + + def match_template_color(self, image, similarity=0.85, threshold=30, direct_match=False) -> bool: + for assets in self.buttons: + if assets.match_template_color( + image, similarity=similarity, threshold=threshold, direct_match=direct_match): self._matched_button = assets return True return False From e1468db85dee604baf061cd9fb40754306468ed3 Mon Sep 17 00:00:00 2001 From: LmeSzinc <37934724+LmeSzinc@users.noreply.github.com> Date: Mon, 6 Nov 2023 22:30:43 +0800 Subject: [PATCH 3/5] Fix: Handle reward on complex background --- assets/share/base/popup/GET_REWARD.2.png | Bin 0 -> 2412 bytes assets/share/base/popup/GET_REWARD.png | Bin 5492 -> 2311 bytes tasks/base/assets/assets_base_popup.py | 23 ++++-- tasks/base/popup.py | 97 +++++++++++++++++++++-- tasks/battle_pass/battle_pass.py | 3 +- tasks/daily/synthesize.py | 10 +-- tasks/freebies/support_reward.py | 13 ++- tasks/item/relics.py | 3 +- 8 files changed, 118 insertions(+), 31 deletions(-) create mode 100644 assets/share/base/popup/GET_REWARD.2.png diff --git a/assets/share/base/popup/GET_REWARD.2.png b/assets/share/base/popup/GET_REWARD.2.png new file mode 100644 index 0000000000000000000000000000000000000000..2ca29c3b2475e04bcc339406e3c1f099db0ba83a GIT binary patch literal 2412 zcmeHGi#yYM9R9I{IXa;zj>wV3nae>a4zgiF+gi*e9JFW{k)fGO7q@8DkxQhKBWa3g zhRxisMWS4C%iK06OD>yB&QJeE&pDsx`F=m|^M2pY^Ssadd_T!3CtGQ#A`}1sX`~$- z0{~(m6z!1!Z-6VGkODTz5Iff}0FaW~J|aL)?mhs3><_TEMxp$P;lwb1Vu&iz+FCW_ zA`u@Dcn$y}hkU)g?~l)Z;&iC9*(eki!#Tj&w_j#|A)9hPJ}o{we!C9pGpgA7s_evV ztZSj0Ap#-Sw6NRQY<7t2hquk`8S#ef91j$>0VLw$POv;PH)O?Do4U-ztWTfWsdXi(O;c=%Z>e~o8$OgFts zK6@=jBN4DYd|3Oufr5dHlCkkB{J@d>g|#iUiGl>-{Vy(35|Yp4!{x~8eVWfS$vE}1 zf4PL0;Brlh1kTBOkbkxpVD|P__nz{bZoA$g*^!sAfaaq)XKEi9B24WO$f-)MbEVBC z3u)Ihdd_-<#)Tp-jt8A%^&Wp@G4`NEucNIO*DIj6o4;$sYj>@~w0@JLk)Oc=u|bG= z+&pW@f>iZSWc^&$SIbZ#qoty_lMmL zEVv#5YI6jk)LPYS(>&EoSMPHAm>Ygn7^QVO$D`WO28%!Q{@J{_>FQ$EV!sp_nwpAN zP|=BU*Fb;9pmC=I8dADdG1geA;xYXVp=R{pz}!gxXiQb+!){hxa04rO z>+o@>fV^m*V+%LNvtQ!Pa|(>;exocg52;3ZnCC`labvk;r%I`zXMgqDwA;ufM;cGy#(P$ zJ}(xR$bYyyvYR;=&Ew@Q)fg|Vo0;(2mcDR{Qo8Z1-Q>aL9HHaLaQ?zc3-TJ4FC6($ zOI)CEwl?@Rf^K^3nXN4dpjD@w@|B2o2RBF6*AC+d0MUm4AnpnP2)DpK2LPA!z}@l& zfMZzzpg_Fs)ocT<-D@P=3L7~zKjcWjy8I$OzQvsU*d_66vGVYf9WdCC&eJCWWQ0O> z8E&=#Aww$N04TtwJS9%PIuxzNLZzg|)RP?83VQH8kC6^{>~Fkv_+7`)=~4LG*Ly#k zb!*M!j@;}dzA-hG0d4(Y)x(mNp_a(qi{_s65qzRCdAw8?{I_pkS3*T@6&+Gjbx~Sz zp3EN;cUE@YT(M`Y-z!|S62W+H7F@o*(|(KwW4>J62p+piM#b&Ht@4Wn{E(?UVap~f zu~J7!)h5Mp2!7mkL)wCu@cmMO*YzCb#HT7!5@L3tX|UM$v6IMvk@P7k7V{R*rJUPT z#>Jhr)U-??)Ef9qFXbgE*Ytik9Tw~1P`>PyZ>9*Pk{J;7*eRllCxbLMx}vM5<}>>- za_VIo;Zfs)K9uT1uz|x#tK)+c`H7?={V?G)HfU@{M*n!71eB_#;N4VY8|*0{%v)}R z*Sr#zxWSvMMByTsK%x^PgEsh_bX@V~F;Z}p(H9RB&_z(`^331GEO#X1d@3r^3nRlH zWmS!yDlgQI9t)I=N#B-C7)YKw+Ma%Y>9l`W_>E^i zT%P2wF~>Wvmlki}x>-!>(X@opjt*vrV@r2Y7^cZ~T1W#mpYb7ohW2fwxa<%1VgI-L eUrs<^;kgT-jNUOcGu5%%4g!gAf|s7~PWTrv$MN?7 literal 0 HcmV?d00001 diff --git a/assets/share/base/popup/GET_REWARD.png b/assets/share/base/popup/GET_REWARD.png index 6ebda832d9cd74d4ef0c7efd3af9a09f5da904da..5174e1d46ed5f75bcb25dbaa32b2d37457162bf5 100644 GIT binary patch delta 1431 zcmV;I1!(&8Du)t~83+IX008P1f{KwL7k>j8X+uL$P-t&-Z*ypGa3D!TLm+T+Z)Rz1 zWdHzp+GAi~p5W-> zfgvwHFO>lUe7nZL$iTqBa9P*U#mSX{G{Bl%P*lRez;J+pfx##xwK$o9f#C}S1Ajw$ zc}YPD0|R3W0|SFdQg%TJ0|R3L0|SFdc1Vyj0|R3V0|OIJNoqw20|NttbACZ(QD%BZ ziGrb}rKN&nN`6wRLU3hqNosDff@fZGeo;YwQDRAI3IhWJ)D8v)1_oZ2{1OHC#LPSe zLsL}-Dual~Ckr}$Qh6iH#pqf!;py3$W%=6}eB$_dJy zmG4pTQRG#;pfp7}N<~TKwdz*2Ms+_8S&g@v`?Mx%r|MYi3hBPmJEA||pvExD$kJHS z__xVD)5B&f%=;}WEEBDKtSxL*ZAI)@?7rGRcew3%!ReUuUYD(|>)lqmFZEdDxzKBY z_d=h=zRUbp`L7Sy8n`#;Sby;OkXxb8!oEZ>MG8hKMH|Ps#YV;D#kVBPPTZVyHu-rf zQ<_}5O-58^Ro1NRJvsOCnDW&NdA@4aXXP zHygC1x6W(3-XYlO-PPWGxR;^NzQ1n5zKQ=QJ5FhxdSW{7jNqBGW`8}Jqcyi=-o6D~ z3&R#IUi@*X!?Fp>AFecB)w=rTTHSR`>u+u}*wnH4!B(qnQ@4NE>AP#y9*(`~`;H$_ zKiGNb^%1|Ln~#g1s6F}QwD*}U=VZ^fU-)z>?((Ut7T1>D5WU%Y>+7BLyEpIqJUH;k z^zrJaiqB@g5PaG7nt%CC-P@n06Lfe02gnPU&TfM00n4C zL_t(|+U(rFOO$Z{$MNrTCYVVC6-e2SRTLvAw}vPR5)vh|k~$147l&wx`X^kRDg=X| zhDy>%!N7`yGz&xvq9MYlY-lhM)WmN?5vJ652hY7;+kKzyGraG)=Z*^jlfeddfBxg_ zXpC|3Ms59MTxsD|t9^hJyEYeNZ}Yj{?{T&1tM(zQ)|h~->gzk-m6Tsvzxv9;NV|Cu zK+>#gqBGQ;S$+QFW%q|z@3Gn^0wBNS^-1= zNqYc89KS!7Y-!vVLI~m6?XPiHePvSDax`WPL^k;ngj~GuR#pw(o9dW6UKr;3Z^ezZ zhYF2?0FoyP!hwoM-FK(jLdS5}e{!=$5J2)t>FG?*P;nS8tZgy|0!Y3&e=*lT5W>Mm zOOPubI+MH4!HuO!QhLgpFak&(Drw4OnoI0}kHF-kvZ7G-=Y^kSA%Nr+(L(^q+x{gI zNG^E>2nZnL{&o-qkTiR-7-Nk8xHw@SvdS|+va7w~aP_jgzU7zRj=!-F0!WH2O}yTA zWz*^a#&5}pbr3+(?&IaXAxCzsIQ#No)G!DjsTae{;N!-cq7Xuizy2R^eyD5S4`Q>S l4C(?N$f2JA009600|3P$p!&N^e~kbD002ovPDHLkV1h1Pz5@UN literal 5492 zcmeHJdsGu=79U^*l%uku1wqyrbfs!CNk|A8O;8gA)F6k4K|vvp2}DUIW&#OP9(Ju1 zwUu2JDxj40g%8k51x0b`Qb7>JcbC_pRs_q6Xb}m}z3KC{?di12hCJ^VX}y(ygeLBtfGUDlWO_%0I{?g^WuUv4k|C znvcdP{I+Y*;Ozk+((PNN92wc0M_Q&wfB_|{6_fPJSQU=wxnz@F1gwc|m`pN3v|G94 z6@)`lm@tsU$22I3L#0uqG#Z`6=1`?H28}6UEFm#y3=f#bfN2~G%@bjGB6KFne35}W zjZBUN309e%fj2HWMypjLFs#$*s5%cSriq5>91e%D!C+7Tf`TWgv|>F)g}aSe5TLkJ zqfl!Vn2JPL6icu;Etd>J9nC?h9yhDP%{&3dV7*uk)2TEfClgR69mlETG_fYbw2jOF}mkWj z3F4=~L7^p>XGAc%&Af_LkW77nh^3=hNQsg}Wn}ZV;&-3ks99YM3i$dTr8)}3F}YSJ z)}Sk*0m<)d1sDVm6O(B)5BR@RG|7H7#m3-ZG!o14p$uNe$2zJ4vs?p)c5dY&J_Jp7 z_7|)O(dTxzZi;>I#MS0SCnqVtB(R|9=>mP4CU><^Pt;U( zU$}(UJkMOxxb}nMJ>?6s>*|)cPy5$dG?SI@67@~V%xufYg?D$mS2lff42yQGKfT2A zAl@`>aG<@tJ!N>nnD_Io2Q~f6Mmh)5OkbRd+k0d{;kdBO0=o3W!2`D@&x;Uc^dGL? zl6jzEHjm@w_3EEhCq!KvJ!YimjXYgkyvL5$ecovG7v<2El!29xYl6$??JO#~^{Qkl zv|rdEU_+27O&@-}Z;xZ0^YHo0$vtZ>QZ^h)$GDo#*3yQ&%q)Din;ezb<%NfZ@~)KR za|;VCE9RrtPEb&25Ta{0)Ub5RN|U44?#$_&mDF@4PP%<17%oS(x79JHFZC( zOBuSxb={QGa^d80qv7Vci?J!aH?nQcYymFTJt;ZChgD6+TZwb$@2{!-D?EJ!^W7}}feR7pXvKe3Z5Ta#ZrY3gw3dCeR8h#%emqwo3amyz8czpur0Efw7A!yq|<(f1&Q*9D9CB?>~w*xxbZNXQuftTxEb-h zfAQL@Exqacx&J<5SZVvHvC}1OCYv+7XD$WGn6?XrQbS#N z9vohLVT4(kCy|GUv~r|Mk%F`CvSZ|DmS=)i7K(yMj-S%#yY=YP8HgsKR|RXf7Uor&Am9a`>KiW7sCT?s}_TXJ*9EDQo?Z ztf6DDTv%9LRj>m3q7LNe*H|r&Ny{33eS}lm*JCqWX8b<;;KAuF#qQCoANo$3cW7^A z^Qyek)rN?+<&TRh8w%UD6`k|e`^|WdQ*FZZ1OpQcOfWFPzyt#m3`{Wa9vBd%jX-mM VTEEb}o*Y4#_xA}96s?T<_&;ypcoF~r diff --git a/tasks/base/assets/assets_base_popup.py b/tasks/base/assets/assets_base_popup.py index 89ac6b632..1489417f0 100644 --- a/tasks/base/assets/assets_base_popup.py +++ b/tasks/base/assets/assets_base_popup.py @@ -32,13 +32,22 @@ GET_LIGHT_CONE = ButtonWrapper( ) GET_REWARD = ButtonWrapper( name='GET_REWARD', - share=Button( - file='./assets/share/base/popup/GET_REWARD.png', - area=(623, 95, 657, 119), - search=(603, 75, 677, 139), - color=(145, 131, 99), - button=(741, 495, 1071, 644), - ), + share=[ + Button( + file='./assets/share/base/popup/GET_REWARD.png', + area=(625, 95, 655, 119), + search=(605, 75, 675, 139), + color=(213, 0, 0), + button=(741, 495, 1071, 644), + ), + Button( + file='./assets/share/base/popup/GET_REWARD.2.png', + area=(625, 144, 655, 168), + search=(605, 124, 675, 188), + color=(226, 0, 0), + button=(625, 144, 655, 168), + ), + ], ) MONTHLY_CARD_GET_ITEM = ButtonWrapper( name='MONTHLY_CARD_GET_ITEM', diff --git a/tasks/base/popup.py b/tasks/base/popup.py index 000194150..3e18c9be5 100644 --- a/tasks/base/popup.py +++ b/tasks/base/popup.py @@ -1,10 +1,22 @@ +from typing import Callable + from module.base.base import ModuleBase +from module.base.utils import color_similarity_2d from module.logger import logger +from tasks.base.assets.assets_base_page import BACK, CLOSE from tasks.base.assets.assets_base_popup import * class PopupHandler(ModuleBase): - def handle_reward(self, interval=5, click_button=None) -> bool: + def reward_appear(self) -> bool: + for button in GET_REWARD.buttons: + image = self.image_crop(button.search, copy=False) + image = color_similarity_2d(image, color=(203, 181, 132)) + if button.match_template(image, direct_match=True): + return True + return False + + def handle_reward(self, interval=5, click_button: ButtonWrapper = None) -> bool: """ Args: interval: @@ -13,16 +25,26 @@ class PopupHandler(ModuleBase): Returns: If handled. """ + # Same as ModuleBase.match_template() + self.device.stuck_record_add(GET_REWARD) + + if interval and not self.interval_is_reached(GET_REWARD, interval=interval): + return False + + appear = self.reward_appear() + if click_button is None: - if self.appear_then_click(GET_REWARD, interval=interval): - return True + if appear: + self.device.click(GET_REWARD) else: - if self.appear(GET_REWARD, interval=interval): + if appear: logger.info(f'{GET_REWARD} -> {click_button}') self.device.click(click_button) - return True - return False + if appear and interval: + self.interval_reset(GET_REWARD, interval=interval) + + return appear def handle_battle_pass_notification(self, interval=5) -> bool: """ @@ -113,3 +135,66 @@ class PopupHandler(ModuleBase): return True return False + + def handle_get_character(self, interval=2) -> bool: + """ + Popup when getting a character from rogue rewards. + + Args: + interval: + + Returns: + If handled. + """ + if self.appear(GET_CHARACTER, interval=interval): + logger.info(f'{GET_CHARACTER} -> {GET_REWARD}') + self.device.click(GET_REWARD) + return True + + return False + + def handle_ui_close(self, appear_button: ButtonWrapper | Callable, interval=2) -> bool: + """ + Args: + appear_button: Click if button appears + interval: + + Returns: + If handled. + """ + if callable(appear_button): + if self.interval_is_reached(appear_button, interval=interval) and appear_button(): + logger.info(f'{appear_button.__name__} -> {CLOSE}') + self.device.click(CLOSE) + self.interval_reset(appear_button, interval=interval) + return True + else: + if self.appear(appear_button, interval=interval): + logger.info(f'{appear_button} -> {CLOSE}') + self.device.click(CLOSE) + return True + + return False + + def handle_ui_back(self, appear_button: ButtonWrapper | Callable, interval=2) -> bool: + """ + Args: + appear_button: Click if button appears + interval: + + Returns: + If handled. + """ + if callable(appear_button): + if self.interval_is_reached(appear_button, interval=interval) and appear_button(): + logger.info(f'{appear_button.__name__} -> {BACK}') + self.device.click(BACK) + self.interval_reset(appear_button, interval=interval) + return True + else: + if self.appear(appear_button, interval=interval): + logger.info(f'{appear_button} -> {BACK}') + self.device.click(BACK) + return True + + return False diff --git a/tasks/battle_pass/battle_pass.py b/tasks/battle_pass/battle_pass.py index 3eb4928c1..fc5acb886 100644 --- a/tasks/battle_pass/battle_pass.py +++ b/tasks/battle_pass/battle_pass.py @@ -12,7 +12,6 @@ from module.ocr.utils import split_and_pair_buttons from module.ui.scroll import Scroll from module.ui.switch import Switch from tasks.base.assets.assets_base_page import BATTLE_PASS_CHECK, MAIN_GOTO_BATTLE_PASS -from tasks.base.assets.assets_base_popup import GET_REWARD from tasks.base.page import page_battle_pass, page_main from tasks.base.ui import UI from tasks.battle_pass.assets.assets_battle_pass import * @@ -187,7 +186,7 @@ class BattlePassUI(UI): else: self.device.screenshot() - if self.appear(GET_REWARD): + if self.reward_appear(): logger.info('Get reward') break if self.appear(CLOSE_CHOOSE_GIFT): diff --git a/tasks/daily/synthesize.py b/tasks/daily/synthesize.py index 8d48d3914..718b60bba 100644 --- a/tasks/daily/synthesize.py +++ b/tasks/daily/synthesize.py @@ -1,11 +1,9 @@ from module.ocr.ocr import * from module.ui.scroll import Scroll -from tasks.base.assets.assets_base_page import MENU_CHECK, SYNTHESIZE_CHECK -from tasks.base.assets.assets_base_popup import GET_REWARD +from tasks.base.assets.assets_base_page import MENU_CHECK, MENU_SCROLL, SYNTHESIZE_CHECK +from tasks.base.assets.assets_base_popup import POPUP_CONFIRM from tasks.base.page import Page, page_menu, page_synthesize from tasks.base.ui import UI -from tasks.base.assets.assets_base_page import MENU_SCROLL -from tasks.base.assets.assets_base_popup import POPUP_CONFIRM from tasks.daily.assets.assets_daily_synthesize_consumable import * from tasks.daily.assets.assets_daily_synthesize_material import * @@ -157,7 +155,7 @@ class SynthesizeUI(UI): else: self.device.screenshot() - if self.appear(GET_REWARD): + if self.reward_appear(): logger.info('Synthesize consumable completed') break # Synthesize confirm @@ -175,7 +173,7 @@ class SynthesizeUI(UI): logger.info('Synthesize consumables page appear') break # Go back to the previous page - if self.appear_then_click(GET_REWARD): + if self.handle_reward(interval=2): logger.info('Click on the blank space to back to synthesize page') continue diff --git a/tasks/freebies/support_reward.py b/tasks/freebies/support_reward.py index 8c9d1ef7c..c3313b7e8 100644 --- a/tasks/freebies/support_reward.py +++ b/tasks/freebies/support_reward.py @@ -1,7 +1,6 @@ from module.base.timer import Timer from module.logger import logger -from tasks.base.assets.assets_base_page import CLOSE, MENU_CHECK -from tasks.base.assets.assets_base_popup import GET_REWARD +from tasks.base.assets.assets_base_page import MENU_CHECK from tasks.base.page import page_menu from tasks.base.ui import UI from tasks.freebies.assets.assets_freebies_support_reward import ( @@ -53,7 +52,7 @@ class SupportReward(UI): """ Pages: in: PROFILE - out: GET_REWARD + out: reward_appear() """ logger.info('Getting reward') claimed = False @@ -68,7 +67,7 @@ class SupportReward(UI): if not claimed and empty.reached(): logger.info('No reward') break - if self.appear(GET_REWARD): + if self.reward_appear(): logger.info('Got reward') break if timeout.reached(): @@ -83,7 +82,7 @@ class SupportReward(UI): def _goto_menu(self): """ Pages: - in: PROFILE or GET_REWARD + in: PROFILE or reward_appear out: MENU """ skip_first_screenshot = False @@ -97,9 +96,7 @@ class SupportReward(UI): if self.appear(MENU_CHECK): return True - if self.appear(IN_PROFILE, interval=2): - logger.info(f'{IN_PROFILE} -> {CLOSE}') - self.device.click(CLOSE) + if self.handle_ui_close(IN_PROFILE, interval=2): continue if self.handle_reward(click_button=CAN_GET_REWARD): # # Avoid clicking on some other buttons diff --git a/tasks/item/relics.py b/tasks/item/relics.py index abf7a4617..7febb0751 100644 --- a/tasks/item/relics.py +++ b/tasks/item/relics.py @@ -1,7 +1,6 @@ from module.base.timer import Timer from module.logger import logger from tasks.base.assets.assets_base_page import CLOSE -from tasks.base.assets.assets_base_popup import GET_REWARD from tasks.item.assets.assets_item_relics import * from tasks.item.keywords import KEYWORD_ITEM_TAB from tasks.item.ui import ItemUI @@ -96,7 +95,7 @@ class RelicsUI(ItemUI): else: self.device.screenshot() - if self.appear(GET_REWARD): + if self.reward_appear(): logger.info("Relic salvaged") break if self.appear_then_click(SALVAGE, interval=2): From 02fab9943154b6f9c53665d3705056c36882d5ac Mon Sep 17 00:00:00 2001 From: LmeSzinc <37934724+LmeSzinc@users.noreply.github.com> Date: Mon, 6 Nov 2023 22:37:48 +0800 Subject: [PATCH 4/5] Fix: subtract_blur images are never used --- tasks/map/interact/aim.py | 3 +-- tasks/map/minimap/minimap.py | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/tasks/map/interact/aim.py b/tasks/map/interact/aim.py index bebbd7fee..0d5e41d10 100644 --- a/tasks/map/interact/aim.py +++ b/tasks/map/interact/aim.py @@ -187,7 +187,7 @@ class Aim: draw_circle(draw, self.circle_enemy, points) if self.debug: self.draw_enemy = cv2.multiply(draw, 4) - subtract_blur(draw, 3) + draw = subtract_blur(draw, 3) # Find peaks points = inrange(draw, lower=36) @@ -230,7 +230,6 @@ class Aim: draw_circle(draw, self.circle_item, points) if self.debug: self.draw_item = cv2.multiply(draw, 2) - subtract_blur(draw, 7) # Find peaks points = inrange(draw, lower=64) diff --git a/tasks/map/minimap/minimap.py b/tasks/map/minimap/minimap.py index e686fc0a0..b0744ec36 100644 --- a/tasks/map/minimap/minimap.py +++ b/tasks/map/minimap/minimap.py @@ -224,7 +224,7 @@ class Minimap(MapResource): scale = self.DIRECTION_ROTATION_SCALE * self.DIRECTION_SEARCH_SCALE mapping = cv2.resize(image, None, fx=scale, fy=scale, interpolation=cv2.INTER_NEAREST) result = cv2.matchTemplate(self.ArrowRotateMap, mapping, cv2.TM_CCOEFF_NORMED) - subtract_blur(result, 5) + result = subtract_blur(result, 5) _, sim, _, loca = cv2.minMaxLoc(result) loca = np.array(loca) / self.DIRECTION_SEARCH_SCALE // (self.DIRECTION_RADIUS * 2) degree = int((loca[0] + loca[1] * 8) * 5) @@ -241,7 +241,7 @@ class Minimap(MapResource): precise_map = self.ArrowRotateMapAll[row[0]:row[1], :] result = cv2.matchTemplate(precise_map, mapping, cv2.TM_CCOEFF_NORMED) - subtract_blur(result, 5) + result = subtract_blur(result, 5) def to_map(x): return int((x * self.DIRECTION_RADIUS * 2) * self.POSITION_SEARCH_SCALE) From 3dd7cf75e2128e1f47ae0fe6b16e3301dad834d0 Mon Sep 17 00:00:00 2001 From: LmeSzinc <37934724+LmeSzinc@users.noreply.github.com> Date: Tue, 7 Nov 2023 13:38:31 +0800 Subject: [PATCH 5/5] Fix: Accept `area` attribute in ClickButton --- module/base/button.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/module/base/button.py b/module/base/button.py index 0846696c2..0f9671a32 100644 --- a/module/base/button.py +++ b/module/base/button.py @@ -308,9 +308,12 @@ class ButtonWrapper(Resource): class ClickButton: - def __init__(self, button, name='CLICK_BUTTON'): - self.area = button - self.button = button + def __init__(self, area, button=None, name='CLICK_BUTTON'): + self.area = area + if button is None: + self.button = area + else: + self.button = button self.name = name def __str__(self):